Оболочка Exchange Management Shell (EMS) в составе Microsoft Exchange Server 2007 — это хорошая интерактивная среда: вы вводите команды, командный процессор проверяет их на синтаксис, выполняет, и результат появляется немедленно. Это отличная модель в том случае, если нужно внести ряд изменений за один раз или быстро ввести несколько команд, чтобы получить какой-то конкретный итог. Однако существует ряд ситуаций, когда необходимо выполнить несколько команд и объединить их логически для нахождения решения или оценки условий. Все это можно сохранить как конечный сценарий, таким образом, вы сможете запускать его в любое время.

Я уже показывал, как использовать команды Windows PowerShell из EMS для того, чтобы найти объекты Exchange Server, изучить их свойства и внести изменения в один или более объектов. Все, что рассматривалось ранее, было нацелено на ввод команд в EMS и их немедленное исполнение. В этой статье я покажу, как строить сценарии, которые вы можете запускать повторно для автоматизации привычных задач, таких как получение информации из почтовых ящиков, создание учетных записей пользователей и изменение настроек на нескольких серверах.

Не забывайте, что мы говорим об Exchange Server 2007, который использует PowerShell 1.0. Версия PowerShell 2.0 доступна в виде Community Technology Preview (CTP) на сайте Microsoft (http://www.microsoft.com/technet/scriptcenter/topics/msh/download2.mspx), она включает редактор с графическим интерфейсом, который упрощает некоторые аспекты написания сценариев, но его нельзя использовать с Exchange.

Оценка условий и принятие решений

Примеры работы с EMS включают три этапа: получение объектов, отбор тех из них, над которыми должно производиться действие, и выполнение какого-либо действия. Одно из ключевых отличий между интерактивными командами и сценариями состоит в том, что сценариям обычно нужен способ оценки условий, и они будут предпринимать то или иное действие, только основываясь на этой оценке.

Языки сценариев обычно предлагают операторы условия, которые позволяют сравнить два значения и увидеть, что одно из них больше, чем другое, меньше или равно ему. У EMS есть ряд операторов, как показано в таблице 1, которые можно использовать для сравнения величин. Эти операторы работают с большинством встроенных типов данных, включая строки. Однако сравнение строк в EMS не является зависящим от регистра по умолчанию.

Операторы условия

Если вам нужно сравнить величины с учетом их регистра, вы можете сделать это, снабдив соответствующий оператор префиксом, содержащим букву «с».

Например:

"Paul" -ceq "paul"

Возвращает false, потому что две строки не являются совпадающими точно.

Также можно задействовать логические операторы для сравнения или изменения значений других типов операций. Эти операторы, показанные в таблице 2, обычно используются в условных операторах, где действие предпринимается в зависимости от результата. Есть другие, более мощные логические операторы, но и эти должны покрыть большую часть ваших потребностей.

Простейшие логические операторы

Существует несколько способов использования условных операторов в EMS, чтобы можно было применять сценарии для оценки условий и принятия действий по результатам. Первый и самый простой способ — это оператор if. Он покажется знакомым каждому, кто когда-либо писал сценарии: вы задаете условие, которое проверяется, и действие, которое должно быть предпринято. Также можно включить предложение else, которое будет проверяться только в том случае, если исходное условие возвращает false. Вот пример:

If (True)
Write-Host "PowerShell is AWESOME!"
Else
Write-Host "You'll never see this message."

Кроме того, можно использовать оператор elseif для объединения в цепь сложных заданий:

$detroitLions = FALSE;
$newOrleansSaints = TRUE;
If ($detroitLions)
Write-Host "Well, there's always next year"
ElseIf ($newOrleansSaints)
Write-Host "Lifelong Saints fans never
give up"
Else
Write-Host "Not a football fan, I guess!"

Оператор if полезен в любых ситуациях, но это не самый лучший способ производить проверки, в которых вы хотите сравнить одно значение с несколькими. В данном случае вы можете использовать оператор switch, который позволяет задать ряд возможных значений и блок кода, который должен быть выполнен для каждого. В качестве примера можно сконструировать оператор switch, чтобы оценить шансы конкретной футбольной команды стать чемпионом:

Switch ($teamName)
{
"Saints" {$odds = 0.5; WriteHost
"Maybe…";}
"Lions" {$odds = 0.0; WriteHost
"No way!";}
"Giants" {$odds = 0.9; WriteHost
"Looks likely at this point.";}
}

Заметим, что в этом примере код, выполняемый для каждой проверки в операторе switch, содержит более одного оператора, отделен точкой с запятой и заключен в фигурные скобки. Скобки являются важным элементом синтаксиса EMS. Вы можете заключать сложные операторы в скобки для того, чтобы работать с ними как с группой в цикле и операторах условия.

Многие, должно быть, заметили, что упомянутый выше оператор switch использует сравнения строк. EMS также позволяет использовать сравнение массивов, регулярные выражения и групповые символы как часть индивидуальных операторов switch. Например, вы можете написать следующий оператор switch для превращения цифровой шкалы в символьную:

Switch ($testScore)
{
{$_-lt 60} {$letterGrade = "F"; break;}
{$_-lt 70} {$letterGrade = "D"; break;} {$_-lt 80} {$letterGrade = "C"; break;}
{$_-lt 90} {$letterGrade = "B"; break;} {$_-lt 100} {$letterGrade = "A"; break;}
}

Обратите внимание, что каждое сравнение в операторе switch использует знак $_ для подстановки текущего объекта в оператор условия.

Циклы и итерации

Вам нередко придется повторять одно действие несколько раз для того, чтобы достичь желаемого. Это требуется при использовании конвейера PowerShell. Например, вы отбираете группу почтовых ящиков и изменяете какой-нибудь атрибут при помощи Get-Mailbox и Set-Mailbox.

Get-Mailbox возвращает набор объектов, каждый из которых передается в Set-Mailbox, и вам не нужно писать собственный цикл для выполнения этого действия.

Вы можете повторить блок кода несколькими способами. Во-первых, вы можете использовать оператор цикла for. Оператор for продолжает выполнение, пока условие, определенное в операторе, остается верным. Вам нужно будет определить переменную значение цикла, условие, которое должно быть проверено, и действие, которое должно быть выполнено для каждого повтора. Описать все это сложнее, чем сделать. Взгляните на этот пример:

For ($i = 0; $i -lt 15; $i=$i+1)
Write-Host "The value of i is now " $i;

В данном примере, где распечатана строка для каждого целого от 1 до 15, $i=0 является начальным значением цикла. Мы можем назвать $i индексом цикла, а начальное значение подготавливает его для работы в цикле. Условие, которое мы тестируем, состоит в том, является ли $i меньше, чем 15; при каждом проходе цикла значение $i увеличивается на 1. Фактический код, выполняемый в цикле, — это простой оператор Write-Host, но вы могли бы предпринять и более сложные действия.

Второй способ создания цикла — это оператор foreach. Данному оператору не требуется начальное значение или условие, которое должно быть проверено, поскольку он спроектирован так, чтобы использоваться с коллекцией объектов, такой как массивы устройств или результаты, возвращаемые другой командой. Используйте оператор foreach, когда хотите предпринять действие для каждого объекта или элемента в наборе, вне зависимости от их количества. Вот пример из документации Microsoft:

Foreach ($file in Get-ChildItem)
Write-Host $file;

Этот код получает список всех файлов в текущем каталоге (который определяется через Get-ChildItem) и проходит по списку, печатая имя каждого файла. Оператор Foreach ценен тем, что освобождает вас от беспокойства по поводу того, с каким количеством шагов работает цикл. Конечно же, код, выполняемый в операторе foreach, может тестировать объекты для того, чтобы принимать решение о том, обрабатывать элемент или нет.

А вдруг вы хотите продолжать выполнять блок кода до тех пор, пока условие не изменится? В этом случае вы, вероятно, используете оператор цикла. Пример:

$keepGoing = TRUE;
while ($keepGoing)
{
Write-Host "This loop will never stop.";
}

В этом случае цикл никогда не остановится, потому что значение $keepGoing не изменится; в реальном сценарии вам придется модернизировать значение $keepGoing в цикле так, чтобы сценарий останавливался, когда нужно. Есть вариант оператора цикла — оператор Do While, который проверяет условие в конце цикла, так что операторы в цикле всегда выполняются по меньшей мере один раз.

Простой пример

Давайте теперь сложим все вместе, чтобы рассмотреть сценарий, который я подготовил для недавнего проекта. Сценарий batch-spam.ps1 предназначен для запуска каждые два часа. Он осматривает указанный каталог, собирает все файлы (в данном случае — спам-сообщения в электронной почте), сжимает их в zip-файл, перемещает zip-файл в другой каталог, затем завершает работу. В листинге 1 показан код этого сценария.

batch-spam.ps1

Я использую еще один сценарий, который запускается на другой системе для того, чтобы получить сжатые файлы со спамом, распаковать и проанализировать их. Это более сложный процесс. Далее в статье я объясню, как работает batch-spam.ps1. Я не буду рассказывать о том, как работают индивидуальные команды PowerShell, но вы можете найти эту информацию, просмотрев документацию Microsoft.

Как видно во фрагменте А листинга 1, сценарий начинается с определения функции PowerShell. Функция есть блок кода, который возвращает значение. И это все. В нашем случае функция принимает аргумент (дата и время) и возвращает true, если дата — текущий день, и false, если это не так. Я позаимствовал эту функцию из журнала Джефри Сновера по PowerShell на сайте blogs.msdn.com/powershell.

Далее во фрагменте В вы увидите краткий блок кода, назначающий каталоги, которые я собираюсь использовать для сбора спама и раскрытия сжатых папок. Код во фрагменте С получает дату и время, потом форматирует их, переставляя вперед номер месяца и день и добавляя значащие нули к однозначным числам, а затем превращает дату в строку, которая будет именем подпапки целевой папки. Эта структура позволяет сценарию накапливать спам в течение многих дней в единственную целевую папку, но сохраняет спам от каждого дня в отдельной подпапке.

После того как мы получили дату и время, сценарий может проверить, существует ли эта папка. Если да, то она будет очищена; если папка не существует, то она будет создана. Для принятия этого решения сценарий использует простой условный оператор. Оператор [void] нужен для того, чтобы игнорировать результаты, которые мы получаем как ответ при создании папки.

Теперь мы можем переместить сообщения со спамом из папки спама в подходящую папку на ту дату, когда они были получены. Как показывает код во фрагменте D, сценарий использует Get-ChildItem для получения всех файлов из исходной папки, затем переправляет результат Copy-Item для копирования файлов.

Следующая часть, сжатие целевой папки, немного хитрее. PowerShell не обладает встроенными функциями для манипуляции с zip-файлами. Однако вы можете вызывать COM-методы в сценариях PowerShell, что продемонстрировано в коде во фрагменте Е. Чтобы создать zip-файл, нужно создать файл и установить первые 22 байт равными специальной строке, которая указывает, что файл является zip-файлом. Это делается при помощи команды Set-Content. После установки заголовка файла мы можем создать новый интерфейс к Windows Explorer и использовать его для добавления файлов в целевой zip-файл. Я взял эту функцию из журнала Майка Ходника по адресу http://blogs.inetium.com/blogs/mhodnick/archive/2006/08/07/295.aspx.

Наконец, мы перемещаем вновь созданный zip-файл в нужное место, как показывает фрагмент F. Заметьте, что в этом случае я использовал Move-Item, потому что хотел переместить файл вместо того, чтобы использовать Copy-Item, как мы делаем, когда перемещаем файлы спама в место назначения.

Пишите еще!

Лучший способ получить опыт написания сценариев EMS — это попытаться «набить руку», написав их несколько штук. Благодаря операторам WhatIf и Confirm можно сделать это, не боясь повредить что-нибудь важное. Существует много интересных примеров сценариев PowerShell в Internet. В частности, у Microsoft есть множество примеров сценариев на сайте The Script Center Script Repository (http://www.microsoft.com/technet/scriptcenter/scripts/msh/default.mspx), которые могут очень пригодиться, когда вы пытаетесь узнать, чего сможете добиться с EMS.

Поль Робишо (troubleshooter@robichaux.net) — главный инженер компании 3 sharp, имеет сертификаты MCSE и звание Exchange MVP. Автор нескольких книг, в том числе The Exchange Server Cookbook, и создатель Web-узла http://www.exchangefaq.org