2010-12-16 29 views
27

He comprobado this publicación ya. Pero no responde mi pregunta. Quiero obtener todos los grupos de directorios activos en los que un usuario en particular es miembro.¿Cómo obtener todos los grupos de AD para un usuario en particular?

He escrito el siguiente código. Pero no puedo seguir adelante ya que no sé cómo dar el filtro y cómo acceder a las propiedades.

class Program 
{ 
    static void Main(string[] args) 
    { 
     DirectoryEntry de = new DirectoryEntry("LDAP://mydomain.com"); 
     DirectorySearcher searcher = new DirectorySearcher(de); 
     searcher.Filter = "(&(ObjectClass=group))"; 
     searcher.PropertiesToLoad.Add("distinguishedName"); 
     searcher.PropertiesToLoad.Add("sAMAccountName"); 
     searcher.PropertiesToLoad.Add("name"); 
     searcher.PropertiesToLoad.Add("objectSid"); 
     SearchResultCollection results = searcher.FindAll(); 
     int i = 1; 
     foreach (SearchResult res in results) 
     { 
      Console.WriteLine("Result" + Convert.ToString(i++)); 
      DisplayProperties("distinguishedName", res); 
      DisplayProperties("sAMAccouontName", res); 
      DisplayProperties("name", res); 
      DisplayProperties("objectSid", res); 
      Console.WriteLine(); 
     } 

     Console.ReadKey(); 
    } 

    private static void DisplayProperties(string property, SearchResult res) 
    { 
     Console.WriteLine("\t" + property); 
     ResultPropertyValueCollection col = res.Properties[property]; 
     foreach (object o in col) 
     { 
      Console.WriteLine("\t\t" + o.ToString()); 
     } 
    } 
} 

¿Alguna idea?

+0

Okie. Aprendí de aquí - http://www.eggheadcafe.com/software/aspnet/30375857/directory-searcher-not-returning-all-groups.aspx que memberOf no devolverá Grupos primarios de un usuario. Pero puedo obtener el PrimaryGroupID que proporciona el RID (?) Del grupo con el que necesito obtener el grupo AD. ¿Alguna idea de como hacerlo? – NLV

+0

Por favor, verifique mi respuesta recién publicada. Tu enfoque actual no funciona muy bien. Si el usuario está asignado a un grupo universal en otro bosque, el grupo universal no se mostrará en el atributo memberOf –

Respuesta

23

Sólo consultar la propiedad "memberOf" y repetir, aunque el retorno, ejemplo:

  search.PropertiesToLoad.Add("memberOf"); 
      StringBuilder groupNames = new StringBuilder(); //stuff them in | delimited 

       SearchResult result = search.FindOne(); 
       int propertyCount = result.Properties["memberOf"].Count; 
       String dn; 
       int equalsIndex, commaIndex; 

       for (int propertyCounter = 0; propertyCounter < propertyCount; 
        propertyCounter++) 
       { 
        dn = (String)result.Properties["memberOf"][propertyCounter]; 

        equalsIndex = dn.IndexOf("=", 1); 
        commaIndex = dn.IndexOf(",", 1); 
        if (-1 == equalsIndex) 
        { 
         return null; 
        } 
        groupNames.Append(dn.Substring((equalsIndex + 1), 
           (commaIndex - equalsIndex) - 1)); 
        groupNames.Append("|"); 
       } 

      return groupNames.ToString(); 

Esto sólo productos alimenticios los nombres de los grupos en la cadena groupNames, delimitados por tuberías, pero cuando te mueves puedes hacer lo que quieras con ellos

+0

Gracias funcionó muy bien. – NLV

+0

¡No hay problema, me alegro de que haya sido útil! – curtisk

+0

realmente muy, muy excelente respuesta :) –

18

Uso tokenGroups:

DirectorySearcher ds = new DirectorySearcher(); 
ds.Filter = String.Format("(&(objectClass=user)(sAMAccountName={0}))", username); 
SearchResult sr = ds.FindOne(); 

DirectoryEntry user = sr.GetDirectoryEntry(); 
user.RefreshCache(new string[] { "tokenGroups" }); 

for (int i = 0; i < user.Properties["tokenGroups"].Count; i++) { 
    SecurityIdentifier sid = new SecurityIdentifier((byte[]) user.Properties["tokenGroups"][i], 0); 
    NTAccount nt = (NTAccount)sid.Translate(typeof(NTAccount)); 
    //do something with the SID or name (nt.Value) 
} 

Nota: esto sólo se consigue grupos de seguridad

+2

Este código fue aproximadamente 10 veces más rápido que cualquiera de los otros códigos que he probado (utilizando PrincipalContext). Pasó de aproximadamente 4 segundos buscando todos los grupos para un usuario a 400 ms. Gracias. – Wolf5

+0

@ Wolf5 No entiendo esto, ¿se supone que debo agregar cada 'NTAcuenta' a una lista, para cada iteración? –

+0

Bueno, funciona usando una lista. ¡Un gran método, y de hecho muy rápido! –

1

El siguiente ejemplo es del artículo de código del proyecto, (Almost) Everything In Active Directory via C#:

// userDn is a Distinguished Name such as: 
// "LDAP://CN=Joe Smith,OU=Sales,OU=domain,OU=com" 
public ArrayList Groups(string userDn, bool recursive) 
{ 
    ArrayList groupMemberships = new ArrayList(); 
    return AttributeValuesMultiString("memberOf", userDn, 
     groupMemberships, recursive); 
} 

public ArrayList AttributeValuesMultiString(string attributeName, 
    string objectDn, ArrayList valuesCollection, bool recursive) 
{ 
    DirectoryEntry ent = new DirectoryEntry(objectDn); 
    PropertyValueCollection ValueCollection = ent.Properties[attributeName]; 
    IEnumerator en = ValueCollection.GetEnumerator(); 

    while (en.MoveNext()) 
    { 
     if (en.Current != null) 
     { 
      if (!valuesCollection.Contains(en.Current.ToString())) 
      { 
       valuesCollection.Add(en.Current.ToString()); 
       if (recursive) 
       { 
        AttributeValuesMultiString(attributeName, "LDAP://" + 
        en.Current.ToString(), valuesCollection, true); 
       } 
      } 
     } 
    } 
    ent.Close(); 
    ent.Dispose(); 
    return valuesCollection; 
} 

Sólo tiene que llamar la Grupos método con el Distinguished Name para el usuario, y pase el indicador booleano para indicar si desea incluir anidados grupos/niño de miembro en su ArrayList resultante:

ArrayList groups = Groups("LDAP://CN=Joe Smith,OU=Sales,OU=domain,OU=com", true); 
foreach (string groupName in groups) 
{ 
    Console.WriteLine(groupName); 
} 

Si necesita hacer cualquier nivel grave de la programación de Active Directory en .NET le recomiendo marcadores & r evisando el artículo de Code Project que mencioné anteriormente.

+1

Okie. He recursivo encontrado los grupos de padres. Pero aún dos grupos (o carpetas?) 'Usuarios de dominio' no están en la lista. Pero si reviso la pestaña 'memberOf' está allí. Los usuarios del dominio es un grupo integrado ¿no? ¿Me estoy perdiendo de algo? – NLV

32

Debe usar System.DirectoryServices.AccountManagement. Es mucho mas facil Aquí hay un buen código de proyecto article que le da una visión general de todas las clases en este archivo DLL.

Como ha señalado, su enfoque actual no encuentra el grupo primario. En realidad, es mucho peor de lo que creías. Hay algunos casos más que no funciona, como el grupo local de dominio de otro dominio. Puede marcar here para más detalles. Así es como se ve el código si cambia para usar System.DirectoryServices.AccountManagement. El siguiente código puede encontrar los grupos inmediatos asignados por este usuario, que incluye el grupo primario.

UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext (ContextType.Domain, "mydomain.com"), IdentityType.SamAccountName, "username"); 
foreach (GroupPrincipal group in user.GetGroups()) 
{ 
    Console.Out.WriteLine(group); 
} 
+0

No hay un método FindByIdentity para UserPrincipal ... –

+0

user.GetGroups() es muy lento. –

0
PrincipalContext pc1 = new PrincipalContext(ContextType.Domain, "DomainName", UserAccountOU, UserName, Password); 
UserPrincipal UserPrincipalID = UserPrincipal.FindByIdentity(pc1, IdentityType.SamAccountName, UserID); 

searcher.Filter = "(&(ObjectClass=group)(member = " + UserPrincipalID.DistinguishedName + ")); 
+2

Por favor, no publique solo las respuestas de solo código. Por favor, detalla qué está pasando en tu respuesta. – NathanOliver

0

Si usted tiene una conexión LDAP con un nombre de usuario y contraseña para conectarse a Active Directory, aquí está el código que utiliza para conectar correctamente:

using System.DirectoryServices.AccountManagement; 

// ... 

// Connection information 
var connectionString = "LDAP://domain.com/DC=domain,DC=com"; 
var connectionUsername = "your_ad_username"; 
var connectionPassword = "your_ad_password"; 

// Get groups for this user 
var username = "myusername"; 

// Split the LDAP Uri 
var uri = new Uri(connectionString); 
var host = uri.Host; 
var container = uri.Segments.Count() >=1 ? uri.Segments[1] : ""; 

// Create context to connect to AD 
var princContext = new PrincipalContext(ContextType.Domain, host, container, connectionUsername, connectionPassword); 

// Get User 
UserPrincipal user = UserPrincipal.FindByIdentity(princContext, IdentityType.SamAccountName, username); 

// Browse user's groups 
foreach (GroupPrincipal group in user.GetGroups()) 
{ 
    Console.Out.WriteLine(group.Name); 
} 
1

Este es el código que funcionó para mí:

public ArrayList GetBBGroups(WindowsIdentity identity) 
{ 
    ArrayList groups = new ArrayList(); 

    try 
    { 
     String userName = identity.Name; 
     int pos = userName.IndexOf(@"\"); 
     if (pos > 0) userName = userName.Substring(pos + 1); 

     PrincipalContext domain = new PrincipalContext(ContextType.Domain, "riomc.com"); 
     UserPrincipal user = UserPrincipal.FindByIdentity(domain, IdentityType.SamAccountName, userName); 

     DirectoryEntry de = new DirectoryEntry("LDAP://RIOMC.com"); 
     DirectorySearcher search = new DirectorySearcher(de); 
     search.Filter = "(&(objectClass=group)(member=" + user.DistinguishedName + "))"; 
     search.PropertiesToLoad.Add("samaccountname"); 
     search.PropertiesToLoad.Add("cn"); 

     String name; 
     SearchResultCollection results = search.FindAll(); 
     foreach (SearchResult result in results) 
     { 
      name = (String)result.Properties["samaccountname"][0]; 
      if (String.IsNullOrEmpty(name)) 
      { 
       name = (String)result.Properties["cn"][0]; 
      } 
      GetGroupsRecursive(groups, de, name); 
     } 
    } 
    catch 
    { 
     // return an empty list... 
    } 

    return groups; 
} 

public void GetGroupsRecursive(ArrayList groups, DirectoryEntry de, String dn) 
{ 
    DirectorySearcher search = new DirectorySearcher(de); 
    search.Filter = "(&(objectClass=group)(|(samaccountname=" + dn + ")(cn=" + dn + ")))"; 
    search.PropertiesToLoad.Add("memberof"); 

    String group, name; 
    SearchResult result = search.FindOne(); 
    if (result == null) return; 

    group = @"RIOMC\" + dn; 
    if (!groups.Contains(group)) 
    { 
     groups.Add(group); 
    } 
    if (result.Properties["memberof"].Count == 0) return; 
    int equalsIndex, commaIndex; 
    foreach (String dn1 in result.Properties["memberof"]) 
    { 
     equalsIndex = dn1.IndexOf("=", 1); 
     if (equalsIndex > 0) 
     { 
      commaIndex = dn1.IndexOf(",", equalsIndex + 1); 
      name = dn1.Substring(equalsIndex + 1, commaIndex - equalsIndex - 1); 
      GetGroupsRecursive(groups, de, name); 
     } 
    } 
} 

medí su rendimiento en un bucle de 200 carreras contra el código que utiliza el AttributeValuesMultiString método recursivo; y funcionó 1.3 veces más rápido. Podría ser así debido a nuestra configuración de AD. Ambos fragmentos dieron el mismo resultado sin embargo.

1

Este código funciona más rápido (dos 1.5 más rápido que mi versión anterior):

public List<String> GetUserGroups(WindowsIdentity identity) 
    { 
     List<String> groups = new List<String>(); 

     String userName = identity.Name; 
     int pos = userName.IndexOf(@"\"); 
     if (pos > 0) userName = userName.Substring(pos + 1); 

     PrincipalContext domain = new PrincipalContext(ContextType.Domain, "riomc.com"); 
     UserPrincipal user = UserPrincipal.FindByIdentity(domain, IdentityType.SamAccountName, userName); // NGeodakov 

     DirectoryEntry de = new DirectoryEntry("LDAP://RIOMC.com"); 
     DirectorySearcher search = new DirectorySearcher(de); 
     search.Filter = "(&(objectClass=group)(member=" + user.DistinguishedName + "))"; 
     search.PropertiesToLoad.Add("cn"); 
     search.PropertiesToLoad.Add("samaccountname"); 
     search.PropertiesToLoad.Add("memberOf"); 

     SearchResultCollection results = search.FindAll(); 
     foreach (SearchResult sr in results) 
     { 
      GetUserGroupsRecursive(groups, sr, de); 
     } 

     return groups; 
    } 

    public void GetUserGroupsRecursive(List<String> groups, SearchResult sr, DirectoryEntry de) 
    { 
     if (sr == null) return; 

     String group = (String)sr.Properties["cn"][0]; 
     if (String.IsNullOrEmpty(group)) 
     { 
      group = (String)sr.Properties["samaccountname"][0]; 
     } 
     if (!groups.Contains(group)) 
     { 
      groups.Add(group); 
     } 

     DirectorySearcher search; 
     SearchResult sr1; 
     String name; 
     int equalsIndex, commaIndex; 
     foreach (String dn in sr.Properties["memberof"]) 
     { 
      equalsIndex = dn.IndexOf("=", 1); 
      if (equalsIndex > 0) 
      { 
       commaIndex = dn.IndexOf(",", equalsIndex + 1); 
       name = dn.Substring(equalsIndex + 1, commaIndex - equalsIndex - 1); 

       search = new DirectorySearcher(de); 
       search.Filter = "(&(objectClass=group)(|(cn=" + name + ")(samaccountname=" + name + ")))"; 
       search.PropertiesToLoad.Add("cn"); 
       search.PropertiesToLoad.Add("samaccountname"); 
       search.PropertiesToLoad.Add("memberOf"); 
       sr1 = search.FindOne(); 
       GetUserGroupsRecursive(groups, sr1, de); 
      } 
     } 
    } 
Cuestiones relacionadas