2011-06-24 11 views
5

W aplikacji internetowej chcemy wyświetlić listę kont sam dla użytkowników, którzy są członkami określonej grupy. Grupy mogą mieć w wielu przypadkach 500 lub więcej członków, a my potrzebujemy reakcji strony.Szybki sposób na uzyskanie listy członków grupy w Active Directory za pomocą C#

Z grupą około 500 członków, trwa 7-8 sekund, aby uzyskać listę kont sam dla wszystkich członków grupy. Czy są szybsze sposoby? Wiem, że konsola zarządzania usługą Active Directory robi to w ciągu sekundy.

Próbowałem kilka metod:

1)

PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain) 
GroupPrincipal grp = GroupPrincipal.FindByIdentity(pcRoot, "MyGroup"); 
List<string> lst = grp.Members.Select(g => g.SamAccountName).ToList(); 

2)

PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain) 
GroupPrincipal grp = GroupPrincipal.FindByIdentity(pcRoot, "MyGroup"); 
PrincipalSearchResult<Principal> lstMembers = grp.GetMembers(true); 
List<string> lst = new List<string>(); 
foreach (Principal member in lstMembers) 
{ 
    if (member.StructuralObjectClass.Equals("user")) 
    { 
     lst.Add(member .SamAccountName); 
    } 
} 

3)

PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain) 
GroupPrincipal grp = GroupPrincipal.FindByIdentity(pcRoot, "MyGroup"); 
System.DirectoryServices.DirectoryEntry de = (System.DirectoryServices.DirectoryEntry)grp.GetUnderlyingObject(); 
List<string> lst = new List<string>(); 
foreach (string sDN in de.Properties["member"]) 
{ 
    System.DirectoryServices.DirectoryEntry deMember = new System.DirectoryServices.DirectoryEntry("LDAP://" + sDN); 
    lst.Add(deMember.Properties["samAccountName"].Value.ToString()); 
} 

Odpowiedz

0

Czy próbowałeś kwerendy LDAP? W dolnej części strony znajduje się przykład w języku C# do wyliczania za pośrednictwem grupy, aby uzyskać członków. MSDN BOL

using System; 
using System.DirectoryServices; 

namespace ADAM_Examples 
{ 
class EnumMembers 
{ 
    /// <summary> 
    /// Enumerate AD LDS groups and group members. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     DirectoryEntry objADAM;     // Binding object. 
     DirectoryEntry objGroupEntry;    // Group Results. 
     DirectorySearcher objSearchADAM;   // Search object. 
     SearchResultCollection objSearchResults; // Results collection. 
     string strPath;       // Binding path. 

     // Construct the binding string. 
     strPath = "LDAP://localhost:389/OU=TestOU,O=Fabrikam,C=US"; 
     Console.WriteLine("Bind to: {0}", strPath); 
     Console.WriteLine("Enum: Groups and members."); 

     // Get the AD LDS object. 
     try 
     { 
      objADAM = new DirectoryEntry(strPath); 
      objADAM.RefreshCache(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Error: Bind failed."); 
      Console.WriteLine("   {0}", e.Message); 
      return; 
     } 

     // Get search object, specify filter and scope, 
     // perform search. 
     try 
     { 
      objSearchADAM = new DirectorySearcher(objADAM); 
      objSearchADAM.Filter = "(&(objectClass=group))"; 
      objSearchADAM.SearchScope = SearchScope.Subtree; 
      objSearchResults = objSearchADAM.FindAll(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Error: Search failed."); 
      Console.WriteLine("   {0}", e.Message); 
      return; 
     } 

     // Enumerate groups and members. 
     try 
     { 
      if (objSearchResults.Count != 0) 
      { 
       foreach(SearchResult objResult in objSearchResults) 
       { 
        objGroupEntry = objResult.GetDirectoryEntry(); 
        Console.WriteLine("Group {0}", 
         objGroupEntry.Name); 
        foreach(object objMember 
         in objGroupEntry.Properties["member"]) 
        { 
         Console.WriteLine(" Member: {0}", 
          objMember.ToString()); 
        } 
       } 
      } 
      else 
      { 
       Console.WriteLine("Results: No groups found."); 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Error: Enumerate failed."); 
      Console.WriteLine("   {0}", e.Message); 
      return; 
     } 

     Console.WriteLine("Success: Enumeration complete."); 
     return; 
    } 
} 

}

+0

Jest to podobne do przykładu 3 w moim pytaniu, część, która pobiera czas logu, interweniuje poprzez każdy element we właściwości członka. – Jeremy

+0

musicie pokochać notację węgierską, niektóre archaiczne pozostałości z oryginalnego przykładu: –

5

Współpracownik kopalni mieli podobne problemy z czasów zapytania przy użyciu różnych metod pobierania Active Directory. Skończyło się na buforowaniu informacji w bazie danych i odświeżaniu jej co wieczór, a następnie dostęp do bazy danych.

Biorąc pod uwagę fakt, że Konta użytkowników nie zmieniają się zbyt często, był to dla niego odpowiedni kompromis. W zależności od zastosowania może to być nieakceptowane.

4

Oto wyszukiwanie cykliczne (szukaj użytkowników w grupach zagnieżdżonych) za pomocą ADSI.

static void Main(string[] args) 
{ 
    /* Connection to Active Directory 
    */ 
    string sFromWhere = "LDAP://SRVENTR2:389/dc=societe,dc=fr"; 
    DirectoryEntry deBase = new DirectoryEntry(sFromWhere, "societe\\administrateur", "test.2011"); 

    /* To find all the users member of groups "Grp1" : 
    * Set the base to the groups container DN; for example root DN (dc=societe,dc=fr) 
    * Set the scope to subtree 
    * Use the following filter : 
    * (member:1.2.840.113556.1.4.1941:=CN=Grp1,OU=MonOu,DC=X) 
    */ 
    DirectorySearcher dsLookFor = new DirectorySearcher(deBase); 
    dsLookFor.Filter = "(&(memberof:1.2.840.113556.1.4.1941:=CN=Grp1,OU=MonOu,DC=societe,DC=fr)(objectCategory=user))"; 
    dsLookFor.SearchScope = SearchScope.Subtree; 
    dsLookFor.PropertiesToLoad.Add("cn"); 
    dsLookFor.PropertiesToLoad.Add("samAccountName"); 

    SearchResultCollection srcUsers = dsLookFor.FindAll(); 

    /* Just show each user 
    */ 
    foreach (SearchResult srcUser in srcUsers) 
    { 
    Console.WriteLine("{0}", srcUser.Path); 
    Console.WriteLine("{0}", srcUser.Properties["samAccountName"][0]); 
    } 

    Console.ReadLine(); 
} 
+1

jednym z głównych powodów, dla których to przeżyliśmy, było to, że wydajność AccountManagement jest niska. Jedynym sposobem, aby naprawdę uzyskać wydajność wyszukiwania AD, jest przejście do biblioteki DirectoryServices. Clunky api, ale naprawdę szybko –

1

Spróbuj to nie wiem, czy byłoby szybciej, ale ....

 PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain) 

     GroupPrincipal mygroup = new GroupPrincipal(pcRoot); 

     // define the principal searcher, based on that example principal 

     PrincipalSearcher ps = new PrincipalSearcher(mygroup); 

     ps.QueryFilter = new GroupPrincipal(pcRoot) { SamAccountName = "Name of your group Case Sensitive" }; 

     List<UserPrincipal> users = new List<UserPrincipal>(); 
     // loop over all principals found by the searcher 

     GroupPrincipal foundGroup = (GroupPrincipal)ps.FindOne(); 

foreach (UserPrincipal u in foundGroup.Members) 
        { 
         users.Add(u); 

        } 
//OR 
List<string> lst = foundGroup.Members.Select(g => g.SamAccountName).ToList();//this will only get the usernames not the user object or UserPrincipal 
0

Podobny do pierwszej opcji, stworzyłem hashset z listy. Im większa grupa, tym dłużej trwa weryfikacja członkostwa. Jest jednak spójny dla pomyślnych i nieudanych zapytań o członkostwo. Wielokrotne iterowanie przez dużą grupę może trwać nawet trzykrotnie dłużej, jeśli konto nie jest członkiem, podczas gdy ta metoda jest zawsze taka sama.

using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain)) 
using(GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "groupName")) 
{ 
    List<string> members = group.GetMembers(true).Select(g => g.SamAccountName).ToList(); 
    HashSet<string> hashset = new HashSet<string>(members, StringComparer.OrdinalIgnoreCase); 

    if(hashset.Contains(someUser) 
     return true; 
} 
Powiązane problemy