Active Directory:DirectoryEntry 成员列表<>GroupPrincipal.GetMembers()

Active Directory: DirectoryEntry member list lt;gt; GroupPrincipal.GetMembers()(Active Directory:DirectoryEntry 成员列表lt;gt;GroupPrincipal.GetMembers())
本文介绍了Active Directory:DirectoryEntry 成员列表<>GroupPrincipal.GetMembers()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小组,我们称之为 GotRocks.我正在尝试获取其所有成员,但在 DirectoryEntry 和 AccountManagement 之间我得到的结果截然不同.以下是成员检索方法的计数:

I have a group, lets call it GotRocks. I am attempting to get all of its members, but I am getting wildly different results count-wise between DirectoryEntry and AccountManagement. Below are the counts by member retrieval method:

Method 1: DirectoryEntry.PropertyName.member = 350
Method 2: AccountManagement.GroupPrincipal.GetMembers(false) = 6500
Method 2: AccountManagement.GroupPrincipal.GetMembers(true) = 6500

作为健全性检查,我进入 ADUC 并从组中提取成员列表,默认情况下限制为 2,000.这里重要的是 ADUC 似乎验证了 AccountManagement 结果.我也检查了 Children 属性,但它是空白的.此外,DirectoryEntry 中列出的成员都不属于 SchemaName 组 - 他们都是用户.

As a sanity check, I went into ADUC and pulled the list of members from the group, which is limited to 2,000 by default. The important thing here is that ADUC seems to validate the AccountManagement result. I have checked the Children property as well, but it is blank. Also, none of the members listed in DirectoryEntry are of the SchemaName group - they are all users.

我不认为这是代码问题,但可能是对 DirectoryEntry 和 GetMembers 方法如何检索组成员缺乏了解.谁能解释为什么 DirectoryEntry 成员列表会产生与 GetMembers 递归函数不同的结果?我需要注意某种方法或属性吗?注意:我已经构建了一个函数,它将通过member;range={0}-{1}"查询 DirectoryEntry,其中循环获取 1,500 个块中的成员.我在这里完全不知所措.

I do not think this is a code problem, but perhaps a lack of understanding of how DirectoryEntry and the GetMembers methods retrieve group members. Can anyone explain why the DirectoryEntry member list would yield a different result from the GetMembers recursive function? Is there a certain method or property I need to be aware of? Note: I have built a function that will query DirectoryEntry by "member;range={0}-{1}" where the loop gets members in chunks of 1,500. I am at a complete and utter loss here.

DirectoryEntry 返回的结果如此之少的事实是有问题的,因为我想使用 DirectoryEntry 的一个简单事实是,走这条路线至少比 AccountManagement 快两个数量级(即秒表时间为 1,100 毫秒,而250,000 毫秒).

The fact that DirectoryEntry is returning so few results is problematic because I want to use DirectoryEntry for the simple fact that going this route is, at a minimum, two orders of magnitude faster than AccountManagement (i.e., stopwatch times of 1,100 milliseconds versus 250,000 milliseconds).

更新 1:方法:

方法一:目录入口

private List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
{
    // Variable declaration(s).
    List<string> listGroupMemberDn = new List<string>();
    string strPath = strActiveDirectoryHost + "/<GUID=" + strPropertyValue + ">";
    string strMemberPropertyRange = null;
    DirectoryEntry directoryEntryGroup = null;
    DirectorySearcher directorySearcher = null;
    SearchResultCollection searchResultCollection = null;
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx
    const int intIncrement = 1500;

    // Load the DirectoryEntry.
    try
    {
        directoryEntryGroup = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);

        directoryEntryGroup.RefreshCache();
    }
    catch (Exception)
    { }

    try
    {
        if (directoryEntryGroup.Properties["member"].Count > 0)
        {
            int intStart = 0;

            while (true)
            {
                int intEnd = intStart + intIncrement - 1;

                // Define the PropertiesToLoad attribute, which contains a range flag that LDAP uses to get a list of members in a pre-specified chunk/block of members that is defined by each loop iteration.
                strMemberPropertyRange = string.Format("member;range={0}-{1}", intStart, intEnd);

                directorySearcher = new DirectorySearcher(directoryEntryGroup)
                {
                    Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))", // User, Contact, Group, Computer objects

                    SearchScope = SearchScope.Base,

                    PageSize = intActiveDirectoryPageSize,

                    PropertiesToLoad = { strMemberPropertyRange }
                };

                try
                {
                    searchResultCollection = directorySearcher.FindAll();

                    foreach (SearchResult searchResult in searchResultCollection)
                    {
                        var membersProperties = searchResult.Properties;

                        // Find the property that starts with the PropertyName of "member;" and get all of its member values.
                        var membersPropertyNames = membersProperties.PropertyNames.OfType<string>().Where(n => n.StartsWith("member;"));

                        // For each record in the memberPropertyNames, get the PropertyName and add to the lest.
                        foreach (var propertyName in membersPropertyNames)
                        {
                            var members = membersProperties[propertyName];

                            foreach (string memberDn in members)
                            {                                   
                                listGroupMemberDn.Add(memberDn);
                            }
                        }
                    }
                }
                catch (DirectoryServicesCOMException)
                {
                    // When the start of the range exceeds the number of available results, an exception is thrown and we exit the loop.
                    break;
                }

                intStart += intIncrement;
            }
        }

        return listGroupMemberDn;
    }
    finally
    {
        listGroupMemberDn = null;
        strPath = null;
        strMemberPropertyRange = null;
        directoryEntryGroup.Close();
        if(directoryEntryGroup != null) directoryEntryGroup.Dispose();                
        if (directorySearcher != null) directorySearcher.Dispose();
        if(searchResultCollection != null) searchResultCollection.Dispose();
    }
}

方法 2:AccountManagement(将 bolRecursive 切换为 true 或 false).

Method 2: AccountManagement (toggle bolRecursive as either true or false).

private List<Guid> GetGroupMemberList(string strPropertyValue, string strDomainController, bool bolRecursive)
{
    // Variable declaration(s).
    List<Guid> listGroupMemberGuid = null;
    GroupPrincipal groupPrincipal = null;
    PrincipalSearchResult<Principal> listPrincipalSearchResult = null;
    List<Principal> listPrincipalNoNull = null;
    PrincipalContext principalContext = null;
    ContextType contextType;
    IdentityType identityType;

    try
    {
        listGroupMemberGuid = new List<Guid>();

        contextType = ContextType.Domain;

        principalContext = new PrincipalContext(contextType, strDomainController);

        // Setup the IdentityType. Use IdentityType.Guid because GUID is unique and never changes for a given object. Make sure that is what strPropertyValue is receiving.
        // This is required, otherwise you will get a MultipleMatchesException error that says "Multiple principals contain a matching Identity."
        // This happens when you have two objects that AD thinks match whatever you're passing to UserPrincipal.FindByIdentity(principalContextDomain, strPropertyValue)
        identityType = IdentityType.Guid;

        groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);

        if (groupPrincipal != null)
        {
            // Get all members that the group contains and add it to the list.
            // Note: The true flag in GetMembers() specifies a recursive search, which enables the application to search a group recursively and return only principal objects that are leaf nodes.
            listPrincipalSearchResult = groupPrincipal.GetMembers(bolRecursive);

            // Remove the nulls from the list, otherwise the foreach loop breaks prematurly on the first null found and misses all other object members.
            listPrincipalNoNull = listPrincipalSearchResult.Where(item => item.Name != null).ToList();

            foreach (Principal principal in listPrincipalNoNull)
            {
                listGroupMemberGuid.Add((Guid)principal.Guid);
            }
        }

        return listGroupMemberGuid;
    }
    catch (MultipleMatchesException)
    {
        // Multiple principals contain a matching identity. 
        // In other words, the same property value was found on more than one record in either of the six attributes that are listed within the IdentityType enum.
        throw new MultipleMatchesException(strPropertyValue);
    }
    finally
    {
        // Cleanup objects.
        listGroupMemberGuid = null;
        if(listPrincipalSearchResult != null) listPrincipalSearchResult.Dispose();
        if(principalContext != null) principalContext.Dispose();
        if(groupPrincipal != null) groupPrincipal.Dispose();
    }
}

更新 2:

public static void Main()
{
    Program objProgram = new Program();

    // Other stuff here.

    objProgram.GetAllUserSingleDc();

    // Other stuff here.
}

private void GetAllUserSingleDc()
{
    string strDomainController = "domain.com"; 
    string strActiveDirectoryHost = "LDAP://" + strDomainController;
    int intActiveDirectoryPageSize = 1000;
    string[] strAryRequiredProperties = null;
    DirectoryEntry directoryEntry = null;
    DirectorySearcher directorySearcher = null;
    SearchResultCollection searchResultCollection = null;
    DataTypeConverter objConverter = null;
    Type fieldsType = null;

    fieldsType = typeof(AdUserInfoClass);

    objConverter = new DataTypeConverter();

    directoryEntry = new DirectoryEntry(strActiveDirectoryHost, null, null, AuthenticationTypes.Secure);

    directorySearcher = new DirectorySearcher(directoryEntry)
    {
        //Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))", // User, Contact, Group, Computer objects
        Filter = "(sAMAccountName=GotRocks)", // Group

        SearchScope = SearchScope.Subtree,

        PageSize = intActiveDirectoryPageSize

        PropertiesToLoad = { "isDeleted","isCriticalSystemObject","objectGUID","objectSid","objectCategory","sAMAccountName","sAMAccountType","cn","employeeId",
                            "canonicalName","distinguishedName","userPrincipalName","displayName","givenName","sn","mail","telephoneNumber","title","department",
                            "description","physicalDeliveryOfficeName","manager","userAccountControl","accountExpires","lastLogon","logonCount","lockoutTime",
                            "primaryGroupID","pwdLastSet","uSNCreated","uSNChanged","whenCreated","whenChanged","badPasswordTime","badPwdCount","homeDirectory",
                            "dNSHostName" }
    };         

    searchResultCollection = directorySearcher.FindAll();            

    try
    {
        foreach (SearchResult searchResult in searchResultCollection)
        {
            clsAdUserInfo.GidObjectGuid = objConverter.ConvertByteAryToGuid(searchResult, "objectGUID");            
            clsAdUserInfo.StrDirectoryEntryPath = strActiveDirectoryHost + "/<GUID=" + clsAdUserInfo.GidObjectGuid + ">";
            clsAdUserInfo.StrSchemaClassName = new DirectoryEntry(clsAdUserInfo.StrDirectoryEntryPath, null, null, AuthenticationTypes.Secure).SchemaClassName;

            if (clsAdUserInfo.StrSchemaClassName == "group")
            {
                // Calling the functions here.
                List<string> listGroupMemberDnMethod1 = GetGroupMemberListStackOverflow(clsAdUserInfo.GidObjectGuid.ToString(), strActiveDirectoryHost, intActiveDirectoryPageSize);

                List<Guid> listGroupMemberGuidMethod2 = GetGroupMemberList(clsAdUserInfo.GidObjectGuid.ToString(), strDomainController, false)
            }   
            // More stuff here.
        }
    }
    finally
    {
        // Cleanup objects.
        // Class constructors.
        objProgram = null;
        clsAdUserInfo = null;
        // Variables.
        intActiveDirectoryPageSize = -1;
        strActiveDirectoryHost = null;
        strDomainController = null;
        strAryRequiredProperties = null;
        directoryEntry.Close();
        if(directoryEntry !=null) directoryEntry.Dispose();
        if(directorySearcher != null) directorySearcher.Dispose();
        if(searchResultCollection != null) searchResultCollection.Dispose();
        objConverter = null;
        fieldsType = null;
    }   
}

更新 3:

下面是我使用的命名空间列表.

Below is the list of namespaces that I am using.

using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Security.Principal;
using System.Text;
using System.Linq;
using System.Collections;

更新 4:Program.cs

using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Security.Principal;
using System.Text;
using System.Linq;

namespace activeDirectoryLdapExamples
{
    public class Program
    {
         public static void Main()
        {
            Program objProgram = new Program();
            objProgram.GetAllUserSingleDc();
        }

        #region GetAllUserSingleDc
        private void GetAllUserSingleDc()
        {
            Program objProgram = new Program();
            string strDomainController = "EnterYourDomainhere";
            string strActiveDirectoryHost = "LDAP://" + strDomainController;
            int intActiveDirectoryPageSize = 1000;
            DirectoryEntry directoryEntry = null;
            DirectorySearcher directorySearcher = null;
            SearchResultCollection searchResultCollection = null;
            DataTypeConverter objConverter = null;

            objConverter = new DataTypeConverter();

            directoryEntry = new DirectoryEntry(strActiveDirectoryHost, null, null, AuthenticationTypes.Secure);

            directorySearcher = new DirectorySearcher(directoryEntry)
            {
                Filter = "(sAMAccountName=GotRocks)", // Group

                SearchScope = SearchScope.Subtree,

                PageSize = intActiveDirectoryPageSize,

                PropertiesToLoad = { "isDeleted","isCriticalSystemObject","objectGUID","objectSid","objectCategory","sAMAccountName","sAMAccountType","cn","employeeId",
                                        "canonicalName","distinguishedName","userPrincipalName","displayName","givenName","sn","mail","telephoneNumber","title","department",
                                        "description","physicalDeliveryOfficeName","manager","userAccountControl","accountExpires","lastLogon","logonCount","lockoutTime",
                                        "primaryGroupID","pwdLastSet","uSNCreated","uSNChanged","whenCreated","whenChanged","badPasswordTime","badPwdCount","homeDirectory",
                                        "dNSHostName" }
            };

            searchResultCollection = directorySearcher.FindAll();

            try
            {
                foreach (SearchResult searchResult in searchResultCollection)
                {                    
                    Guid? gidObjectGuid = objConverter.ConvertByteAryToGuid(searchResult, "objectGUID");
                    string StrSamAccountName = objConverter.ConvertToString(searchResult, "sAMAccountName");
                    // Get new DirectoryEntry and retrieve the SchemaClassName from it by binding the current objectGUID to it.
                    string StrDirectoryEntryPath = strActiveDirectoryHost + "/<GUID=" + gidObjectGuid + ">";
                    string StrSchemaClassName = new DirectoryEntry(StrDirectoryEntryPath, null, null, AuthenticationTypes.Secure).SchemaClassName;

                    #region GetGroupMembers
                    if (StrSchemaClassName == "group")
                    {
                        // FAST!
                        var watch = System.Diagnostics.Stopwatch.StartNew();
                        List<string> listGroupMemberDn = GetGroupMemberList(gidObjectGuid.ToString(), strActiveDirectoryHost, intActiveDirectoryPageSize);
                        watch.Stop();
                        var listGroupMemberDnElapsedMs = watch.ElapsedMilliseconds;

                        // SLOW!
                        watch = System.Diagnostics.Stopwatch.StartNew();
                        List<Guid> listGroupMemberGuidRecursiveTrue = GetGroupMemberList(gidObjectGuid.ToString(), strDomainController, true);
                        watch.Stop();
                        var listGroupMemberGuidRecursiveTrueElapsedMs = watch.ElapsedMilliseconds;

                        watch = System.Diagnostics.Stopwatch.StartNew();
                        List<Guid> listGroupMemberGuidRecursiveFalse = GetGroupMemberList(gidObjectGuid.ToString(), strDomainController, false);
                        watch.Stop();
                        var listGroupMemberGuidRecursiveFalseElapsedMs = watch.ElapsedMilliseconds;

                        ////// Display all members of the list.
                        //listGroupMemberDn.ForEach(item => Console.WriteLine("Member GUID: {0}", item));
                        //listGroupMemberGuidRecursiveTrue.ForEach(item => Console.WriteLine("Member GUID: {0}", item));
                        //listGroupMemberGuidRecursiveFalse.ForEach(item => Console.WriteLine("Member GUID: {0}", item));

                        Console.WriteLine("objectGUID: {0}", gidObjectGuid);
                        Console.WriteLine("sAMAccountName: {0}", strSamAccountName);

                        // Result: 350
                        Console.WriteLine("
listGroupMemberDn Count Members: {0}", listGroupMemberDn.Count);
                        Console.WriteLine("Total RunTime listGroupMemberDnElapsedMs (in milliseconds): {0}", listGroupMemberDnElapsedMs);

                        // Result: 6500
                        Console.WriteLine("
listGroupMemberGuidRecursiveTrue Count Members: {0}", listGroupMemberGuidRecursiveTrue.Count);
                        Console.WriteLine("Total RunTime listGroupMemberGuidRecursiveTrueElapsedMs (in milliseconds): {0}", listGroupMemberGuidRecursiveTrueElapsedMs);

                        // Result: 6500
                        Console.WriteLine("
listGroupMemberGuidRecursiveFalse Count Members: {0}", listGroupMemberGuidRecursiveFalse.Count);
                        Console.WriteLine("Total RunTime listGroupMemberGuidRecursiveFalseElapsedMs (in milliseconds): {0}", listGroupMemberGuidRecursiveFalseElapsedMs);
                        Console.WriteLine("
");
                    }
                    #endregion

                    #region CurrentSearchResult
                    else
                    {
                        Console.WriteLine("ObjectGuid = {0}", gidObjectGuid);
                        Console.WriteLine("SamAccountName = {0}", strSamAccountName);

                    }
                    #endregion
                }

                Console.WriteLine("
Press any key to continue.");
                Console.ReadKey();
            }
            finally
            {
                objProgram = null;
                intActiveDirectoryPageSize = -1;
                strActiveDirectoryHost = null;
                strDomainController = null;
                directoryEntry.Close();
                if (directoryEntry != null) directoryEntry.Dispose();
                if (directorySearcher != null) directorySearcher.Dispose();
                if (searchResultCollection != null) searchResultCollection.Dispose();
                objConverter = null;
            }
        }
        #endregion

        #region GetGroupMemberListGuid
        private List<Guid> GetGroupMemberList(string strPropertyValue, string strDomainController, bool bolRecursive)
        {
            List<Guid> listGroupMemberGuid = null;
            List<Principal> listPrincipalNoNull = null;
            GroupPrincipal groupPrincipal = null;
            PrincipalSearchResult<Principal> listPrincipalSearchResult = null;
            PrincipalContext principalContext = null;
            ContextType contextType;
            IdentityType identityType;

            try
            {
                listGroupMemberGuid = new List<Guid>();

                contextType = ContextType.Domain;

                principalContext = new PrincipalContext(contextType, strDomainController);

                identityType = IdentityType.Guid;

                groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);

                if (groupPrincipal != null)
                {
                    listPrincipalSearchResult = groupPrincipal.GetMembers(bolRecursive);

                    listPrincipalNoNull = listPrincipalSearchResult.Where(item => item.Name != null).ToList();

                    foreach (Principal principal in listPrincipalNoNull)
                    {
                        listGroupMemberGuid.Add((Guid)principal.Guid);
                    }
                }

                return listGroupMemberGuid;
            }
            catch (MultipleMatchesException)
            {
                throw new MultipleMatchesException(strPropertyValue);
            }
            finally
            {
                // Cleanup objects.
                listGroupMemberGuid = null;
                listPrincipalNoNull = null;
                principalContext = null;
                if (groupPrincipal != null) groupPrincipal.Dispose();
                if (listPrincipalSearchResult != null) listPrincipalSearchResult.Dispose();
                if (principalContext != null) principalContext.Dispose();
            }
        }
        #endregion

        #region GetGroupMemberListDn
        private List<string> GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
        {
            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}-*" });
            }
            return members;
        }
        #endregion

        #region DataTypeConvert
        private class DataTypeConverter
        {
            public DataTypeConverter() { }

            public String ConvertToString(SearchResult searchResult, string strPropertyName)
            {
                String bufferObjectString = null;

                try
                {
                    bufferObjectString = (String)this.GetPropertyValue(searchResult, strPropertyName);

                    if (string.IsNullOrEmpty(bufferObjectString))
                    {
                        return null;
                    }
                    else
                    {
                        return bufferObjectString;
                    }
                }
                finally
                {
                    bufferObjectString = null;
                }
            }

            public Guid? ConvertByteAryToGuid(SearchResult searchResult, string strPropertyName)
            {
                Guid? bufferObjectGuid = null;

                try
                {
                    bufferObjectGuid = new Guid((Byte[])(Array)this.GetPropertyValue(searchResult, strPropertyName));

                    if (bufferObjectGuid == null || bufferObjectGuid == Guid.Empty)
                    {
                        throw new NullReferenceException("The field " + strPropertyName + ", of type GUID, can neither be NULL nor empty.");
                    }
                    else
                    {
                        return bufferObjectGuid;
                    }
                }
                finally
                {
                    bufferObjectGuid = null;
                }
            }
        }
        #endregion
    }
}

推荐答案

最后一个代码块(更新2)就是答案!

用于读取 member 属性的代码比它需要的要复杂.它返回倾斜的结果可能是有原因的,但我并没有看得太难,因为您根本不需要使用 DirectorySearcher .我只是重写了它.

The code you have for reading the member attribute is more complicated than it needs to be. There may be a reason in there why it's returning skewed results, but I didn't look too hard because you don't need to be using DirectorySearcher at all. I just rewrote it.

这是最简单的形式:

private static List<string> GetGroupMemberList(string groupGuid, string domainDns) {
    var members = new List<string>();

    var group = new DirectoryEntry($"LDAP://{domainDns}/<GUID={groupGuid}>", null, null, AuthenticationTypes.Secure);

    while (true) {
        var memberDns = group.Properties["member"];
        foreach (var member in memberDns) {
            members.Add(member.ToString());
        }

        if (memberDns.Count == 0) break;

        try {
            group.RefreshCache(new[] {$"member;range={members.Count}-*", "member"});
        } catch (System.Runtime.InteropServices.COMException e) {
            if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
                break;
            }
            throw;
        }
    }
    return members;
}

这样称呼它:

var members = GetGroupMemberList("00000000-0000-0000-0000-000000000000", "domain.com");

这不是递归的.要使其递归,您必须从每个成员创建一个新的 DirectoryEntry 并测试它是否是一个组,然后获取该组的成员.

This is not recursive. To make it recursive, you will have to create a new DirectoryEntry from each member and test if it is a group, then get the members of that group.

我打开了代码,所以这里是递归版本.它很慢,因为它必须绑定到每个成员才能查看它是否是一个组.

I have the code open, so here's the recursive version. It is slow because it has to bind to each member to see if it's a group.

这不是防弹的.在某些情况下,您可能会得到奇怪的结果(例如,如果您的用户组中有受信任的外部域上的用户).

This is not bullet-proof. There are still cases where you might get weird results (like if you have users on trusted external domains in a group).

private static List<string> GetGroupMemberList(string groupGuid, string domainDns, bool recurse = false) {
    var members = new List<string>();

    var group = new DirectoryEntry($"LDAP://{domainDns}/<GUID={groupGuid}>", null, null, AuthenticationTypes.Secure);

    while (true) {
        var memberDns = group.Properties["member"];
        foreach (var member in memberDns) {
            if (recurse) {
                var memberDe = new DirectoryEntry($"LDAP://{member}");
                if (memberDe.Properties["objectClass"].Contains("group")) {
                    members.AddRange(GetGroupMemberList(
                        new Guid((byte[]) memberDe.Properties["objectGuid"].Value).ToString(), domainDns,
                        true));
                } else {
                    members.Add(member.ToString());
                }
            } else {
                members.Add(member.ToString());
            }
        }

        if (memberDns.Count == 0) break;

        try {
            group.RefreshCache(new[] {$"member;range={members.Count}-*", "member"});
        } catch (System.Runtime.InteropServices.COMException e) {
            if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
                break;
            }
            throw;
        }
    }
    return members;
}

更新:我确实必须编辑您的 GetMembers 示例,因为它不断向我抛出异常.我注释掉了 .Where 行并更改了将成员添加到列表中的 foreach 循环:

Update: I did have to edit your GetMembers example, since it kept throwing exceptions on me. I commented out the .Where line and changed the foreach loop that adds the members to the list:

        //listPrincipalNoNull = listPrincipalSearchResult.Where(item => item.Name != null).ToList();
        if (groupPrincipal != null) {
            foreach (Principal principal in listPrincipalSearchResult) {
                listGroupMemberGuid.Add(((DirectoryEntry)principal.GetUnderlyingObject()).Guid);
            }
        }

这当然是在编译一个 Guid 列表而不是 DN.

This, of course, is compiling a list of Guids rather than DNs.

更新 2: 这是一个版本,它还拉取将该组作为主要组的用户(但未在 member 中列出组的属性).GetMembers 似乎可以做到这一点.将用户创建的组作为主要组会很奇怪,但在技术上是可行的.部分内容从此处的答案中复制:如何检索组中的用户,包括主要组用户

Update 2: Here is a version that also pulls users who have the group as the primary group (but not listed in the member attribute of the group). GetMembers seems to do this. It would be odd for a user-created group to be the primary group, but it is technically possible. Parts of this are copied from the answer here: How to retrieve Users in a Group, including primary group users

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;
}

这篇关于Active Directory:DirectoryEntry 成员列表&lt;&gt;GroupPrincipal.GetMembers()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)