Comment puis-je obtenir une liste d'utilisateurs depuis Active Directory?

109

Comment puis-je obtenir une liste d'utilisateurs depuis Active Directory? Existe-t-il un moyen d'extraire le nom d'utilisateur, le prénom, le nom? J'ai vu un article similaire où cela a été utilisé:

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

Je n'ai jamais rien fait avec Active Directory donc je suis complètement perdu. Toute aide serait grandement appréciée!

Mike
la source
3
Lisez l'excellent article MSDN Managing Directory Security Principals dans .NET Framework 3.5 pour une excellente introduction à l'utilisation d'AD avec .NET 3.5
marc_s
On dirait que l'article de @ marc_s a été archivé, voici un lien mis à jour
jb.
@marc_s J'adorerais lire monsieur, mais le lien est mort. J'ai essayé ce blogs.msdn.microsoft.com/msdnmagazine/2008/01/16/... mais même les liens sur cet article mènent à une page génétique pour le magazine Microsoft
Malcolm Salvador
1
@ Malky.Kid J'ai trouvé mon chemin vers l'article. Utilisez le lien du premier commentaire de cette question et téléchargez le numéro de janvier 2008 . N'oubliez pas de débloquer le fichier chm dans la page des propriétés de l'explorateur avant de le lire.
OneWorld

Réponses:

229

Si vous êtes nouveau dans Active Directory, je vous suggère de comprendre d'abord comment Active Directory stocke les données.

Active Directory est en fait un serveur LDAP. Les objets stockés sur le serveur LDAP sont stockés de manière hiérarchique. C'est très similaire au stockage de vos fichiers dans votre système de fichiers. C'est pourquoi il a le nom de serveur d' annuaire et Active Directory

Les conteneurs et objets sur Active Directory peuvent être spécifiés par un distinguished name. Le nom distinctif est comme ça CN=SomeName,CN=SomeDirectory,DC=yourdomain,DC=com. Comme une base de données relationnelle traditionnelle, vous pouvez exécuter une requête sur un serveur LDAP. C'est ce qu'on appelle la requête LDAP.

Il existe plusieurs façons d'exécuter une requête LDAP dans .NET. Vous pouvez utiliser DirectorySearcher à partir de System.DirectoryServicesou SearchRequest à partir de System.DirectoryServices.Protocol.

Pour votre question, puisque vous demandez de trouver spécifiquement l'objet principal de l'utilisateur, je pense que le moyen le plus intuitif est d'utiliser PrincipalSearcher à partir de System.DirectoryServices.AccountManagement. Vous pouvez facilement trouver de nombreux exemples différents sur Google. Voici un exemple qui fait exactement ce que vous demandez.

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

Notez que sur l'objet utilisateur AD, il existe un certain nombre d'attributs. En particulier, givenNamevous donnera le First Nameet snvous donnera le Last Name. À propos du nom d'utilisateur. Je pense que vous vouliez dire le nom de connexion de l'utilisateur. Notez qu'il existe deux noms de connexion sur l'objet utilisateur AD. Le premier est samAccountName, également connu sous le nom de nom de connexion utilisateur antérieur à Windows 2000. userPrincipalNameest généralement utilisé après Windows 2000.

Harvey Kwok
la source
2
Que faire si le serveur ne contient pas de domaine
Comment utilisez-vous le même code pour répertorier les utilisateurs d'un groupe AD?
nJoshi
Existe-t-il un moyen d'utiliser cette méthode pour restreindre la recherche à ceux de l'annuaire auxquels une adresse e-mail a été attribuée?
ARidder101
Qu'à cela ne tienne, je l'ai compris. Je devais juste ajouter if (((UserPrincipal)result).EmailAddress != null)avant d'ajouter le résultat à ma liste.
ARidder101
2
Et si l'ordinateur actuel n'appartient pas au domaine?
Marcus
23

Si vous souhaitez filtrer vos comptes actifs, ajoutez ceci au code de Harvey:

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

après la première utilisation. Puis ajouter

  searcher.QueryFilter = userPrin;

avant de tout trouver. Et cela devrait vous amener les plus actifs.

Apereira
la source
Je ne pense pas que vous en ayez besoin searcher.QueryFilter = userPrin;car nous transmettons déjà le principal de l'utilisateur au chercheur principal lors de l'initialisation, mais sinon merci pour le conseil sur le filtrage des utilisateurs actifs uniquement!
Andrey du
1
Ouais, Andrey a raison Donc, fondamentalement, cela pourrait être remplacé par l'ajout de cette propriété dans la deuxième instruction d'utilisation:using (var searcher = new PrincipalSearcher(new UserPrincipal(context){ Enabled = true }))
Marko Jovanov
Mais je pensais que vous deviez d'abord tester si vous Enabledaviez une valeur:if (userPrincipal.Enabled.HasValue)
JohnB
4

Le mérite revient certainement à @Harvey Kwok ici, mais je voulais juste ajouter cet exemple car dans mon cas, je voulais obtenir une véritable liste des utilisateurs principaux. Il est probablement plus efficace de filtrer cette requête à l'avance, mais dans mon petit environnement, il est simplement plus facile de tout extraire, puis de filtrer au besoin plus tard dans ma liste.

Selon ce dont vous avez besoin, vous n'aurez peut-être pas besoin de convertir en DirectoryEntry, mais certaines propriétés ne sont pas disponibles à partir de 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());
        }
}
Jordan
la source
Qu'est-ce que «e» s'il vous plaît?
Fandango68
1
Merci, je n'ai jamais remarqué ça. Je l'ai changé, c'était censé être "u". J'ai également ajouté des? S pour gérer les valeurs nulles si la propriété est manquante.
Jordanie
1

Incluez le System.DirectoryServices.dll, puis utilisez le code ci-dessous:

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
la source
1
@ Fandango68: LOL, oui ça l'est !!! System.Windows.Forms.MessageBox.Show (ex.Message + ex.StackTrace);
Jhollman