2012-03-07 24 views
7

Ho una soluzione funzionante, tuttavia sono abbastanza sicuro che esiste un metodo meno dispendioso in termini di risorse perché la soluzione corrente prevede l'esecuzione di una query per ottenere il membro dei gruppi e quindi una query per ottenere informazioni su ciascun utente.Ottieni utenti "membri" di un gruppo

Ecco il codice che ho:

DirectoryEntry root = new DirectoryEntry("LDAP://server:port"); 
DirectorySearcher searcher = new DirectorySearcher(root); 
searcher.Filter = "(&(ObjectClass=Group)(CN=foo-group))"; 

var members = (IEnumerable)searcher.FindOne() 
       .GetDirectoryEntry() 
       .Invoke("members"); 

Dictionary<string , string> results = new Dictionary<string , string>(); 

foreach(object member in members) { 
    DirectoryEntry de = new DirectoryEntry(member); 
    results.Add(de.Properties[ "SAMAccountname" ][ 0 ].ToString(), de.Properties[ "cn" ][ 0 ].ToString()); 
} 

Idealmente mi piacerebbe essere in grado di fare una singola query per ottenere tutti gli utenti che sono membro di un gruppo, filtra le proprietà per caricare e poi visualizzazione loro. Quindi qualcosa del genere

DirectoryEntry root = new DirectoryEntry("LDAP://server:port"); 
DirectorySearcher searcher = new DirectorySearcher(root); 
searcher.PropertiesToLoad.Add("cn"); 
searcher.PropertiesToLoad.Add("SAMAccountname"); 
searcher.Filter = "(&(ObjectClass=user)(memberof=foo-group))"; 

foreach(var user in searcher.FindAll()) { 
    //do whatever... 
} 

Sfortunatamente, questo non funziona per qualche motivo.

Grazie per il vostro aiuto,

risposta

9

Se è possibile utilizzare System.DirectoryServices.AccountManagement:

var context = new PrincipalContext(ContextType.Domain, "YOUR_DOMAIN_NAME"); 
using (var searcher = new PrincipalSearcher()) 
{ 
    var groupName = "YourGroup"; 
    var sp = new GroupPrincipal(context, groupName); 
    searcher.QueryFilter = sp; 
    var group = searcher.FindOne() as GroupPrincipal; 

    if (group == null) 
     Console.WriteLine("Invalid Group Name: {0}", groupName); 

    foreach (var f in group.GetMembers()) 
    { 
     var principal = f as UserPrincipal; 

     if (principal == null || string.IsNullOrEmpty(principal.Name)) 
      continue; 

     Console.WriteLine("{0}", principal.Name); 
    } 
} 

ho qualche codice VB che' Lo farò anche alla vecchia maniera, ma questo è sicuramente più semplice con AccountManagement.


Ecco il codice VB mi riferivo (ancora una volta non è abbastanza, ma è funzionale):

Public Function GetUsersByGroup(de As DirectoryEntry, groupName As String) As IEnumerable(Of DirectoryEntry) 
    Dim userList As New List(Of DirectoryEntry) 
    Dim group As DirectoryEntry = GetGroup(de, groupName) 

    If group Is Nothing Then Return Nothing 

    For Each user In GetUsers(de) 
     If IsUserInGroup(user, group) Then 
      userList.Add(user) 
     End If 
    Next 

    Return userList 
End Function 

Public Function GetGroup(de As DirectoryEntry, groupName As String) As DirectoryEntry 
    Dim deSearch As New DirectorySearcher(de) 

    deSearch.Filter = "(&(objectClass=group)(SAMAccountName=" & groupName & "))" 

    Dim result As SearchResult = deSearch.FindOne() 

    If result Is Nothing Then 
     Return Nothing 
    End If 

    Return result.GetDirectoryEntry() 
End Function 

Public Function GetUsers(de As DirectoryEntry) As IEnumerable(Of DirectoryEntry) 
    Dim deSearch As New DirectorySearcher(de) 
    Dim userList As New List(Of DirectoryEntry) 

    deSearch.Filter = "(&(objectClass=person))" 

    For Each user In deSearch.FindAll() 
     userList.Add(user.GetDirectoryEntry()) 
    Next 

    Return userList 
End Function 

Public Function IsUserInGroup(user As DirectoryEntry, group As DirectoryEntry) As Boolean 
    Dim memberValues = user.Properties("memberOf") 

    If memberValues Is Nothing OrElse memberValues.Count = 0 Then Return False 

    For Each g In memberValues.Value 
     If g = group.Properties("distinguishedName").Value.ToString() Then 
      Return True 
     End If 
    Next 

    Return False 
End Function 

e di utilizzo:

Dim entries = New DirectoryEntry("LDAP://...") 
Dim userList As IEnumerable(Of DirectoryEntry) = GetUsersByGroup(entries, "GroupName") 
+0

Questo sta funzionando bene, grazie. Tuttavia qual è la differenza tra questo e l'altro metodo. C'è un modo per specificare il server su cui sta eseguendo la ricerca. Voglio assicurarmi che non ci siano discrepanze con altri dati che sto visualizzando. –

+0

Non sono sicuro al 100% di cosa stia facendo sotto le copertine ma li ho mixati prima senza problemi o discrepanze. –

+0

Hai un'idea di come associare il dominio al server LDAP appropriato? –

2

Se si controlla HERE è possibile effettuare le seguenti operazioni:

DirectoryEntry group = new DirectoryEntry("LDAP://CN=foo-group,DC=Cmp,DC=COM"); 
foreach(object dn in group.Properties["member"]) 
    //do whatever 
+1

che non funziona per me perché non ho il percorso completo, ho solo il CN –

2
using System.DirectoryServices; 

DirectoryEntry objEntry = DirectoryEntry(Ldapserver, userid, password); 
DirectorySearcher personSearcher = new DirectorySearcher(objEntry); 
personSearcher.Filter = string.Format("(SAMAccountName={0}", username); 
SearchResult result = personSearcher.FindOne(); 

if(result != null) 
{ 
    DirectoryEntry personEntry = result.GetDirectoryEntry(); 
    PropertyValueCollection groups = personEntry.Properties["memberOf"]; 
    foreach(string g in groups) 
    { 
     Console.WriteLine(g); // will write group name 
    } 
} 

I originariamente utilizzato un metodo simile a quello che hai pubblicato e ci sono voluti circa 12 minuti per scorrere l'annuncio pubblicitario di tutta la mia azienda e ottenere i risultati. Dopo il passaggio a questo metodo, ci vogliono circa 2 minuti. Dovrai utilizzare l'indirizzo ldapserver dove ho scritto ldapserver e userid e password e username è SAMAccountName per la persona che stai cercando.

Problemi correlati