代码之家  ›  专栏  ›  技术社区  ›  J Weezy

Active Directory:调整函数性能以检索组成员

  •  0
  • J Weezy  · 技术社区  · 6 年前

    这篇文章是以下内容的后续:

    Active Directory: DirectoryEntry member list <> GroupPrincipal.GetMembers()

    我有一个函数,用于检索Active Directory中组的所有成员的distinguishedName属性。此函数用于检索所有用户和组对象的大型脚本(总运行时间为7-10分钟)。我这里的问题是,distinguishedName上的下游SSIS查找速度非常慢。这并不奇怪,因为它查找的是varchar(255)和UniqueIdentifier(16字节)。我可以在源代码上执行SQL选择,然后合并联接,这会加快速度。但是,我注意到摘录中存在一个潜在的竞争条件(请参见上面的运行时),其中组成员没有匹配的distinguishedName。如果是这样,那么我需要解决这个问题;但是,合并联接不会导致加载失败,而查找可以设置为导致加载失败。

    因此,我需要通过distinguishedName动态获取guid。然而,当我尝试使用下面的方法时,GetGroupMemberList函数的性能大幅下降。是否有更好/更快的方法通过distinguishedName获取组成员guid?

    方法(对于两个循环):

    listGroupMemberGuid.Add(new DirectoryEntry("LDAP://" + member, null, null, AuthenticationTypes.Secure).Guid);
    
    listGroupMemberGuid.Add(new DirectoryEntry("LDAP://" + user, null, null, AuthenticationTypes.Secure).Guid);
    

    功能:

    private List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
    {
        // Variable declaration(s).
        List<string> listGroupMemberDn = new List<string>();
        string strPath = strActiveDirectoryHost + "/<GUID=" + strPropertyValue + ">";
        const int intIncrement = 1500; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx
    
        var members = new List<string>();
    
        // The count result returns 350.
        var group = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
        //var group = new DirectoryEntry($"LDAP://{"EnterYourDomainHere"}/<GUID={strPropertyValue}>", null, null, AuthenticationTypes.Secure);
    
        while (true)
        {
            var memberDns = group.Properties["member"];
            foreach (var member in memberDns)
            {
                members.Add(member.ToString());
            }
    
            if (memberDns.Count < intIncrement) break;
    
            group.RefreshCache(new[] { $"member;range={members.Count}-*" });
        }
    
        //Find users that have this group as a primary group
        var secId = new SecurityIdentifier(group.Properties["objectSid"][0] as byte[], 0);
    
        /* Find The RID (sure exists a best method)
         */
        var reg = new Regex(@"^S.*-(\d+)$");
        var match = reg.Match(secId.Value);
        var rid = match.Groups[1].Value;
    
        /* Directory Search for users that has a particular primary group
         */
        var dsLookForUsers =
            new DirectorySearcher {
                Filter = string.Format("(primaryGroupID={0})", rid),
                SearchScope = SearchScope.Subtree,
                PageSize = 1000,
                SearchRoot = new DirectoryEntry(strActiveDirectoryHost)
        };
        dsLookForUsers.PropertiesToLoad.Add("distinguishedName");
    
        var srcUsers = dsLookForUsers.FindAll();
    
        foreach (SearchResult user in srcUsers)
        {
            members.Add(user.Properties["distinguishedName"][0].ToString());
        }
        return members;
    }
    

    更新1:

    用于在foreach中检索DN的代码(searchResult):

    foreach (SearchResult searchResult in searchResultCollection)
    {
        string strDn = searchResult.Properties["distinguishedName"][0].ToString();
        var de = new DirectoryEntry("LDAP://" + strDn, null, null, AuthenticationTypes.Secure);
        de.RefreshCache(new[] { "objectGuid" });
        var guid = new Guid((byte[])de.Properties["objectGuid"].Value);
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Gabriel Luci    6 年前

    由于您必须为每个成员再次与Active Directory对话,因此速度将始终较慢。但是,您可以最小化它所带来的流量。

    我在监控网络流量的同时做了两个快速测试。我比较了两种方法:

    1. 使命感 .Guid DirectoryEntry ,就像在代码中一样。
    2. 使用此方法:
    var de = new DirectoryEntry("LDAP://" + member, null, null, AuthenticationTypes.Secure);
    de.RefreshCache(new [] {"objectGuid"});
    var guid = new Guid((byte[]) de.Properties["objectGuid"].Value);
    

    第二种方法的网络流量显著减少:第一个帐户的流量不足三分之一,之后每个帐户的流量甚至更少(似乎是重复使用连接)。

    我知道如果你使用 .Properties 不打电话 .RefreshCache 首先,它会拉动 每一个 帐户的属性。好像是用 .Guid 做同样的事情。

    使命感 .RefreshCache(new [] {"objectGuid"}); 仅获取 objectGuid 属性,并将其保存在缓存中。那么当你使用 .Properties["objectGuid"] 它在缓存中已经具有该属性,因此不需要再进行任何网络连接。

    更新时间: 对于你在搜索中得到的,只需询问 objectGuid 属性而不是 distinguishedName :

    dsLookForUsers.PropertiesToLoad.Add("objectGuid");
    
    var srcUsers = dsLookForUsers.FindAll();
    
    foreach (SearchResult user in srcUsers)
    {
        members.Add(new Guid((byte[])user.Properties["objectGuid"][0]));
    }