Search code examples
powershellwmi

How can I speed up a query to Win32_UserAccount filtering by FullName property


I'm trying to find a specific user based on the FullName property of the user using a simple WMI command in powershell:

Get-WmiObject win32_useraccount -Filter "fullname='Jack Ryan'"

There are about 50,000 users and this is taking up to 30 seconds to find all the users based on the FullName property.

However when I try to search based on Name instead of FullName I get a response back in under a second. I don't understand why it's taking so long to lookup by FullName.

How can I speed this up? (Unfortunately I need to filter based on FullName and get all the usernames for those identities)


Solution

  • Getting group members via ADSI, as per @rboy comment. Probably easiest to have your own function here if you cannot use Get-LocalGroupMember.

    function Get-LocalMembers {
        Param(
            [parameter(Mandatory=$false)][string]$GroupName
        )
        $ADSI = [ADSI]"WinNT://$env:COMPUTERNAME"
        if ($PSBoundParameters.ContainsKey('GroupName')) {
            $Groups = $ADSI.Children.Find($GroupName,'Group')
        }
        else {
            $Groups = $ADSI.Children | Where-Object { $_.SchemaClassName -eq 'Group' }
        }
    
        Foreach ($Group in $Groups) {
            [PSCustomObject] @{
                Group = $($Group | Select-Object -ExpandProperty Name)
                Members = $(
                    $Group.Invoke('members') | ForEach-Object { 
                        $_.GetType().InvokeMember("Name",'GetProperty',$null,$_,$null)
                    }
                )
            }
        }
    }
    

    Usage:

    Get-LocalMembers                            # Get members of all groups
    Get-LocalMembers -GroupName Administrators  # Get members of specified group
    

    EDIT

    Getting both Name and FullName properties. I'm not sure really how much more we could do with ADSI in PowerShell here. I've never really explored it any further than user objects and group/member lists.

    function Get-LocalMembers {
        Param(
            [parameter(Mandatory=$false)][string]$GroupName
        )
        $ADSI = [ADSI]"WinNT://$env:COMPUTERNAME"
        if ($PSBoundParameters.ContainsKey('GroupName')) {
            $Groups = $ADSI.Children.Find($GroupName,'Group')
        }
        else {
            $Groups = $ADSI.Children | Where-Object { $_.SchemaClassName -eq 'Group' }
        }
    
        Foreach ($Group in $Groups) {
            [PSCustomObject] @{
                Group = $($Group | Select-Object -ExpandProperty Name)
                Members = $(
                    $Group.Invoke('members') | ForEach-Object { 
                        [PSCustomObject] @{
                            Name = $_.GetType().InvokeMember("Name",'GetProperty',$null,$_,$null)
                            FullName = $(
                                # A Group can be a member of a group and doesn't have a 'FullName property'
                                Try {
                                    $_.GetType().InvokeMember("Fullname",'GetProperty',$null,$_,$null)
                                }
                                Catch {
                                    "Group"
                                }
                            )
                        }
                    }
                )
            }
        }
    }
    

    Disclaimer: I'm running this on a local, non-domain joined laptop none of my accounts have the Fullname property populated.