2010-09-08 15 views
7

Given grupę tak w usłudze Active Directory:Get członków grupy Active Directory, rekursywnie, czyli łącznie z podgrupami

MainGroup 
    GroupA 
    User1 
    User2 
    GroupB 
    User3 
    User4 

można łatwo ustalić, czy User3 jest członkiem MainGroup lub jej podgrup z kodem jak ta :

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

chciałbym wiedzieć, czy istnieje podobny sposób uzyskać wszystkich użytkowników, które są członkiem grupy lub któregokolwiek z jej podgrup, czyli w przykładzie dla MainGroup dostać User1, Użytkownik2, User3 i użytkownik4 .

Oczywistym sposobem na uzyskanie wszystkich użytkowników jest rekursywne zapytanie każdej podgrupy, ale zastanawiałem się, czy jest łatwiejszy sposób.

Stosując takie samo podejście z filtrem memberOf:1.2.840.113556.1.4.1941:, ale korzystając z korzenia domeny zamiast użytkownika jako podstawy wyszukiwania nie jest wykonalne, jako zapytanie trwa zbyt długo (prawdopodobnie to oblicza wszystkie członkostwa grupy rekursywnie dla wszystkich użytkowników w domena i sprawdza, czy są członkami danej grupy).

Jaki jest najlepszy sposób na uzyskanie wszystkich członków grupy, w tym jej podgrup?

Odpowiedz

15

Na wszelki wypadek może to przynieść korzyść komuś innemu: oto rozwiązanie, które znalazłem. Jest to po prostu wyszukiwanie cykliczne z kilkoma dodatkowymi sprawdzeniami, aby uniknąć dwukrotnego sprawdzania tej samej grupy lub użytkownika, np. jeśli grupa A jest członkiem grupy B, a grupa B jest członkiem grupy A lub użytkownik jest członkiem więcej niż jednej grupy.

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

Ten post został tu na chwilę, ale chciałem dodać dzięki za komentarz odpowiedź. Właśnie spotkałem się z tym samym problemem, a ja zamierzam to wypróbować. – Steven

+0

Nie wiem, czy to zobaczysz (lub nawet, jeśli jest to najbardziej odpowiedni sposób zadawania takich pytań, ale mam problemy z uruchomieniem tego, i myślę, że to prawdopodobnie z powodu mojego braku Zrozumienie AD Kiedy otrzymuję odrębną nazwę (DN) mojej grupy, to zwraca ona coś takiego: "CN = , OU = , OU = Lista dystrybucyjna, OU = Usługi Exchange, OU = Podstawowe usługi katalogowe, DC = , DC = com 'Ale kiedy próbowałem dotrzeć do tego (lub tego bez wiodącego "CN ="), dostaję "Nieokreślony błąd" w punkcie, w którym poszukiwacz iterował przez FindAll() – Steven

+0

@Steven: Myślę, że najlepiej byłoby opublikować nowe pytanie (z linkiem do tego, jeśli jest to problem pokrewny). W tej chwili nie mogę ci pomóc, ponieważ brakuje mi domeny do przetestowania, przepraszam :) –

1
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]); 
    } 
Powiązane problemy