Powershell 优化Get ADUser过滤器

Powershell 优化Get ADUser过滤器,powershell,active-directory,large-data,Powershell,Active Directory,Large Data,在AD中,我试图识别在2个或更多记录中填充相同EmployeeID值的用户帐户。下面是我的一段代码:我正在使用一个定义的Show Progress函数,仅getaduser命令就花费了2个多小时来获取所有记录。其他步骤2到5相当快。虽然我已经完成了这项工作,但我想知道是否可以使用PowerShell更高效地完成这项工作 Get-ADUser -LDAPFilter "(&(ObjectCategory=Person)(objectclass=user)(employeeid=*

在AD中,我试图识别在2个或更多记录中填充相同EmployeeID值的用户帐户。下面是我的一段代码:我正在使用一个定义的Show Progress函数,仅getaduser命令就花费了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文件,然后用Excel进行后期处理,但由于数据集太大,时间和内存都很紧张,我不得不皱眉


非常感谢您的建议。

因为我们不知道$properties或$selectPropsList中有什么内容,所以您的问题实际上只是要找出向哪些用户颁发了相同的EmployeeID,对吗? 默认情况下,Get ADUser已返回以下属性:

DifferentizedName、Enabled、GivenName、Name、ObjectClass、ObjectGUID、SamAccountName、SID、姓氏、UserPrincipalName

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

接下来,通过使用链接到的ShowProgress脚本,您将大大降低脚本的执行速度。你真的需要一个进度条吗? 为什么不直接将包含活动步骤的行写入控制台

此外,在速度部门,把所有东西都排在一起也没有帮助

$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

另外,Get ADUser已经只返回用户对象,因此不需要LDAP筛选器ObjectCategory=Personobjectclass=user。使用-Filter-EmployeeID-like'*'可能更快

因为我们不知道$properties或$selectPropsList中有什么,您的问题实际上只是要找出向哪些用户发布了相同的EmployeeID,对吗? 默认情况下,Get ADUser已返回以下属性:

DifferentizedName、Enabled、GivenName、Name、ObjectClass、ObjectGUID、SamAccountName、SID、姓氏、UserPrincipalName

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

接下来,通过使用链接到的ShowProgress脚本,您将大大降低脚本的执行速度。你真的需要一个进度条吗? 为什么不直接将包含活动步骤的行写入控制台

此外,在速度部门,把所有东西都排在一起也没有帮助

$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
另外,Get ADUser已经只返回用户对象,因此不需要LDAP筛选器ObjectCategory=Personobjectclass=user。使用-Filter EmployeeID类似的“*”可能更快

此答案补充并侧重于显示操作过程中的进度:

截至本文撰写之时,最新发布的:

有一个明显的错误,因为它没有通过相关行传递管道输入,因此被意外注释掉

在概念上有缺陷,因为它没有使用进程块,这意味着在处理之前首先收集所有管道输入,这与进度条的概念背道而驰

因此,在管道中的上一个命令输出其所有输出之前,Show Progress调用不会显示进度。一个简单的替代方法是将管道分解为单独的命令,并在每个命令之前发出一条进度消息,宣布下一个处理阶段,而不是如西奥的回答所示的每个对象的进度

通常,无法显示命令内部处理的进度,只能显示命令的多对象输出的进度

最简单的方法是通过你打电话的方式 ,但这带来了两个挑战:

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

为接收到的每个对象调用写入进度将导致整体处理的显著放缓;折衷方法是只为每N个对象调用它,如中所示;该方法可以封装在一个正确实现的函数中,即一个la Show Progress,该函数要求将对象总数作为参数传递,并通过一个进程块执行正确的流式输入对象处理;这就是说,仅仅使用PowerShell代码传递输入对象的行为代价就很高

结论:

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

它们要求您知道对象的总数 要预先处理管道,无法知道有多少对象将通过它:

或者:在可行的情况下,事先收集所有要在内存中处理的对象;然后,集合中的元素计数可以作为完成百分比计算的基础。对于非常大的输入集,这可能不是一个选项

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

PowerShell代码中的逐对象处理(通过或通过)本质上很慢

您可以通过限制对每N个对象的调用来缓解这种情况,如中所示 总的来说,这是在处理速度和向最终用户显示完成进度百分比的能力之间的折衷。

此答案补充并侧重于在操作过程中显示进度:

截至本文撰写之时,最新发布的:

有一个明显的错误,因为它没有通过相关行传递管道输入,因此被意外注释掉

在概念上有缺陷,因为它没有使用进程块,这意味着在处理之前首先收集所有管道输入,这与进度条的概念背道而驰

因此,在管道中的上一个命令输出其所有输出之前,Show Progress调用不会显示进度。一个简单的替代方法是将管道分解为单独的命令,并在每个命令之前发出一条进度消息,宣布下一个处理阶段,而不是如西奥的回答所示的每个对象的进度

通常,无法显示命令内部处理的进度,只能显示命令的多对象输出的进度

最简单的方法是通过你打电话的方式 ,但这带来了两个挑战:

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

为接收到的每个对象调用写入进度将导致整体处理的显著放缓;折衷方法是只为每N个对象调用它,如中所示;该方法可以封装在一个正确实现的函数中,即一个la Show Progress,该函数要求将对象总数作为参数传递,并通过一个进程块执行正确的流式输入对象处理;这就是说,仅仅使用PowerShell代码传递输入对象的行为代价就很高

结论:

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

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

或者:在可行的情况下,事先收集所有要在内存中处理的对象;然后,集合中的元素计数可以作为完成百分比计算的基础。对于非常大的输入集,这可能不是一个选项

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

PowerShell代码中的逐对象处理(通过或通过)本质上很慢

您可以通过限制对每N个对象的调用来缓解这种情况,如中所示
总的来说,这是处理速度和向最终用户显示完成进度百分比的能力之间的折衷。

看看这是否有帮助谢谢,游戏是战争,这是一个有用的链接看看这是否有帮助谢谢,游戏是战争,这是一个有用的链接谢谢Theo!你在这里提供的建议很有帮助。我应该在问题中提到,我需要从目标用户对象中提取大约20个属性,包括title、dept、company、office、manager等等。而且,我从Write Progress询问,虽然预期有200K+个对象,但我只是想知道Get ADUser仍在返回对象。正如我在我的作品中提到的,在第一步之后,剩下的步骤相当快。现在,我将尝试根据您的建议修改我的过滤器并删除“显示进度”,并将重新发布性能。@KarthickGanesan特别是当您必须处理这么多用户对象时,我将尽可能精简第一次运行的Get ADUser。在确定具有公共EmployeeID的用户时,您可能会忽略其中大多数用户,因此从获取所有这些属性开始是一种资源浪费。我将使用$result中的过滤用户只对该用户子集进行更多处理。这将意味着额外的循环
您现在拥有的用户,但由于希望只有少数,这应该比为您无论如何都不会使用的用户检索所有用户要快。哇,这确实是一个非常好的建议。我从您的观点推断,我应该使用另一个Get ADUser来提取所有必需的属性,这些属性仅适用于那些已过滤到$result变量中的目标用户对象。这太好了!✌@卡加尼桑:是的,就是这个主意。实际上,使用第2步中的$dupes数组(如第2.5步)获取其余属性更容易。然后所有其他步骤都可以保留为Istanks Theo!你在这里提供的建议很有帮助。我应该在问题中提到,我需要从目标用户对象中提取大约20个属性,包括title、dept、company、office、manager等等。而且,我从Write Progress询问,虽然预期有200K+个对象,但我只是想知道Get ADUser仍在返回对象。正如我在我的作品中提到的,在第一步之后,剩下的步骤相当快。现在,我将尝试根据您的建议修改我的过滤器并删除“显示进度”,并将重新发布性能。@KarthickGanesan特别是当您必须处理这么多用户对象时,我将尽可能精简第一次运行的Get ADUser。在确定具有公共EmployeeID的用户时,您可能会忽略其中大多数用户,因此从获取所有这些属性开始是一种资源浪费。我将使用$result中的过滤用户只对该用户子集进行更多处理。这将意味着通过你现在拥有的用户进行额外的循环,但由于希望只有少数用户,这应该比为你无论如何都不会使用的用户检索所有用户更快。哇,这确实是一个非常好的建议。我从您的观点推断,我应该使用另一个Get ADUser来提取所有必需的属性,这些属性仅适用于那些已过滤到$result变量中的目标用户对象。这太好了!✌@卡加尼桑:是的,就是这个主意。实际上,使用第2步中的$dupes数组(如第2.5步)获取其余属性更容易。然后所有其他步骤都可以保留为isThanks mklement0,看到您的回答总是一件令人高兴的事情。它多次帮助我微调PS脚本功能。然而,由于我自己仍然是PS的新手,我最近有了一些偏差。1错误-我已经取消了对象passthru$\u2行的注释-概念上的缺陷-就在鼻子下面,谢谢你指出这一点。3将ShowProgress调用放在命令之前-我认为当前命令应该通过管道显示进度,以便显示进度条4。。。。。。4在使用管道之前对输出对象进行计数-我发现这是无法做到的,也没有解决方法。或者,是否有某种方法,特别是使用Get ADUser,只知道计数而不首先检索对象?对不起,我太笨了。5每N个对象只调用写入进度-已接受;可能,至少每10分之一计数一次。结论:将写进度与对象传递一起使用基本上是不好的,因为它只会增加处理时间。感谢您的良好反馈,@KarthickGanesan。Re 3-我的错:是的,展示进步是行不通的;我已经重写了这一段,它现在明确提到了西奥的替代方案:将管道分解为多个命令,并将进度信息限制为宣布整个处理的每个阶段。Re 4不,你不能预先知道计数,但如果所有对象都适合内存,只需事先将它们收集到一个数组中,如西奥的回答$users=Get ADUser…,你可以从中提前得出计数。@KarthickGanesan:Re 5和结论:是的,这肯定会减慢速度,即使将写进度调用限制为每N个对象都会有所帮助,但使用PowerShell代码简单地传递对象本身就很慢。这是处理速度和向最终用户显示完成进度百分比之间的折衷。感谢mklement0,看到您的回答总是一件令人高兴的事。它多次帮助我微调PS脚本功能。然而,由于我自己仍然是PS的新手,我最近有了一些偏差。1错误-我已经取消了对象passthru$\u2行的注释-概念上的缺陷-就在鼻子下面,谢谢你指出这一点。3将ShowProgress调用放在命令之前-我认为当前命令应该通过管道显示进度,以便显示进度条4。。。。。。4在使用管道之前对输出对象进行计数-我发现这是无法做到的,也没有解决方法。或者,是否有某种方法,特别是使用Get ADUser,只知道计数而不首先检索对象?对不起,我太笨了。5每N个对象只调用写入进度-已接受;可能,至少每10分之一计数一次。结论:使用Write-P基本上是不好的
“rogress和一个对象passthru,因为这只会增加处理时间。谢谢你的反馈,@KarthickGanesan。”。Re 3-我的错:是的,展示进步是行不通的;我已经重写了这一段,它现在明确提到了西奥的替代方案:将管道分解为多个命令,并将进度信息限制为宣布整个处理的每个阶段。Re 4不,你不能预先知道计数,但如果所有对象都适合内存,只需事先将它们收集到一个数组中,如西奥的回答$users=Get ADUser…,你可以从中提前得出计数。@KarthickGanesan:Re 5和结论:是的,这肯定会减慢速度,即使将写进度调用限制为每N个对象都会有所帮助,但使用PowerShell代码简单地传递对象本身就很慢。这是处理速度和向最终用户显示完成进度百分比之间的折衷。