2011-06-24 14 views
5

En una aplicación web, estamos buscando mostrar una lista de cuentas sam para usuarios que son miembros de un determinado grupo. Los grupos pueden tener 500 o más miembros en muchos casos y necesitamos que la página responda.Forma rápida de obtener una lista de miembros del grupo en Active Directory con C#

Con un grupo de aproximadamente 500 miembros, se requieren de 7-8 segundos para obtener una lista de las cuentas de sam para todos los miembros del grupo. ¿Hay formas más rápidas? Sé que la Consola de administración de Active Directory lo hace en menos de un segundo.

He probado unos cuantos métodos:

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

Respuesta

0

¿Has probado una consulta LDAP? La parte inferior de la página tiene un ejemplo en C# para enumerar a través de un grupo para obtener miembros. 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

Esto es similar al ejemplo 3 en mi pregunta, la parte que requiere un tiempo de registro se integra a través de cada elemento en la propiedad del miembro. – Jeremy

+0

tiene que amar la notación húngara, algunos restos arcaicos de un ejemplo original –

5

Un compañero de trabajo mío tenía problemas similares con los tiempos de consulta cuando se utilizan varios métodos de recuperación de Active Directory. Terminó almacenando en caché la información en una base de datos y actualizándola todas las noches y luego simplemente accediendo a la base de datos.

Teniendo en cuenta que las Cuentas de usuario no cambian con tanta frecuencia, este fue un compromiso aceptable para él. Dependiendo de su uso, esto puede o no ser aceptable.

4

Aquí hay una búsqueda recursiva (busca usuarios en grupos anidados) usando 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

uno de los principales motivos para subir la votación fue porque el rendimiento de AccountManagement es pobre. La única forma de obtener realmente el rendimiento de la búsqueda de AD es pasar a DirectoryServices lib. Clunky api pero realmente rápido –

1

probar este no está seguro de si sería más rápido, pero ....

 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

Al igual que en su primera opción, he creado un hashset de la lista. Cuanto más grande sea el grupo, más tiempo se tarda en verificar la membresía. Sin embargo, es consistente para consultas de membresía exitosas y sin éxito. Para iterar a través de un grupo grande en algún momento tomaría 3 veces más si la cuenta no era miembro, mientras que este método es el mismo siempre.

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; 
} 
Cuestiones relacionadas