首先,我无法理解为什么我需要这些数据,而且我无法了解有关网络的细节。您必须相信我除了PowerShell脚本之外没有其他方法可以获取此数据来运行LDAP查询。
我正在使用具有多个林和多个域的网络。所有森林之间都有信任。我在其中一个森林上登录了一个域,但由于信任,我可以查询所有这些域。
我有一个包含数百万个AD群组的CSV文件。我需要找到数百万AD组中每个人的所有直接成员。很多成员资格都是跨域的,这意味着我不能只使用AD组的member
属性,而是必须查询每个域并检查memberOf
。
我有一个获取此数据的PowerShell脚本。出于各种原因,我不能分享我的代码,但这就是它的作用:
System.DirectoryServices.DirectorySearcher
个对象数组DN
DN
DirectorySearcher
数组,并在memberOf
(DirectorySearcher
)<中查找属于(memberOf=$adGroupDN)
AD组的所有对象/ LI>
醇>
代码有效。但由于我正在处理包含数百万个AD组的输入列表,因此脚本非常慢。根据我的测试运行计算,我需要两周多的时间才能获得所需的所有数据。
我想知道是否有更好/更快的方法来做到这一点?
我想也许我可以使用线程或其他东西,但我不确定这是否有帮助,也不确定从哪里开始。
非常感谢任何建议。
domain1\group1
从我的输入列表中domain2\group2
作为成员)member
属性。我知道获取它的唯一方法是从输入列表中查询所有组memberOf
的每个DC /域。DirectorySearcher
在高级别,我的代码如下所示:
$arrayOfDirectorySearcherObjectsForEachDCInMyNetwork = ... code to create an array of System.DirectoryServices.DirectorySearcher objects, one for each DC/domain in my network
Foreach ($groupDN in $inputListOfUniqueGroupDNs)
{
Foreach ($domain in $arrayOfDirectorySearcherObjectsForEachDCInMyNetwork)
{
...
答案 0 :(得分:2)
如果是一个选项,在域控制器上运行脚本会给你一点点优势。但是否则多线程可能是你最好的选择。
那就是说,我对此表示质疑:
很多会员资格都是跨域的,这意味着我不能只使用 AD组的成员属性,而不是每个查询 域并检查memberOf。
小组范围在这里很重要。如果您的所有群组都是通用群组,则无论哪种方式都不会有所影响(无论您是在群组上查看member
还是在用户上查看memberOf
)。
但重要的是要注意memberOf
不会在不同的域上显示域本地组组(即使在同一个林中)。
组中的member
属性始终是成员的权威来源。是的,在受信任的域上获取帐户的详细信息有点困难,但可以这样做。
这是一个PowerShell函数,它将拉取组中每个成员的“域\用户名”,包括嵌套组中的那些成员。
function OutputMembers {
param([string] $groupDn)
foreach ($m in ([ADSI]("LDAP://" + $groupDn)).member) {
$member = [ADSI]("LDAP://" + $m)
$member.objectClass
if ($member.objectClass -eq "group") {
#this member is a group so pull the members of that group
OutputMembers $member.distinguishedName
} else {
#"msDS-PrincipalName" is not loaded by default, so we have to tell it to get it
$member.Invoke("GetInfoEx", @("msDS-PrincipalName"), 0)
if ([string]::IsNullOrEmpty($member."msDS-PrincipalName")) {
#member is on a trusted domain, so we have to go look it up
$sid = New-Object System.Security.Principal.SecurityIdentifier ($member.objectSid[0], 0)
$sid.Translate([System.Security.Principal.NTAccount]).value
} else {
$member."msDS-PrincipalName"
}
}
}
}
通过它,您可以使用每个组的distinguishedName
调用该函数,例如:
OutputMembers "CN=MyGroup,OU=Groups,DC=domain,DC=com"
答案 1 :(得分:1)
我认为步骤3中的性能问题可能是嵌入式循环(如果你也寻找间接组成员资格,它甚至可能是递归的):
Foreach ($UserDN in $UserDNs) {
...
Foreach ($GroupDN in $GroupDNs) {
...
内循环中的所有内容对于脚本的性能非常重要,因为它将被调用$UserDNs.Count * $GroupDNs.Count
次!
我怀疑内部循环中存在大量冗余LDAP查询(对于属于同一组的用户),因此关注它并构建一种对服务器的每个冗余查询的自定义缓存以克服此问题。类似的东西:
$MemberCache = @{}
Function GetMembers([String]$GroupDN) {
If (!$MemberCache.ContainsKey($GroupDN)) {
$MemberCache[$GroupDN] = @{} #HashTables are much faster then using the contains method on an array
# retrieve all members of the AD group in that DirectorySearcher
ForEach ($Member in $Members) {$MemberCache[$GroupDN].$Member = $True}
}
$MemberCache[$GroupDN]
}
Function IsMember([String]$DN, [String]$GroupDN) {
(GetMembers($GroupDN)).ContainsKey($DN)
}
一般的想法是,您不应远程重做“查找memberOf
中DirectorySearcher ((memberOf=$adGroupDN))
个$adGroupDN
AD组中的所有对象{{1 (之前已经查询过的任何组)但是从本地哈希表(缓存)中检索所需的信息。
答案 2 :(得分:0)
这里可以做几个优化。这些优化与Powershell无关,而与算法本身无关。
请注意: