代码之家  ›  专栏  ›  技术社区  ›  Paolo Tedesco

递归获取Active Directory组的成员,即包括子组

  •  7
  • Paolo Tedesco  · 技术社区  · 14 年前

    在Active Directory中给定这样的组:

    MainGroup
      GroupA
        User1
        User2
      GroupB
        User3
      User4
    

    我可以很容易地确定User3是MainGroup的成员还是它的任何子组的成员,代码如下:

    using System;
    using System.DirectoryServices;
    
    static class Program {
        static void Main() {
            DirectoryEntry user = new DirectoryEntry("LDAP://CN=User3,DC=X,DC=y");
            string filter = "(memberOf:1.2.840.113556.1.4.1941:=CN=MainGroup,DC=X,DC=y)";
            DirectorySearcher searcher = new DirectorySearcher(user, filter);
            searcher.SearchScope = SearchScope.Subtree;
            var r = searcher.FindOne();
            bool isMember = (r != null);
        }
    }
    

    我想知道是否有类似的方法来获取一个组或其任何子组的所有成员,即在MainGroup的示例中获取User1、User2、User3和User4。

    获取所有用户的明显方法是递归地查询每个子组,但我想知道是否有一种更简单的方法。

    memberOf:1.2.840.113556.1.4.1941: 筛选,但使用域根而不是用户作为搜索基础是不可行的,因为查询花费的时间太长(可能它递归计算域中所有用户的所有组成员身份,并检查他们是否是给定组的成员)。

    2 回复  |  直到 5 年前
        1
  •  22
  •   Paolo Tedesco    14 年前

    以防这对其他人有好处:下面是我最终得到的解决方案。它只是一个递归搜索,通过一些额外的检查来避免对同一个组或用户进行两次检查,例如,如果groupA是groupB的成员,groupB是groupA的成员,或者某个用户是多个组的成员。

    using System;
    using System.DirectoryServices;
    using System.Collections.Generic;
    
    static class Program {
    
        static IEnumerable<SearchResult> GetMembers(DirectoryEntry searchRoot, string groupDn, string objectClass) {
            using (DirectorySearcher searcher = new DirectorySearcher(searchRoot)) {
                searcher.Filter = "(&(objectClass=" + objectClass + ")(memberOf=" + groupDn + "))";
                searcher.PropertiesToLoad.Clear();
                searcher.PropertiesToLoad.AddRange(new string[] { 
                    "objectGUID",
                    "sAMAccountName",
                    "distinguishedName"});
                searcher.Sort = new SortOption("sAMAccountName", SortDirection.Ascending);
                searcher.PageSize = 1000;
                searcher.SizeLimit = 0;
                foreach (SearchResult result in searcher.FindAll()) {
                    yield return result;
                }
            }
        }
    
        static IEnumerable<SearchResult> GetUsersRecursively(DirectoryEntry searchRoot, string groupDn) {
            List<string> searchedGroups = new List<string>();
            List<string> searchedUsers = new List<string>();
            return GetUsersRecursively(searchRoot, groupDn, searchedGroups, searchedUsers);
        }
    
        static IEnumerable<SearchResult> GetUsersRecursively(
            DirectoryEntry searchRoot,
            string groupDn,
            List<string> searchedGroups,
            List<string> searchedUsers) {
            foreach (var subGroup in GetMembers(searchRoot, groupDn, "group")) {
                string subGroupName = ((string)subGroup.Properties["sAMAccountName"][0]).ToUpperInvariant();
                if (searchedGroups.Contains(subGroupName)) {
                    continue;
                }
                searchedGroups.Add(subGroupName);
                string subGroupDn = ((string)subGroup.Properties["distinguishedName"][0]);
                foreach (var user in GetUsersRecursively(searchRoot, subGroupDn, searchedGroups, searchedUsers)) {
                    yield return user;
                }
            }
            foreach (var user in GetMembers(searchRoot, groupDn, "user")) {
                string userName = ((string)user.Properties["sAMAccountName"][0]).ToUpperInvariant();
                if (searchedUsers.Contains(userName)) {
                    continue;
                }
                searchedUsers.Add(userName);
                yield return user;
            }
        }
    
        static void Main(string[] args) {
            using (DirectoryEntry searchRoot = new DirectoryEntry("LDAP://DC=x,DC=y")) {
                foreach (var user in GetUsersRecursively(searchRoot, "CN=MainGroup,DC=x,DC=y")) {
                    Console.WriteLine((string)user.Properties["sAMAccountName"][0]);
                }
            }
        }
    
    }
    
        2
  •  1
  •   Dimitre Chtilianov    13 年前
        static List<SearchResult> ad_find_all_members(string a_sSearchRoot, string a_sGroupDN, string[] a_asPropsToLoad)
        {
            using (DirectoryEntry de = new DirectoryEntry(a_sSearchRoot))
                return ad_find_all_members(de, a_sGroupDN, a_asPropsToLoad);
        }
    
        static List<SearchResult> ad_find_all_members(DirectoryEntry a_SearchRoot, string a_sGroupDN, string[] a_asPropsToLoad)
        {
            string sDN = "distinguishedName";
            string sOC = "objectClass";
            string sOC_GROUP = "group";
            string[] asPropsToLoad = a_asPropsToLoad;
            Array.Sort<string>(asPropsToLoad);
            if (Array.BinarySearch<string>(asPropsToLoad, sDN) < 0)
            {
                Array.Resize<string>(ref asPropsToLoad, asPropsToLoad.Length+1);
                asPropsToLoad[asPropsToLoad.Length-1] = sDN;
            }
            if (Array.BinarySearch<string>(asPropsToLoad, sOC) < 0)
            {
                Array.Resize<string>(ref asPropsToLoad, asPropsToLoad.Length+1);
                asPropsToLoad[asPropsToLoad.Length-1] = sOC;
            }
    
            List<SearchResult> lsr = new List<SearchResult>();
    
            using (DirectorySearcher ds = new DirectorySearcher(a_SearchRoot))
            {
                ds.Filter = "(&(|(objectClass=group)(objectClass=user))(memberOf=" + a_sGroupDN + "))";
                //ds.PropertiesToLoad.Clear();
                ds.PropertiesToLoad.AddRange(asPropsToLoad);
                //ds.PageSize = 1000;
                //ds.SizeLimit = 0;
                foreach (SearchResult sr in ds.FindAll())
                    lsr.Add(sr);
            }
    
            for(int i=0;i<lsr.Count;i++)
                if (lsr[i].Properties.Contains(sOC) && lsr[i].Properties[sOC].Contains(sOC_GROUP))
                    lsr.AddRange(ad_find_all_members(a_SearchRoot, (string)lsr[i].Properties[sDN][0], asPropsToLoad));
    
            return lsr;
        }
    
        static void Main(string[] args)
        {
        foreach (var sr in ad_find_all_members("LDAP://DC=your-domain,DC=com", "CN=your-group-name,OU=your-group-ou,DC=your-domain,DC=com", new string[] { "sAMAccountName" }))
            Console.WriteLine((string)sr.Properties["distinguishedName"][0] + " : " + (string)sr.Properties["sAMAccountName"][0]);
        }