Powershell 在具有多个受信任的林和域的网络中,更快地获得数百万广告组的广告成员资格
首先,我无法了解我为什么需要这些数据,也无法了解网络的具体情况。您必须相信我,除了运行LDAP查询的PowerShell脚本之外,没有其他方法可以获取此数据 我正在使用一个具有多个林和多个域的网络。所有的森林之间都有信任。我登录到其中一个林中的一个域,但由于信任关系,我可以查询所有林 我有一个CSV文件,里面有数百万个广告组。我需要找到数百万广告群中每个人的直接成员。很多会员都是跨域的,这意味着我不能只使用广告组的Powershell 在具有多个受信任的林和域的网络中,更快地获得数百万广告组的广告成员资格,powershell,active-directory,ldap,Powershell,Active Directory,Ldap,首先,我无法了解我为什么需要这些数据,也无法了解网络的具体情况。您必须相信我,除了运行LDAP查询的PowerShell脚本之外,没有其他方法可以获取此数据 我正在使用一个具有多个林和多个域的网络。所有的森林之间都有信任。我登录到其中一个林中的一个域,但由于信任关系,我可以查询所有林 我有一个CSV文件,里面有数百万个广告组。我需要找到数百万广告群中每个人的直接成员。很多会员都是跨域的,这意味着我不能只使用广告组的member属性,而必须查询每个域并检查memberOf 我有一个获取此数据的Po
member
属性,而必须查询每个域并检查memberOf
我有一个获取此数据的PowerShell脚本。出于各种原因,我无法共享我的代码,但它的作用如下:
System.DirectoryServices.DirectorySearcher
对象数组DN
DN
,在DirectorySearcher
数组上循环,并在该DirectorySearcher
((memberOf=$adGroupDN)
)中查找作为广告组成员的所有对象
- 我的输入列表是数百万个唯一的组DNs
- 我有多个不同的林/域
- 我的输入组DNs分布在所有林/域中
- 我的组DNs输入列表中的组跨越不同的林/域(
我的输入列表中的domain1\group1
为成员)domain2\group2
- 我需要从我的输入列表中获取组中每个组的完整列表
- 由于跨域成员身份,我不能依赖输入组的
属性。我知道获取它的唯一方法是在每个DC/域中查询属于我输入列表中的组的所有组member
- 我只能使用PowerShell
- 我没有ActiveDirectory模块,只能使用.NET
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) { ...
- 我能想到的加快它的唯一方法是多线程第二个for循环,在这个循环中,它使用运行空间同时查询多个DC/域,但我不知道如何做到这一点
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"
}
}
}
}
这样,您就可以使用每个组的distrignizedName
调用该函数,如:
OutputMembers "CN=MyGroup,OU=Groups,DC=domain,DC=com"
我假设步骤3中的性能问题可能有一个嵌入式循环(如果您也寻找间接的组成员身份,它甚至可能是递归的): 内部循环中的所有内容对于脚本的性能都非常重要,因为它们将被调用
$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)
}
一般的想法是,对于相同的
$adGroupDN
(您以前查询过的任何组),您不应该远程重做“在该DirectorySearcher((memberOf=$adGroupDN))
中查找广告组的成员的所有对象”,而是从本地哈希表(缓存)中检索所需的信息.这里可以进行一些优化。这些优化与Powershell无关,而是与算法本身有关
Powershell不是为执行此类任务而设计的。应改用C\C++或至少C#
创建并维护到要从中查询信息的每个全局编录的RootDse对象的连接,直到所有作业完成。在这种情况下,所有AD查询都将使用一个到AD的缓存连接,这将显著提高性能
对铁竖起大拇指。为所有查询的组创建缓存。例如,如果您查询了A组的成员资格,而A组是B组的成员,则无需再次查询A组的成员资格。当然,在您的情况下,您不能简单地存储
$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)
}