优化 Get-ADUser 过滤器

Optimize Get-ADUser filter

在 AD 中,我试图识别在 2 条或更多条记录中填充了相同 EmployeeID 值的用户帐户。下面是我的一段代码(来源:我正在使用 Show-Progress 定义的函数 here),仅 Get-ADUser 命令就花费了 2 个多小时来获取所有记录。其他步骤(2 到 5)非常快。当我完成这项工作时,我想知道是否可以使用 PowerShell 更有效地完成这项工作。

Get-ADUser -LDAPFilter "(&(ObjectCategory=Person)(objectclass=user)(employeeid=*))" -Properties $properties -Server $server_AD_GC -ResultPageSize 1000 | 
    # *ISSUE HERE*
    #    The Get-ADUser extract process seems to work very slow.
    #    However, it is important to note that the above command will be retrieving more than 200K records
    # NOTE: I've inferred that employeeid is an indexed attribute and is replicated to GlobalCatalogs and hence have used it in the filter
    Show-Progress -Activity "(1/5) Getting AD Users ..." |
select $selectPropsList -OutVariable results_UsersBaseSet |
Group-Object EmployeeID | 
    Show-Progress -Activity "(2/5) Grouping on EmployeeID ..." | 
? { $_.Count -gt 1 } | 
    Show-Progress -Activity "(3/5) Filtering only dup EmpID records ..." | 
select -Exp Group | 
    Show-Progress -Activity "(4/5) UnGrouping ..." | 
Export-Csv "C:\Users\me\op_GetADUser_w_EmpID_Dupes_EntireForest - $([datetime]::Now.ToString("MM-dd-yyyy_hhmmss")).csv" -NoTypeInformation |
    Show-Progress -Activity "(5/5) Exporting ..." | 
Out-Null

PS:我也试过首先将所有用户帐户导出到一个 csv 文件,然后 post-process with Excel 但我不得不皱眉,因为数据集的大小,它既是时间又是内存处理。

非常感谢任何建议。

由于我们不知道 $properties$selectPropsList 中的内容,您的问题实际上只是找出向哪些用户发出了相同的 EmployeeID,对吗?
默认情况下,Get-ADUser 已经 returns 这些属性:

DistinguishedNameEnabledGivenNameNameObjectClassObjectGUIDSamAccountNameSIDSurnameUserPrincipalName

所以我猜你需要的只是 EmployeeID。尝试收集大量属性确实会减慢速度,因此将其保持在最低限度有助于加快速度。

接下来,通过使用您链接到的 Show-Progress 脚本,您将大大减慢脚本的执行速度。你真的需要进度条吗? 为什么不直接将带有 activity 步骤的行直接写入控制台?

此外,将所有东西都放在一起对速度部门也无济于事..

$server_AD_GC    = 'YourServer'
$selectPropsList = 'EmployeeID', 'Name', 'SamAccountName', 'Enabled'
$outFile         = "C:\Users\me\op_GetADUser_w_EmpID_Dupes_EntireForest - $([datetime]::Now.ToString("MM-dd-yyyy_hhmmss")).csv"

Write-Host "Step (1/4) Getting AD Users ..." 
$users = Get-ADUser -Filter "EmployeeID -like '*'" -Properties EmployeeID -Server $server_AD_GC -ResultPageSize 1000

Write-Host "Step (2/4) Grouping on EmployeeID ..."
$dupes = $users | Group-Object -Property EmployeeID | Where-Object { $_.Count -gt 1 }

Write-Host "Step (3/4) Collecting duplicates ..."
$result = foreach ($group in $dupes) {
    $group.Group | Select-Object $selectPropsList
}

Write-Host "Step (4/4) Exporting ..."
$result | Export-Csv -Path $outFile -NoTypeInformation

Write-Host  "All done" -ForegroundColor Green

P.S。 Get-ADUser 已经 returns 个用户对象,因此不需要 LDAP 过滤器 (ObjectCategory=Person)(objectclass=user)。使用 -Filter "EmployeeID -like '*'" 可能更快

这个答案是对 的补充,侧重于在操作过程中显示进度:

  • linked Show-Progress function,这是撰写本文时最新的:

    • 有一个彻底的 bug,因为它不通过管道输入(相关行被意外注释掉)

    • 在概念上有缺陷,因为它没有使用 process 块,这意味着 所有管道输入首先被收集 ,然后再收集已处理 - 这违背了进度条的想法。

  • 因此,您的 Show-Progress 调用不会显示进度,直到管道中的前一个命令输出了其输出的 all。一个简单的替代方法是将管道分解成单独的命令,并简单地在每个命令 之前发出 one 进度消息,宣布下一个 Theo 的回答中所示的处理阶段(而不是每个对象的进度)。

  • 一般无法显示command-internal处理的进度,只能显示一个命令(多对象)的进度输出.

    • 最简单的方法是通过 ForEach-Object 调用,您可以在其中调用
      Write-Progress,但这带来了两个挑战:

      • 为了显示 完成百分比 进度条,您需要知道总共有多少对象,您必须提前确定,因为管道无法知道它将接收多少个对象;你唯一的选择是先 收集所有输出 (或找到一些其他方法来计算它)然后使用收集的输出作为管道输入,使用对象计数作为计算的基础要传递给 Write-Progress -PerCentComplete.

        的值
      • 为接收到的每个对象调用Write-Progress将导致整体处理显着减速;折衷方案是只为每 N 个对象调用它,如 所示;那里的方法可以包含在一个正确实现的函数 a la Show-Progress 中,该函数需要将对象总数作为参数传递并执行适当的 streaming 输入对象处理(通过 process块);也就是说,仅使用 PowerShell 代码 传递输入对象的行为是昂贵的。


结论:

完成百分比进度显示有两个固有问题:

  • 他们要求你事先知道要处理的对象总数(管道无法知道有多少对象将通过它):

    • 任一个:收集所有要处理的对象内存预先,如果可行;集合中元素的数量可以作为完成百分比计算的基础。对于非常大的输入集,这可能不是一个选项。

    • 或者:预先执行一个额外的处理步骤,仅计算所有对象,而实际上并没有检索它们。就增加的额外处理时间而言,这可能不切实际。

  • PowerShell 代码 中逐对象处理 - 通过 ForEach-Object 高级 script/function - 本质上很慢。

    • 您可以通过限制对每 N 个对象的 Write-Progress 调用来减轻这种情况,如
    • 所示

总体而言,这是处理速度与向最终用户显示完成百分比进度的能力之间的权衡。