Home > other >  PowerShell filtering for AD Groups based on Membership Count in the initial query (aka not using -fi
PowerShell filtering for AD Groups based on Membership Count in the initial query (aka not using -fi

Time:04-15

PowerShell question for you savvy folks. Is it possible to filter a Get-ADGroup command based on group size (aka only return groups greater than x members)? I'm trying to filter in a more efficient way than: Get-ADGroup -Filter * and then running the member count check after, as in | where {$_.members.count -gt 10,000} or something.

But I'm having a hard time doing any kind of member count check on the initial filter so I don't have to return every group object in the individual domain and then check membership count. This is because the AD instance I'm querying against has a huge amount of AD groups that takes a long time to pull all groups first, then check.

I've tried variations of the below, but I'm guessing that the initial "members" property doesn't exist in the attribute set you can query against:

Get-ADGroup -Properties members -Filter {members -ge 10,000}

Any help is appreciated!

CodePudding user response:

Is it possible to filter a Get-ADGroup command based on group size (aka only return groups greater than x members)?

No!

The LDAP query filter syntax supported by Active Directory does not have any facility for specifying the count of multi-valued attributes.

You need to query the directory for groups that have any members, then count the result set client-side:

Get-ADGroup -LDAPFilter '(&(objectClass=group)(member=*))' -Properties member |Where-Object {
    $_.member.Count -gt 10000
}

CodePudding user response:

This is how you can improve the speed of your query with multi-threading, using Runspaces in this example, the main idea is to get all the OUs in the Domain and let each runspace query a specific OU at the same time (as many queries as defined in $threads).

This should improve the speed of the script by a big amount, however, this requires tweaking, if you have too many threads running at the same time it is likely that it can fail.

# define the params that will be passed to the runspaces
$params = @{
    LDAPFilter  = "(member=*)"
    SearchScope = 'OneLevel'
    Properties  = 'member'
}

# define the logic of the runspace
$scriptblock = {
    param($params)

    foreach($group in Get-ADGroup @params) {
        if($group.Member.Count -gt 10000) {
            $group
        }
    }
}

try {
    # get all OUs
    $ous = (Get-ADOrganizationalUnit -Filter *).DistinguishedName
    # get all Domain Controllers available
    # we don't want to make too many queries to the same DC!!
    $dcs = (Get-ADDomainController -Filter *).Name
    # define the number of threads that can run at the same time
    # maybe you could use `$dcs.Count` as Threads
    # this depends on your server's resources and your network
    $threads = 10
    $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $threads)
    $RunspacePool.Open()
    
    $runspace = foreach($ou in $ous) {
        $params['SearchBase'] = $ou
        $params['Server'] = $dcs[$i   % $dcs.Count]
        $ps = [powershell]::Create()
        $ps.AddScript($scriptblock).AddParameter('params', $params)
        $ps.RunspacePool = $RunspacePool

        [pscustomobject]@{
            Instance = $ps
            Task     = $ps.BeginInvoke()
        }
    }

    # capture the output from each runspace here!
    $result = foreach($r in $runspace) {
        $r.Instance.EndInvoke($r.Task)
        $r.Instance.foreach('Dispose')
    }
}
catch {
    Write-Warning $_.Exception.Message
}
finally {
    $runspace.foreach('Clear')
    $RunspacePool.foreach('Dispose')
}

$result | Format-Table
  • Related