Get members of an Active Directory group recursively, i.e. including subgroups

前端 未结 2 604
小鲜肉
小鲜肉 2020-12-30 11:49

Given a group like this in Active Directory:

MainGroup
  GroupA
    User1
    User2
  GroupB
    User3
  User4

I can easily determine if Us

相关标签:
2条回答
  • 2020-12-30 12:31
        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]);
        }
    
    0 讨论(0)
  • 2020-12-30 12:49

    Just in case this might benefit someone else: here is the solution I ended up with. It is just a recursive search, with some extra checks to avoid checking the same group or user twice, e.g. if groupA is member of groupB and groupB is member of groupA or a user is member of more than one group.

    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]);
                }
            }
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题