Как я могу получить список пользователей из активного каталога?

109

Как я могу получить список пользователей из активного каталога? Есть ли способ вытащить имя пользователя, имя, фамилию? Я видел похожий пост, где это использовалось:

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

Я никогда ничего не делал с активным каталогом, поэтому я полностью потерялся. Любая помощь будет принята с благодарностью!

Майк
источник
3
Прочтите отличную статью MSDN « Управление принципами безопасности каталогов в .NET Framework 3.5», чтобы получить отличное введение в использование AD с .NET 3.5
marc_s
Похоже, статья @ marc_s заархивирована, вот обновленная ссылка
jb.
@marc_s Я бы с удовольствием почитал, сэр, но ссылка мертвая. Я пробовал это blogs.msdn.microsoft.com/msdnmagazine/2008/01/16/… но даже ссылки в этой статье ведут на генетическую страницу журнала microsoft
Малкольм Сальвадор
1
@ Malky.Kid Я нашла путь к статье. Воспользуйтесь ссылкой на первый комментарий к этому вопросу и загрузите выпуск за январь 2008 года . Не забудьте перед чтением разблокировать chm-файл на странице свойств проводника.
OneWorld

Ответы:

229

Если вы новичок в Active Directory, я предлагаю вам сначала понять, как Active Directory хранит данные.

Active Directory на самом деле является сервером LDAP. Объекты, хранящиеся на сервере LDAP, хранятся иерархически. Это очень похоже на то, как вы храните файлы в файловой системе. Вот почему он получил имя каталога сервера и в Active Directory ,

Контейнеры и объекты в Active Directory могут быть указаны с помощью файла distinguished name. Вот такое выдающееся имя CN=SomeName,CN=SomeDirectory,DC=yourdomain,DC=com. Как и в случае с традиционной реляционной базой данных, вы можете выполнять запросы к серверу LDAP. Это называется запрос LDAP.

Есть несколько способов выполнить запрос LDAP в .NET. Вы можете использовать DirectorySearcher из System.DirectoryServicesили SearchRequest из System.DirectoryServices.Protocol.

Что касается вашего вопроса, поскольку вы просите конкретно найти объект пользователя-участника, я думаю, что наиболее интуитивно понятным способом является использование PrincipalSearcher из System.DirectoryServices.AccountManagement. Вы можете легко найти много разных примеров в Google. Вот образец, который делает именно то, что вы просите.

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

Обратите внимание, что у пользовательского объекта AD есть несколько атрибутов. В частности, givenNameдаст вам First Nameи snдаст вам Last Name. По поводу имени пользователя. Я думаю, вы имели в виду имя пользователя для входа в систему. Обратите внимание, что на объекте пользователя AD есть два имени для входа. Один из samAccountNameних также известен как имя пользователя для входа в систему до Windows 2000. userPrincipalNameобычно используется после Windows 2000.

Харви Квок
источник
2
Что делать, если сервер не содержит домена
Как использовать один и тот же код для вывода списка пользователей из группы AD?
nJoshi
Есть ли способ с помощью этого метода сузить поиск только до тех, кому был назначен адрес электронной почты в каталоге?
ARidder101
Ничего, я понял. Мне просто нужно было добавить, if (((UserPrincipal)result).EmailAddress != null)прежде чем добавить результат в свой список.
ARidder101,
2
А что если текущий компьютер не принадлежит домену?
Маркус
23

Если вы хотите отфильтровать y активных учетных записей, добавьте это в код Харви:

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

после первого использования. Затем добавьте

  searcher.QueryFilter = userPrin;

прежде чем найти все. И это должно привести вас к активным.

аперейра
источник
Я не думаю, что вам это нужно, searcher.QueryFilter = userPrin;поскольку мы уже передаем принципала пользователя основному искателю при инициализации, но в остальном спасибо за совет по фильтрации только активных пользователей!
Андрей
1
Да, Андрей прав. По сути, это можно заменить добавлением этого свойства во втором выражении using:using (var searcher = new PrincipalSearcher(new UserPrincipal(context){ Enabled = true }))
Марко Йованов
Но я подумал, что Enabledсначала нужно проверить, имеет ли значение значение:if (userPrincipal.Enabled.HasValue)
JohnB
4

Конечно, здесь заслуга @Harvey Kwok, но я просто хотел добавить этот пример, потому что в моем случае я хотел получить реальный список UserPrincipals. Вероятно, более эффективно отфильтровать этот запрос заранее, но в моей небольшой среде проще извлечь все, а затем фильтровать по мере необходимости позже из моего списка.

В зависимости от того, что вам нужно, может не потребоваться приведение к DirectoryEntry, но некоторые свойства недоступны в 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());
        }
}
Иордания
источник
Что такое "е", пожалуйста?
Fandango68
1
Спасибо, никогда этого не замечал. Я его поменял, должно было быть "u". Я также добавил? Для обработки нулевых значений, если свойство отсутствует.
Иордания
1

Включите System.DirectoryServices.dll, затем используйте приведенный ниже код:

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
источник
1
@ Fandango68: LOL, да, это так !!! System.Windows.Forms.MessageBox.Show (например, Message + ex.StackTrace);
Jhollman