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

在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: filter相同的方法,但使用域根而不是用户作为搜索库是不可行的,因为查询花费的时间太长(可能它以递归方式计算所有组成员资格)对于域中的所有用户,并检查它们是否是给定组的成员)。

获取组中所有成员(包括其子组)的最佳方法是什么?

万一这可能会让其他人受益:这是我最终解决的问题。 它只是一个递归搜索,有一些额外的检查以避免两次检查同一组或用户,例如,如果groupA是groupB的成员,groupB是groupA的成员,或者用户是多个组的成员。

 using System; using System.DirectoryServices; using System.Collections.Generic; static class Program { static IEnumerable 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 GetUsersRecursively(DirectoryEntry searchRoot, string groupDn) { List searchedGroups = new List(); List searchedUsers = new List(); return GetUsersRecursively(searchRoot, groupDn, searchedGroups, searchedUsers); } static IEnumerable GetUsersRecursively( DirectoryEntry searchRoot, string groupDn, List searchedGroups, List 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]); } } } } 
  static List 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 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(asPropsToLoad); if (Array.BinarySearch(asPropsToLoad, sDN) < 0) { Array.Resize(ref asPropsToLoad, asPropsToLoad.Length+1); asPropsToLoad[asPropsToLoad.Length-1] = sDN; } if (Array.BinarySearch(asPropsToLoad, sOC) < 0) { Array.Resize(ref asPropsToLoad, asPropsToLoad.Length+1); asPropsToLoad[asPropsToLoad.Length-1] = sOC; } List lsr = new List(); 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