Иван Коробко
PowerShell. Поиск объектов в каталоге Active Directory
Получение информации из каталога Active Directory в девяти случаях из десяти сводится к поиску объектов, которые удовлетворяют заданным критериям.
В каталоге Active Directory объекты хранятся в иерархической структуре, поэтому для получения доступа к нужному объекту необходимо указать к нему путь в формате RDN. Обычно местоположение объекта неизвестно или оно может измениться, поэтому программный способ поиска объекта/объектов по заданным условиям – самое эффективное средство для определения его местонахождения.
Иерархическая структура каталога Active Directory
Иерархическая структура каталога Active Directory обычно формируется с помощью специфических объектов – контейнеров (Organizational Unit), которые имеют префикс «OU=». Контейнеры, образующие домен, имеют префикс DC (Domain Component). Большинство других объектов кроме корня домена имеют префикс «CN=» (Common Name).
Однако и здесь существует исключение: служебные контейнеры также имеют префикс «CN=».
Тип объекта определяется набором элементов массива objectClass. Поиск объектов осуществляется по заданным критериям. Чаще всего одним из заданных критериев является тип объекта.
В таблице 1 приведены типы объектов и соответствующие им значения элементов массива objectClass. При составлении запроса необходимо учитывать пересечения элементов массива.
Ярким примером является запрос поиска всех учетных записей компьютеров и пользователей. Оба класса относятся к классу person, однако учетные записи компьютеров дополнительно входят в класс Computer (см. таблицу 1), именно поэтому для выборки всех учетных записей необходимо в фильтре это учесть: (&(objectClass=user)(!objectClass=Computer)).
Таблица 1. Типы объекта в Active Directory
Комментарий
|
Тип объекта
|
Значение objectClass
|
Фрагмент поискового запроса
|
Учетная запись компьютера
|
Computer
|
Top
Person
OrganizationalPerson
User
Computer
|
(&(objectClass=Computer)
|
Контакт, используется в почтовых приложениях
|
Contact
|
Top
Person
OrganizationalPerson
Contact
|
(&(objectClass=Contact)
|
Группа безопасности
|
Group
|
Top
Group
|
(&(objectClass=Group)
|
Учетная запись пользователя, не совместимая с доменами Windows 2K
|
InetOrgPerson
|
Top
Person
OrganizationalPerson
User
InetOrgPerson
|
(&(objectClass=InetOrgPerson)
|
Папка дерева каталогов Active Directory
|
OU
|
Top
OrganizationalUnit
|
(&(objectClass=OrganizationalUnit)
|
Опубликованный в Active Directory сетевой принтер
|
Printer
|
Top
Leaf
ConnectionPoint
PrintQueue
|
(&(objectClass=PrintQueue)
|
Опубликованная в Active Directory сетевая папка
|
Shared Folder
|
Top
Leaf
ConnectionPoint
Volume
|
(&(objectClass=Volume)
|
Учетная запись пользователя, совместимая с доменами Windows NT
|
User
|
Top
Person
OrganizationalPerson
User
|
(&(objectClass=Person)(!(objectClass =Computer)))
|
Контейнер (папка), создаваемая в каталоге Active Directory по умолчанию
|
Container
|
Top
Container
|
(&(objectClass=Container))
|
Корень домена
|
RootDSE
|
Top
Domain
DomainDNS
|
(&(objectClass=DomainDNS)
|
Поиск объектов в Active Directory при помощи библиотек .NET Framework осуществляется с помощью класса DirectorySearcher, относящегося к пространству имён System.Directory Services.
Процедура поиска имеет несколько характеристик, основные из которых:
- Область поиска. Область, или глубина, поиска определяется с помощью свойства SearchScope.
- Критерии поиска. Задаются с помощью свойства filter.
- Сортировка элементов. С помощью метода sort и его свойств задают поле и направление сортировки.
Область поиска
Поиск объекта может быть осуществлен в одной из трех областей:
- Base (obj.SearchScope=0) – поиск осуществляется по корневому объекту, указанному в первой части запроса. Всегда возвращается либо один объект, либо пустой набор объектов. Эта область поиска используется чаще всего для проверки на существование объекта, указанного в запросе.
- OneLevel (obj.SearchScope=1) – поиск осуществляется только по непосредственным дочерним объектам контейнерного объекта, указанного в первой части запроса. Поиск по вложенным объектам более низких уровней не производится. В поиск не попадет и сам контейнерный объект.
- SubTree (obj.SearchScope=2) – поиск осуществляется по всем вложенным объектам. В поиск при этом не попадает сам контейнерный объект. Эта область поиска задана по умолчанию.
Критерии поиска
При составлении критерия, или, как его еще называют, фильтра поиска, используют выражения, строящиеся по определенным правилам, а именно (см. таблицу 2):
- каждое выражение должно быть заключено в скобки;
- в выражениях допускается использование операторов сравнения: «<», «<=», «=», «>=» и «>';
- допускаются составные выражения, образуемые с помощью префиксных операторов: «&», «|», «!»;
- между оператором и операндами пробелы не допускаются.
Таблица 2. Операторы фильтра поиска
Оператор
|
Значение
|
=
|
Эквивалентно
|
~=
|
Примерно равно
|
<=
|
Меньше или равно
|
>=
|
Больше или равно
|
>
|
Больше
|
<
|
Меньше
|
&
|
И
|
|
|
ИЛИ
|
!
|
НЕ
|
*
|
Любое количество любых символов
|
Приведу несколько характерных примеров фильтров:
- (name=А*). Результатом поиска являются все объекты, имена которых начинаются с буквы «А».
- &((objectClass=person)(!objectClass=computer)). Будут возвращены все объекты, принадлежащие к классу person и не принадлежащие к классу computer, то есть все учетные записи пользователей.
Встречаются случаи, в которых необходимо в качестве значений указывать служебные символы, например звездочку, скобку и др.
Чтобы реализовать эту возможность, нужный символ требуется заменить на соответствующее ему кодовое значение, приведенное в таблице 3.
Таблица 3. Служебные символы, используемые в фильтрах поиска
Символ
|
Значение
|
*
|
\2a
|
(
|
\28
|
)
|
\29
|
\
|
\5c
|
NUL
|
\00
|
/
|
\2f
|
Сортировка элементов
Сортировка элементов осуществляется с помощью метода sort, поддерживающего два свойства: PropertyName и Direction.
С помощью свойства PropertyName производится назначение поля, по которому будет осуществляться сортировка, а с помощью Direction – направление.
В случае Sort.Direction=0 осуществляется упорядочивание от «А» до «Я», при Sort.Direction=1 – в обратном порядке.
Пример поиска объектов в Active Directory
Приведу пример поиска всех учетных записей пользователя на букву «А». Дополнительно выполним сортировку выводимых данных от А к Я по полю name. Рассмотрим алгоритм работы сценария.
Сначала необходимо вызвать объект DirectorySearcher и указать точку монтирования к каталогу Active Directory. Затем укажем область поиска – весь каталог Active Directory: SearchScope = subtree.
Критерий поиска логически складывается из двух элементов: в первом выберем все учетные записи пользователей. Это можно сделать, указав фильтр (&(objectClass=user)(!(objectClass=Computer))).
Вторым критерием из всех найденных учетных записей отберем начинающиеся с буквы «А». Для этого используем фильтр (&(name=А*)). С помощью символа «*» обозначают произвольное содержимое. Объединив оба фильтра в один, получим: (&((objectClass=user)(name=А*))(!(objectClass=Computer))).
После определения всех необходимых атрибутов поиска необходимо запустить процесс поиска с помощью одной из функций: FindAll() или FindOne().Поскольку объектов заведомо больше одного, то в данном случае рекомендуется использовать FindAll().
Чтение элементов осуществляется с помощью цикла For...Next. Массив – коллекция SearchResults, возвращаемая функцией FindAll(), элемент коллекции – SearchResult.
Для чтения свойств найденных объектов необходимо получить доступ к его пространству имен с помощью метода DirectorySearcher и, наконец, с помощью параметризированного свойства (Parameterized property) Properties() получить требуемое значение.
В листинге 1 приведен рассмотренный пример на языке VB.NET, а в листинге 2 – на PowerShell.
Листинг 1. Поиск объектов по заданным критериям (VB.NET)
Dim obj As New DirectorySearcher("LDAP://RootDSE")
obj.SearchScope = SearchScope.Subtree
obj.Filter = "(&(objectClass=person)(name=a*)(!objectClass=computer))"
obj.Sort.PropertyName = "cn"
obj.Sort.Direction = SortDirection.Ascending
For Each element As SearchResult In obj.FindAll()
Dim obj2 As DirectoryEntry = element.GetDirectoryEntry()
msgbox obj2.Properties("cn").Value)
Next
В листинге 2 код отличается. Значительные изменения в сторону упрощения претерпевает вывод значений элементов полученного массива. В отличие от классического For.... Next, в PowerShell можно использовать инструкцию foreach-object или короткий псевдним % (знак процента). В этом случае доступ к элементам массива осуществляется с помощью специальной переменной «$_».
Листинг 2. Поиск объектов по заданным критериям (PowerShell)
$obj = new-object DirectoryServices.DirectorySearcher("LDAP://RootDSE")
$obj.SearchScope = "Subtree"
$obj.Filter = "(&(objectClass=person)(name=a*)(!objectClass=computer))"
$obj.Sort.PropertyName = "cn"
$obj.Sort.Direction = "Ascending"
$obj.FindAll() | %{
$obj2=$_.GetDirectoryEntry()
$obj2.cn
Заключение
Подводя итог написанному, необходимо сказать, что поиск объектов – очень мощное средство. Грамотно составленный запрос, верно определенные области поиска и сортировка позволят с легкостью формировать сложнейшие отчеты, на составление которых могло бы уйти гораздо больше времени.