Como posso obter uma lista de usuários do Active Directory?

109

Como posso obter uma lista de usuários do Active Directory? Existe uma maneira de obter nome de usuário, nome, sobrenome? Eu vi uma postagem semelhante em que isso foi usado:

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

Eu nunca fiz nada com o Active Directory, então estou completamente perdido. Qualquer ajuda seria muito apreciada!

Mike
fonte
3
Leia o excelente artigo do MSDN Gerenciando Princípios de Segurança de Diretório no .NET Framework 3.5 para uma ótima introdução ao uso do AD com .NET 3.5
marc_s
Parece que o artigo de @marc_s foi arquivado, aqui está um link atualizado
jb.
@marc_s Eu adoraria ler, senhor, mas o link está morto. Eu tentei este blogs.msdn.microsoft.com/msdnmagazine/2008/01/16/… mas mesmo os links nesse artigo levam a uma página genética para a revista microsoft
Malcolm Salvador
1
@ Malky.Kid Encontrei o caminho para o artigo. Use o link do primeiro comentário para esta pergunta e baixe a edição de janeiro de 2008 . Não se esqueça de desbloquear o arquivo chm na página de propriedades do Explorer antes de ler.
OneWorld

Respostas:

229

Se você é novo no Active Directory, sugiro que entenda como o Active Directory armazena dados primeiro.

O Active Directory é na verdade um servidor LDAP. Os objetos armazenados no servidor LDAP são armazenados hierarquicamente. É muito semelhante a você armazenar seus arquivos em seu sistema de arquivos. É por isso que recebeu o nome Directory server e Active Directory

Os recipientes e objetos no Active Directory podem ser especificados por a distinguished name. O nome distinto é assim CN=SomeName,CN=SomeDirectory,DC=yourdomain,DC=com. Como um banco de dados relacional tradicional, você pode executar uma consulta em um servidor LDAP. É chamado de consulta LDAP.

Existem várias maneiras de executar uma consulta LDAP no .NET. Você pode usar DirectorySearcher de System.DirectoryServicesou SearchRequest de System.DirectoryServices.Protocol.

Para sua pergunta, já que você está pedindo para localizar o objeto principal do usuário especificamente, acho que a maneira mais intuitiva é usar PrincipalSearcher de System.DirectoryServices.AccountManagement. Você pode encontrar facilmente muitos exemplos diferentes no google. Aqui está um exemplo que está fazendo exatamente o que você está pedindo.

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

Observe que, no objeto de usuário AD, há vários atributos. Em particular, givenNamedará a você o First Namee sno Last Name. Sobre o nome de usuário. Acho que você quis dizer o nome de logon do usuário. Observe que há dois nomes de logon no objeto de usuário AD. Um deles é samAccountName, também conhecido como nome de logon do usuário anterior ao Windows 2000. userPrincipalNameé geralmente usado após o Windows 2000.

Harvey Kwok
fonte
2
E se o servidor não contiver Domínio
Como você usa o mesmo código para listar usuários de um grupo AD?
nJoshi de
Existe uma maneira de usar esse método para restringir a pesquisa apenas àqueles no diretório que receberam um endereço de e-mail?
ARidder101
Não importa, eu descobri. Eu só tive que adicionar if (((UserPrincipal)result).EmailAddress != null)antes de adicionar o resultado à minha lista.
ARidder101
2
E se o computador atual não pertencer ao domínio?
Marcus
23

Se você deseja filtrar as contas ativas, adicione ao código de Harvey:

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

após o primeiro uso. Então adicione

  searcher.QueryFilter = userPrin;

antes de encontrar tudo. E isso deve te dar os mais ativos.

apereira
fonte
Não acho que você precise searcher.QueryFilter = userPrin;, pois já passamos o usuário principal para o pesquisador principal na inicialização, mas, caso contrário, obrigado pela dica sobre a filtragem de usuários ativos apenas!
Andrey
1
Sim, Andrey está certo. Basicamente, isso poderia ser substituído com a adição dessa propriedade no segundo usando a declaração:using (var searcher = new PrincipalSearcher(new UserPrincipal(context){ Enabled = true }))
Marko Jovanov,
Mas pensei que você teria que testar se Enabledtinha um valor primeiro:if (userPrincipal.Enabled.HasValue)
JohnB
4

Certamente o crédito vai para @Harvey Kwok aqui, mas eu só queria adicionar este exemplo porque, no meu caso, eu queria obter uma Lista real de Princípios do Usuário. Provavelmente é mais eficiente filtrar essa consulta antecipadamente, mas em meu ambiente pequeno, é mais fácil extrair tudo e filtrar conforme necessário mais tarde da minha lista.

Dependendo do que você precisa, pode não ser necessário transmitir para DirectoryEntry, mas algumas propriedades não estão disponíveis em 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ânia
fonte
O que é 'e', ​​por favor?
Fandango68
1
Obrigado, nunca percebi isso. Eu mudei, era para ser "u". Eu também adicionei? S para lidar com valores nulos se a propriedade estiver ausente.
Jordânia,
1

Inclua System.DirectoryServices.dll e, em seguida, use o código abaixo:

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
fonte
1
@ Fandango68: LOL, é sim !!! System.Windows.Forms.MessageBox.Show (ex.Message + ex.StackTrace);
Jhollman