WMI query filtering

Hi Guys,

I am a powershell newbie (on V3). I am trying to find a way to retrieve the members of the local admin group on a remote machine. Below is the closest command I could find to retrieve such information (other than the alternate methods of using some ADSI queries which I am not familiar with). Using the “GroupComponent” property of the below output object, I should be able to get the desired list (after the text manipulations).

My query is,

Below command works fine, takes about 10 seconds to run on a workgroup/domain machine.

get-wmiobject -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$env:computername',Name='administrators'"""

I was trying to construct the similar command using the powershell way (instead of query lang) as seen below.

Get-WmiObject -Class win32_groupuser | where pscomputername -Match $env:COMPUTERNAME | where GroupComponent -Match win32_group.domain 

Both commands works absolutely fine on a workgroup machine. But when I use them on a domain machine, latter just takes too much of time and never completes (it does not return any error, which means the command/syntax is fine).

What am I doing wrong? If “Get-WmiObject -Class win32_groupuser” is retrieving too much of details (inefficient filtering) from AD which is slowing down the process, why is it not happening on the 1st command? How can I make the 2nd style of command working?

Me, I’d go with an ADSI query using the WinNT provider.

On a domain machine, you’re always going to get a more extensive list, because the domain machine “sees” everyone in the domain. The ADSI approach might help avoid that.

Hi GJ,

Please check if below works for you. The 1st Get-WmiObject command gets the Administrators group using the well known security ID which works with localised Windows installation (e.g. French, German). The 2nd Get-WmiObject command retrieves the associated user accounts and groups (members of Administrators) with the GetRelated method.

$LocalGroup = Get-WmiObject -Class Win32_Group -Filter "SID = 'S-1-5-32-544'" -ComputerName MyRemoteComputerName
if ($LocalGroup)
{
    $LocalGroup.GetRelated('Win32_UserAccount')
    $LocalGroup.GetRelated('Win32_Group')
}

Best,
Daniel

Thanks for the response Don & Daniel.

@Don, I will check out ADSI query. But in this case, how is the 1st command(used with wmi -query) working without any problem? Is it not going to see everyone in domain?

@Daniel, Unfortunately, I still have the same problem. Simply searching using the SID still goes through all the domain and trying to retrieve the results (even after 5 minutes it was still trying). So had to slightly tweak your 1st command as below by filtering only the localaccounts. But still $LocalGroup.GetRelated(‘Win32_UserAccount’) takes a lot of time and I had to break it after 5 min as I didn’t want to choke my domain controller.

 Get-WmiObject Win32_Group -filter "LocalAccount=1" | where SID -eq S-1-5-32-544 

Hi GJ,

Sorry for my late reply.

Yes, unfortunately the code I’ve tested in my small lab domain didn’t cause any delay but you are right it does not run very well with computers joined to a large forest or domain.

To answer your question why your 1st command runs faster than your 2nd command.

Your 1st command: Your query won’t look for domain groups because you’ve restricted/filtered it to the computer name. Using the Query parameter is a valid way to use the Get-WmiObject cmdlet assuming you know the query language (WQL).

get-wmiobject -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$env:computername',Name='administrators'"""

Alternative to your 1st command: Using the Class and Filter parameters will produce the same query as your 1st command but the cmdlet does the work for you to build the WQL statement to query. You do not need to know the exact syntax of WQL statements.

Get-WmiObject -Class Win32_GroupUser -Filter "GroupComponent=""Win32_Group.Domain='$env:COMPUTERNAME',Name='Administrators'"""

Your 2nd command: Plain simple you are filtering too late. Your Get-WmiObject -Class Win32_GroupUser command is not being restricted/filtered so it goes out and puts all groups the machine can find into the pipeline. Your attempt to filter the pipeline is too late because the Get-WmiObject cmdlet is already doing its thing without filter/query and puts the objects into the pipeline for the Where-Object cmdlets to consume.

Get-WmiObject -Class win32_groupuser | where pscomputername -Match $env:COMPUTERNAME | where GroupComponent -Match win32_group.domain

Best practice: Always filter to the left and process to the right. Which means here: Use the -Query or -Filter parameter of Get-WmiObject to restrict the objects being returned than process the objects (text manipulation for example).

Here is a hopefully working example:

$ComputerName = 'RemoteComputerName'
$GroupMembers = @(Get-WmiObject -Class Win32_GroupUser -Filter "GroupComponent=""Win32_Group.Domain='$ComputerName',Name='Administrators'""" -ComputerName $ComputerName)
foreach ($GroupMember in $GroupMembers)
{
    if ($GroupMember.PartComponent -match 'Domain="(.+)",Name="(.+)"')
    {
        [pscustomobject]@{
            Domain = $Matches[1]
            Name = $Matches[2]
        }
    }
}

Best,
Daniel

Awesome. Many thanks for the detailed explanation Daniel.

Looks like there is a small mistake in the 2nd line of the code ($GroupMembers). The end parenthesis should be ending after the $computername.

Hi Daniel,

Thanks again for your answer. I am yet to learn the string manipulation techniques and hash table concepts in powershell. If you have time and if it is easy to explain the text manipulation method you used here, please explain. only if you have some spare time… :slight_smile:

if ($GroupMember.PartComponent -match 'Domain="(.+)",Name="(.+)"')
    {
        [pscustomobject]@{
            Domain = $Matches[1]
            Name = $Matches[2]
        }
    }