Как читатели могут уже знать, Редактор сценариев и я лишь недавно стали полноправными сценаристами Майкрософт, и за последнее время немалая часть нашего труда ушла на разбор тысяч писем, приходящих на адрес электронной почты
scripter@microsoft.com. Не утруждая себя исследованиями, мы предположили бы, что наиболее часто встречающимся вопросом из тех, что мы получаем по электронной почте, является: «Где я могу достать обозреватель Active Directory?». Но знаете что? Мы никогда не видели его. Мы искали и искали, но не могли его найти.
Наконец, оставив ряд секретных сообщений на форуме в Интернете, мы получили закодированный ответ, который после расшифровки указал нам, что ADSI Scriptomatic является на самом деле обозревателем Active Directory. Ну, он не называется обозревателем Active Directory, и его назначение на деле состоит не в обзоре Active Directory (а в помощи при создании сценариев ADSI), так что я решил написать сценарий Windows PowerShell, который позволил бы выполнять обзор схемы Active Directory. Как ни странно, называется он BrowseActiveDirectorySchema.ps1, а показан он на рис. 1.
Рис. 1. BrowseActiveDirectorySchema.ps1
Param($action,$class, [switch]$help)
Function GetHelp()
{
$helpText= '
@"
DESCRIPTION:
NAME: BrowseActiveDirectorySchema.ps1
Browse Active Directory Schema. Lists Classes, and properties.
PARAMETERS:
-Action <L(ist all classes), M(andatory), O(ptional), F(ind)>
-Class class to search: user, computer, person, contact etc
-Help displays this help topic
SYNTAX:
BrowseActiveDirectorySchema.ps1 -A L
Lists the name of each class defined in the AD schema
BrowseActiveDirectorySchema.ps1 -A M -c user
Lists the mandatory properties of the user class
BrowseActiveDirectorySchema.ps1 -A O -c computer
Lists the optional properties of the computer class
BrowseActiveDirectorySchema.ps1 -A F -c user
Lists all Active Directory Classes that contain the word user
in the actual class name
BrowseActiveDirectorySchema.ps1 -Action Find -c user
Lists all Active Directory Classes that contain the word user
in the actual class name
BrowseActiveDirectorySchema.ps1 -help
Prints the help topic for the script
"@ #end helpText
$helpText
} #end GetHelp
Function GetADSchema($Action, $class)
{
$schema = [DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
Switch ($Action)
{
"classes" {
$schema.FindAllClasses() |
Select-Object -Property Name
}
"Mandatory"
{
"Mandatory Properties of $class object"
($schema.FindClass("$class")).MandatoryProperties |
Format-Table -Property Name, Syntax, IsSingleValued -AutoSize
}
"Optional"
{
"Optional Properties of $class object"
"This might take a few seconds ..."
($schema.FindClass("$class")).OptionalProperties |
Format-Table -Property Name, Syntax, IsSingleValued -AutoSize
}
"Find"
{
$schema.FindAllClasses() |
Where-Object { $_.name -match "$class" } |
Select-Object -property name
}
DEFAULT {"$action is not a valid action." ; GetHelp ; Exit}
}
} #end GetADSchema
Function GetAllClasses()
{
GetAdSchema("classes")
} #end GetAllClasses
Function GetMandatory($class)
{
GetAdSchema -action "Mandatory" -class $class
} #end GetMandatory
Function GetOptional($class)
{
GetAdSchema -action "Optional" -class $class
} #end GetOptional
Function FindClasses($class)
{
GetAdSchema -action "Find" -class $class
} #end FindClasses
# *** Entry Point to Script ***
if($help) { GetHelp ; Exit }
Switch ($action)
{
"L" {GetAllClasses ; Exit}
"M" {GetMandatory($class) ; Exit}
"O" {GetOptional($class) ; Exit}
"F" {FindClasses($class) ; Exit}
DEFAULT { "$action is not a valid action." ; GetHelp ; Exit}
}
Как можно заметить, сценарий начинается с оператора Param. Он используется для создания трех параметров командной строки, позволяющих изменить сценарий путем его выполнения вместо изменения сценария для того, чтобы получить иное поведение, что довольно полезно:
Param($action,$class, [switch]$help)
Если, например, нужно увидеть обязательные свойства класса user в службах доменов Active Directory (Active Directory Domain Services – AD DS), то указывается –action M и –class user, как показано на рис. 2.
Увеличить
Рис. 2 Просмотр обязательных свойств класса user
С той же легкостью можно было бы выбрать необязательные свойства класса group. Это преимущество использования параметров командной строки: возможность изменить поведение сценария во время выполнения вместо переписывания. Это наилучший вариант при написании сценариев, которые предполагается использовать как служебные программы (а не лишь однажды).
Выдача справки
В следующем разделе сценария на рис. 1 показана функция GetHelp. При написании сценария, предоставляющего параметры командной строки, рекомендуется включить функцию, которая будет отображать справку по использованию сценария. Нежелательно, чтобы пользователям сценария было необходимо открывать его и читать весь текст, чтобы понять, что он делает. Да, руководящий принцип разработки сценариев заключается в том, что сценарий должен быть читаемым, но включение функции справки может упростить жизнь пользователям.
Функция GetHelp отображает информацию во многом подобно командлету Get-Help. Отображаются три раздела текста: описание, параметры и синтаксис. GetHelp делает две вещи. Она создает внутреннюю строку с текстом для отображения и отображает содержимое переменной, содержащей внутреннюю строку (в данном случае $helpText).
Внутренняя строка (here-string) – это конструкция Windows PowerShell, позволяющая вводить информацию и форматировать выдаваемое, не волнуясь о правилах кавычек. Все, что вводится во внутреннюю строку, считается текстом. GetHelp вызывается, когда сценарий выполняется с ключом –help или если кто-то вводит неверный параметр. На рис. 3 показаны результаты вызова сценария с ключом –help.
Рис. 3. Вызов сценария с ключом –help
Скучные детали
Теперь мы подходим к функции GetADSchema – выполняющей основную часть реальной работы для сценария на рис. 1. Внутренний ключ (here key) использует класс Microsoft .NET Framework DirectoryServices.ActiveDirectory.ActiveDirectorySchema. Путем помещения этого класса в квадратные скобки, за которыми следуют двойные двоеточия, можно получить доступ к статическим методам класса (в данном случае GetSchema и GetCurrentSchema).
Статический метод GetCurrentSchema возвращает экземпляр класса ActiveDirectorySchema, представляющего схему, к которой сейчас подключен пользователь. На рис. 4 показаны члены класса ActiveDirectorySchema.
После создания экземпляра класса .NET Framework DirectoryServices.ActiveDirectory.ActiveSchema и сохранения получившегося объекта схемы в переменной $schema необходимо решить, какое действие выполнить. Чтобы сделать это, оператор Switch («Параметр») вычисляет значение, переданное ему из переменной $action.
Основываясь на выполненном условии, функция найдет все классы в AD DS, отобразит обязательные или необязательные свойства конкретного класса или произведет поиск класса, отвечающего данным критериям. При использовании Switch рекомендуется всегда включать условие по умолчанию.
Вспомогательные функции
Чтобы разбить часть кода и упростить расширение сценария, я включил ряд вспомогательных функций, вызываемых на основе параметров, передаваемых сценарию при его выполнении. Каждая из вспомогательных функций вызывает GetADSchema и передает различный набор параметров в зависимости от значения, предоставленного для параметра –action из командной строки.
Первая вспомогательная функция – GetAllClasses, вызывающая GetADSchema и передающая слово "classes". Когда оператор Switch в функции GetADSchema встречает строку "classes", он вызывает метод FindAllClasses из класса ActiveDirectorySchema. Вот код, вызываемый оператором Switch:
"classes" {
$schema.FindAllClasses() |
Select-Object -Property Name'
А вот функция GetAllClasses:
Function GetAllClasses()
{
GetADSchema("classes")
} #end GetAllClasses
Следующая вспомогательная функция – это GetMandatory, целью которой является возвращение обязательных свойств объекта, указанных в параметре –class, при выполнении сценария. Функция GetMandatory получает значение для $class из командной строки с помощью параметра –class. Когда функция GetMandatory вызывает функцию GetADSchema, она передает два параметра. Поскольку передаются два параметра, я могу порекомендовать указать полное имя параметра для обоих, что упрощает чтение и восприятие кода. Напротив, в функции GetAllClasses мы не использовали имя параметра –action при вызове функции GetADSchema. В этом случае значение "classes" было передано позиционным образом.
При вызове функции GetADSchema она использует метод FindClass из класса ActiveDirectorySchema, чтобы получить класс, указанный в переменной $class. Она возвращает экземпляр класса ActiveDirectorySchemaClass. Члены этого класса показаны на рис. 5.
Функция GetADSchema далее запрашивает свойство MandatoryProperties и передает по конвейеру результаты командлету Format-Table, который выбирает свойства Name, Syntax и IsSingleValued. Переключаемый параметр –Autosize командлета Format-Table автоматически определяет размер столбцов, чтобы по возможности избежать переносов в значениях свойств. Код, выполняемый при нахождении строки "Mandatory", показан ниже:
"Mandatory"
{
"Mandatory Properties of $class object"
($schema.FindClass("$class")).MandatoryProperties |
Format-Table -Property Name, Syntax, IsSingleValued -AutoSize
}
А вот функция GetMandatory:
Function GetMandatory($class)
{
GetAdSchema -action "Mandatory" -class $class
} #end GetMandatory
Теперь давайте взглянем на то, как функция GetOptional может отобразить необязательные свойства класса AD DS. GetOptional принимает значение $class, которое было получено от командной строки через параметр –class, затем передает значение $class функции GetADSchema вместе с действием, именуемым "Optional".
Когда в операторе Switch найдена строка "Optional", на экран выводится сообщение, объясняющее, что отображение необязательных свойств может занять несколько секунд. Затем вызывается метод FindClass из класса ActiveDirectorySchema. Метод FindClass возвращает экземпляр класса ActiveDirectorySchemaClass. Если запросить свойство OptionalProperties класса ActiveDirectorySchemaClass, оно возвратит необязательные свойства, определенные для выбранного класса в AD DS.
Результаты передаются по конвейеру командлету Format-Table, который отображает информацию в том же стиле, что и для обязательных свойств. Вот этот раздел кода:
"Optional"
{
"Optional Properties of $class object"
"This might take a few seconds ..."
($schema.FindClass("$class")).OptionalProperties |
Format-Table -Property Name, Syntax, IsSingleValued -AutoSize
}
Приведенный ниже код – это готовая функция GetOptional:
Function GetOptional($class)
{
GetAdSchema -action "Optional" -class $class
} #end GetOptional
Последняя вспомогательная функция – FindClasses, вызывающая функцию GetADSchema и передающая два значения. Первое – это действие Find («Поиск»), а второе – это класс, который следует найти. Цель этой функции состоит в том, чтобы помочь пользователю определяет классы в схеме AD DS, которые могут заслуживать дальнейшего изучения.
Предположим, что пользователь заинтересован в работе с электронной почтой. В таком случае он хотел бы увидеть, какие классы относятся к электронной почте и какие свойства существуют для применимого класса. Как показано на рис. 6, сперва выполняется сценарий с параметрами почты –action f и –class. Это возвращает все классы, в имени которых содержится строка "mail". После обнаружения интересующего класса свойства класса изучаются путем выбора действия m (от «обязательное») и указания параметра –c (от «класс»), за которыми следует точное имя класса.
Увеличить
Рис. 6. Поиск класса в схеме AD DS
Когда функция FindClasses вызывает GetADSchema, вызывается метод FindAllClasses, и полученная коллекция классов ActiveDirectorySchemaClass пересылается по конвейеру. Where-Object использует поиск по шаблону в виде регулярного выражения для поиска классов, соответствующих значению, сохраненному в переменной $class. Вот код:
"Find"
{
$schema.FindAllClasses() |
Where-Object { $_.name -match "$class" } |
Select-Object -property name
А это функция FindClasses:
Function FindClasses($class)
{
GetAdSchema -action "Find" -class $class
} #end FindClasses
После определения всех вспомогательных функций разработчик прибывает к точке входа в сценарий. Точка входа делает лишь одну вещь – изучает командную строку и определяет, какую функцию вызвать. В первую очередь проверяется присутствие параметра –help. Если сценарий выполняется с помощью –h или –help, то сценарий вызовет функцию GetHelp для отображения справки и выйдет следующим образом:
if($help) { GetHelp ; Exit }
Поскольку поиск параметра –help выполняется в первую очередь, его присутствие в командной строке перекрывает все прочее. Если параметр –help не используется, сценарию необходимо вычислить значение, поставляемое для параметра –action, который является параметром по умолчанию. Все введенное в командной строке будет интерпретировано как значение для –action, если ничего другого не используется. Это дает дополнительное преимущество, позволяя фиксировать фиктивный ввод в сценарий.
Оператор Switch является естественным средством для вычисления значений, предоставляемых для –action. Определяются четыре действия, каждое из которых вызывает соответствующую функцию. Пятое определяемое условие – это действие по умолчанию, и оно отображает сообщение, что действие не допускается, после чего вызывает функцию GetHelp.
Относительно оператора Switch следует помнить, что он может находить несколько совпадений. По этой причине после каждого вызова функций используется оператор Exit («Выход»). Код оператора Switch показан здесь:
Switch ($action)
{
"L" {GetAllClasses ; Exit}
"M" {GetMandatory($class) ; Exit}
"O" {GetOptional($class) ; Exit}
"F" {FindClasses($class) ; Exit}
DEFAULT { "$action is not a valid action." ; GetHelp ; Exit}
}
Ну вот, в общем-то, и все. Нет иного обозревателя Active Directory, кроме ADSI Scriptomatic. Но сценарий BrowseActiveDirectorySchema.ps1 пока что может неплохо справиться с этим. Для знакомства с прочими занятными примерами сценариев Active Directory посетите узел сценариев Active Directory. И вы знаете, что мы открыты в любое время года в Центре сценариев.