基于初始查询中的成员计数的 AD 组的 PowerShell 过滤(也就是不使用 -filter *)

PowerShell filtering for AD Groups based on Membership Count in the initial query (aka not using -filter *)

PowerShell 问题给各位精明的人。是否可以根据组大小过滤 Get-ADGroup 命令(也就是仅 return 组大于 x 成员)?我正在尝试以比以下更有效的方式进行过滤: Get-ADGroup -Filter * 然后 运行 成员计数检查,如 | where {$_.members.count -gt 10,000} 或其他内容。

但是我很难对 初始过滤器 进行任何类型的成员计数检查,所以我不必 return 中的每个组对象个人域,然后检查成员数。这是因为我正在查询的 AD 实例有大量的 AD 组,需要很长时间才能先拉出所有组,然后再检查。

我已经尝试了下面的变体,但我猜测最初的“成员”属性 不存在于您可以查询的属性集中:

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

感谢任何帮助!

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

没有!

Active Directory 支持的 LDAP 查询过滤器语法没有任何工具来指定 multi-valued 个属性的数量。

您需要在目录中查询具有 any 个成员的组,然后统计结果集 client-side:

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

这就是使用multi-threading提高查询速度的方法,在本例中使用Runspaces,主要思想是获取域中的所有OU,让每个运行空间查询同时一个特定的 OU(与 $threads 中定义的查询一样多)。

这应该可以大大提高脚本的速度,但是,这需要调整,如果同时有太多线程 运行很可能会失败。

$ErrorActionPreference = 'Stop'

# 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