¿Cómo puedo obtener una lista de usuarios del directorio activo?

109

¿Cómo puedo obtener una lista de usuarios del directorio activo? ¿Hay alguna forma de extraer nombre de usuario, nombre, apellido? Vi una publicación similar donde se usó esto:

 PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN");

Nunca he hecho nada con el directorio activo, así que estoy completamente perdido. ¡Cualquier ayuda será muy apreciada!

Miguel
fuente
3
Lea el excelente artículo de MSDN Administración de los principales de seguridad de directorios en .NET Framework 3.5 para obtener una excelente introducción al uso de AD con .NET 3.5
marc_s
Parece que el artículo de @ marc_s se archivó, aquí hay un enlace actualizado
jb.
@marc_s Me encantaría leer señor, pero el enlace está muerto. Probé este blogs.msdn.microsoft.com/msdnmagazine/2008/01/16/… pero incluso los enlaces de ese artículo llevan a una página genética para la revista microsoft
Malcolm Salvador
1
@ Malky.Kid Encontré mi camino hacia el artículo. Utilice el enlace del primer comentario a esta pregunta y descargue la edición de enero de 2008 . No olvide desbloquear el archivo chm en la página de propiedades del Explorador antes de leer.
OneWorld

Respuestas:

229

Si es nuevo en Active Directory, le sugiero que primero comprenda cómo Active Directory almacena los datos.

Active Directory es en realidad un servidor LDAP. Los objetos almacenados en el servidor LDAP se almacenan jerárquicamente. Es muy similar a almacenar sus archivos en su sistema de archivos. Es por eso que obtuvo el nombre de servidor de directorio y Active Directory

Los contenedores y objetos de Active Directory se pueden especificar mediante un distinguished name. El nombre distinguido es así CN=SomeName,CN=SomeDirectory,DC=yourdomain,DC=com. Como una base de datos relacional tradicional, puede ejecutar consultas en un servidor LDAP. Se llama consulta LDAP.

Hay varias formas de ejecutar una consulta LDAP en .NET. Puede utilizar DirectorySearcher desde System.DirectoryServiceso SearchRequest desde System.DirectoryServices.Protocol.

Para su pregunta, dado que está pidiendo encontrar el objeto principal del usuario específicamente, creo que la forma más intuitiva es usar PrincipalSearcher de System.DirectoryServices.AccountManagement. Puede encontrar fácilmente muchos ejemplos diferentes en Google. Aquí hay una muestra que hace exactamente lo que está pidiendo.

using (var context = new PrincipalContext(ContextType.Domain, "yourdomain.com"))
{
    using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
    {
        foreach (var result in searcher.FindAll())
        {
            DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
            Console.WriteLine("First Name: " + de.Properties["givenName"].Value);
            Console.WriteLine("Last Name : " + de.Properties["sn"].Value);
            Console.WriteLine("SAM account name   : " + de.Properties["samAccountName"].Value);
            Console.WriteLine("User principal name: " + de.Properties["userPrincipalName"].Value);
            Console.WriteLine();
        }
    }
}
Console.ReadLine();

Tenga en cuenta que en el objeto de usuario de AD, hay varios atributos. En particular, givenNamele dará el First Namey snle dará el Last Name. Sobre el nombre de usuario. Creo que te refieres al nombre de inicio de sesión del usuario. Tenga en cuenta que hay dos nombres de inicio de sesión en el objeto de usuario de AD. Uno es samAccountName, que también se conoce como nombre de inicio de sesión de usuario anterior a Windows 2000. userPrincipalNamese utiliza generalmente después de Windows 2000.

Harvey Kwok
fuente
2
¿Qué pasa si el servidor no contiene el dominio
¿Cómo se usa el mismo código para enumerar usuarios de un grupo de AD?
nJoshi
¿Existe alguna forma de utilizar este método para limitar la búsqueda solo a aquellos en el directorio a los que se les ha asignado una dirección de correo electrónico?
ARidder101
No importa, lo descubrí. Solo tenía que agregar if (((UserPrincipal)result).EmailAddress != null)antes de agregar el resultado a mi lista.
ARidder101
2
¿Y si la computadora actual no pertenece al dominio?
Marcus
23

Si desea filtrar y cuentas activas agregue esto al código de Harvey:

 UserPrincipal userPrin = new UserPrincipal(context);
 userPrin.Enabled = true;

después del primer uso. Luego añade

  searcher.QueryFilter = userPrin;

antes de encontrar todo. Y eso debería darte los activos.

apereira
fuente
No creo que lo necesite searcher.QueryFilter = userPrin;, ya que ya pasamos el principal del usuario al buscador principal en la inicialización, pero de lo contrario, ¡gracias por el consejo sobre el filtrado de usuarios activos solamente!
Andrey
1
Sí, Andrey tiene razón. Básicamente, esto podría reemplazarse agregando esta propiedad en la segunda declaración de uso:using (var searcher = new PrincipalSearcher(new UserPrincipal(context){ Enabled = true }))
Marko Jovanov
Pero pensé que Enabledprimero tenías que probar si tenía un valor:if (userPrincipal.Enabled.HasValue)
JohnB
4

Ciertamente, el crédito es para @Harvey Kwok aquí, pero solo quería agregar este ejemplo porque en mi caso quería obtener una lista real de UserPrincipals. Probablemente sea más eficiente filtrar esta consulta por adelantado, pero en mi pequeño entorno, es más fácil extraer todo y luego filtrar según sea necesario de mi lista.

Dependiendo de lo que necesite, es posible que no necesite convertir a DirectoryEntry, pero algunas propiedades no están disponibles en UserPrincipal.

using (var searcher = new PrincipalSearcher(new UserPrincipal(new PrincipalContext(ContextType.Domain, Environment.UserDomainName))))
{
    List<UserPrincipal> users = searcher.FindAll().Select(u => (UserPrincipal)u).ToList();
    foreach(var u in users)
        {
            DirectoryEntry d = (DirectoryEntry)u.GetUnderlyingObject();
            Console.WriteLine(d.Properties["GivenName"]?.Value?.ToString() + d.Properties["sn"]?.Value?.ToString());
        }
}
Jordán
fuente
¿Qué es 'e' por favor?
Fandango68
1
Gracias, nunca me di cuenta de eso. Lo cambié, se suponía que era "u". También agregué? S para manejar valores nulos si falta la propiedad.
Jordania
1

Incluya System.DirectoryServices.dll, luego use el siguiente código:

DirectoryEntry directoryEntry = new DirectoryEntry("WinNT://" + Environment.MachineName);
string userNames="Users: ";

foreach (DirectoryEntry child in directoryEntry.Children)
{
    if (child.SchemaClassName == "User")
    {
        userNames += child.Name + Environment.NewLine   ;         
    }

}
MessageBox.Show(userNames);
FreeAsInBeer
fuente
1
@ Fandango68: LOL, si lo es !!! System.Windows.Forms.MessageBox.Show (por ejemplo, Mensaje + por ejemplo, StackTrace);
Jhollman