Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell 在具有多个受信任的林和域的网络中,更快地获得数百万广告组的广告成员资格_Powershell_Active Directory_Ldap - Fatal编程技术网

Powershell 在具有多个受信任的林和域的网络中,更快地获得数百万广告组的广告成员资格

Powershell 在具有多个受信任的林和域的网络中,更快地获得数百万广告组的广告成员资格,powershell,active-directory,ldap,Powershell,Active Directory,Ldap,首先,我无法了解我为什么需要这些数据,也无法了解网络的具体情况。您必须相信我,除了运行LDAP查询的PowerShell脚本之外,没有其他方法可以获取此数据 我正在使用一个具有多个林和多个域的网络。所有的森林之间都有信任。我登录到其中一个林中的一个域,但由于信任关系,我可以查询所有林 我有一个CSV文件,里面有数百万个广告组。我需要找到数百万广告群中每个人的直接成员。很多会员都是跨域的,这意味着我不能只使用广告组的member属性,而必须查询每个域并检查memberOf 我有一个获取此数据的Po

首先,我无法了解我为什么需要这些数据,也无法了解网络的具体情况。您必须相信我,除了运行LDAP查询的PowerShell脚本之外,没有其他方法可以获取此数据

我正在使用一个具有多个林和多个域的网络。所有的森林之间都有信任。我登录到其中一个林中的一个域,但由于信任关系,我可以查询所有林

我有一个CSV文件,里面有数百万个广告组。我需要找到数百万广告群中每个人的直接成员。很多会员都是跨域的,这意味着我不能只使用广告组的
member
属性,而必须查询每个域并检查
memberOf

我有一个获取此数据的PowerShell脚本。出于各种原因,我无法共享我的代码,但它的作用如下:

  • 为我的所有域创建
    System.DirectoryServices.DirectorySearcher
    对象数组
  • 遍历CSV文件,该文件包含每个广告组及其
    DN
  • 对于每个
    DN
    ,在
    DirectorySearcher
    数组上循环,并在该
    DirectorySearcher
    (memberOf=$adGroupDN)
    )中查找作为广告组
    成员的所有对象
  • 代码是有效的。但由于我处理的是一个有数百万广告群的输入列表,所以脚本的速度非常慢。根据我的测试运行计算,获得我需要的所有数据需要2周以上的时间

    我想知道是否有更好/更快的方法来做到这一点

    我想也许我可以使用线程或其他东西,但我不确定这是否会有帮助,也不确定从哪里开始

    任何建议都将不胜感激

    正在添加一些其他详细信息。。。
    • 我的输入列表是数百万个唯一的组DNs
    • 我有多个不同的林/域
    • 我的输入组DNs分布在所有林/域中
    • 我的组DNs输入列表中的组跨越不同的林/域(
      domain1\group1
      我的输入列表中的
      domain2\group2
      为成员)
    • 我需要从我的输入列表中获取组中每个组的完整列表
    • 由于跨域成员身份,我不能依赖输入组的
      member
      属性。我知道获取它的唯一方法是在每个DC/域中查询属于我输入列表中的组的所有组
    • 我只能使用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/域,但我不知道如何做到这一点

    在域控制器上运行脚本会给您带来一点好处,如果这是一个选项的话。但除此之外,多线程可能是您的最佳选择

    研究使用。有一个例子

    尽管如此,我对此表示怀疑:

    很多会员都是跨域的,这意味着我不能只使用 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"
                }
            }
        }
    }
    
    这样,您就可以使用每个组的
    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)
    }