Jak mogę uzyskać listę użytkowników z Active Directory?

109

Jak mogę uzyskać listę użytkowników z Active Directory? Czy istnieje sposób na pobranie nazwy użytkownika, imienia, nazwiska? Widziałem podobny post, w którym to zostało użyte:

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

Nigdy nie robiłem nic z Active Directory, więc jestem kompletnie zagubiony. Każda pomoc byłaby bardzo mile widziana!

Mikrofon
źródło
3
Przeczytaj doskonały artykuł MSDN Managing Directory Security Principals w .NET Framework 3.5, aby uzyskać świetne wprowadzenie do korzystania z usługi AD z .NET 3.5
marc_s
Wygląda na to, że artykuł @ marc_s został zarchiwizowany. Oto zaktualizowany link
jb.
@marc_s Chciałbym przeczytać proszę pana, ale link jest martwy. Wypróbowałem ten blogs.msdn.microsoft.com/msdnmagazine/2008/01/16/… ale nawet linki w tym artykule prowadzą do strony genetycznej magazynu Microsoft
Malcolm Salvador
1
@ Malky.Kid Znalazłem drogę do artykułu. Użyj łącza do pierwszego komentarza do tego pytania i pobierz numer ze stycznia 2008 roku . Nie zapomnij odblokować pliku chm na stronie właściwości Eksploratora przed przeczytaniem.
OneWorld

Odpowiedzi:

229

Jeśli dopiero zaczynasz korzystać z Active Directory, proponuję najpierw zrozumieć, w jaki sposób Active Directory przechowuje dane.

Active Directory jest w rzeczywistości serwerem LDAP. Obiekty przechowywane na serwerze LDAP są przechowywane hierarchicznie. Jest to bardzo podobne do przechowywania plików w systemie plików. Dlatego otrzymał nazwę Serwer katalogów i Active Directory

Kontenery i obiekty w usłudze Active Directory można określić za pomocą pliku distinguished name. Nazwa wyróżniająca jest taka CN=SomeName,CN=SomeDirectory,DC=yourdomain,DC=com. Podobnie jak tradycyjna relacyjna baza danych, możesz uruchamiać zapytania na serwerze LDAP. Nazywa się to zapytaniem LDAP.

Istnieje wiele sposobów uruchamiania kwerendy LDAP w środowisku .NET. Możesz użyć DirectorySearcher z System.DirectoryServiceslub SearchRequest z System.DirectoryServices.Protocol.

Jeśli chodzi o twoje pytanie, ponieważ chcesz znaleźć konkretny obiekt użytkownika głównego, myślę, że najbardziej intuicyjnym sposobem jest użycie PrincipalSearcher from System.DirectoryServices.AccountManagement. Możesz łatwo znaleźć wiele różnych przykładów z google. Oto próbka, która robi dokładnie to, o co prosisz.

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

Należy zauważyć, że obiekt użytkownika usługi AD ma wiele atrybutów. W szczególności givenNameda ci First Namei snda ci Last Name. O nazwie użytkownika. Myślę, że miałeś na myśli nazwę logowania użytkownika. Zauważ, że istnieją dwie nazwy logowania do obiektu użytkownika usługi AD. Jednym z samAccountNamenich jest nazwa logowania użytkownika w wersji starszej niż Windows 2000. userPrincipalNamejest zwykle używany po Windows 2000.

Harvey Kwok
źródło
2
Co jeśli serwer nie zawiera domeny
W jaki sposób używasz tego samego kodu do tworzenia listy użytkowników z grupy AD?
nJoshi
Czy za pomocą tej metody można zawęzić wyszukiwanie tylko do tych w katalogu, którym przypisano adres e-mail?
ARidder101
Nieważne, rozgryzłem to. Musiałem tylko dodać if (((UserPrincipal)result).EmailAddress != null)przed dodaniem wyniku do mojej listy.
ARidder101
2
A co, jeśli obecny komputer nie należy do domeny?
Marcus
23

Jeśli chcesz filtrować aktywne konta, dodaj to do kodu Harveya:

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

po pierwszym użyciu. Następnie dodaj

  searcher.QueryFilter = userPrin;

przed znalezieniem wszystkich. I to powinno dać ci aktywnych.

apereira
źródło
Myślę, że nie potrzebujesz, searcher.QueryFilter = userPrin;ponieważ już przekazujemy nazwę użytkownika do głównej wyszukiwarki podczas inicjalizacji, ale poza tym dziękujemy za wskazówkę dotyczącą filtrowania tylko aktywnych użytkowników!
Andrey
1
Tak, Andrey ma rację, więc w zasadzie można to zastąpić dodaniem tej właściwości w drugiej instrukcji using:using (var searcher = new PrincipalSearcher(new UserPrincipal(context){ Enabled = true }))
Marko Jovanov.
Ale pomyślałem, że musisz najpierw sprawdzić, czy masz Enabledwartość:if (userPrincipal.Enabled.HasValue)
JohnB
4

Z pewnością zasługa @Harvey Kwok tutaj, ale chciałem tylko dodać ten przykład, ponieważ w moim przypadku chciałem uzyskać aktualną listę UserPrincipals. Prawdopodobnie skuteczniejsze jest filtrowanie tego zapytania z góry, ale w moim małym środowisku po prostu łatwiej jest wyciągnąć wszystko, a następnie filtrować w razie potrzeby z mojej listy.

W zależności od potrzeb może nie być konieczne rzutowanie do DirectoryEntry, ale niektóre właściwości nie są dostępne w 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());
        }
}
Jordania
źródło
Co to jest „e”?
Fandango68
1
Dzięki, nigdy tego nie zauważyłem. Zmieniłem to, miało być „u”. Dodałem także? S, aby obsłużyć wartości null, jeśli brakuje właściwości.
Jordan
1

Dołącz plik System.DirectoryServices.dll, a następnie użyj poniższego kodu:

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
źródło
1
@ Fandango68: LOL, tak jest !!! System.Windows.Forms.MessageBox.Show (np. Message + ex.StackTrace);
Jhollman,