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

我是研究僧i 提交于 2019-11-29 09:38:08

问题


Given a group like this in Active Directory:

MainGroup
  GroupA
    User1
    User2
  GroupB
    User3
  User4

I can easily determine if User3 is member of MainGroup or any of its subgroups with code like this:

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

I would like to know if there is a similar way to get all the users that are member of a group or any of its subgroups, i.e. in the example for MainGroup get User1, User2, User3 and User4.

The obvious way of getting all the users is to recursively query each subgroup, but I was wondering if there is an easier way to do it.

Using the same approach with the memberOf:1.2.840.113556.1.4.1941: filter, but using the domain root instead of the user as a search base is not feasible, as the query takes too long (probably it computes all the group memberships recursively for all users in the domain and checks if they are member of the given group).

Which is the best way to get all members of a group, including its subgroups?


回答1:


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

}



回答2:


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


来源:https://stackoverflow.com/questions/3665487/get-members-of-an-active-directory-group-recursively-i-e-including-subgroups

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!