В статье «Where-Object и конвейер», опубликованной в Windows IT Pro/RE № 1 за 2014 год, речь шла о конвейере PowerShell и о его «секретном имени» ($_). Ранее я рассказывал, как с помощью конвейера можно скомбинировать две команды Active Directory (AD) – например, чтобы найти всех пользователей, которые не регистрировались на протяжении последних 90 дней, и отключить их учетные записи:

search-adaccount –usersonly –AccountInactive –timespan «90" | disable-ADAccount

Хотя этот»однострочник«выглядит простым, в нем есть скрытая сложность. Предположим, что, проводя ревизию своей среды AD, вы обнаруживаете, что данные учетных записей ваших пользователей включают имена, инициалы и фамилии, введенные как значения соответствующих атрибутов, тогда как поле атрибута DisplayName – пустое, и вы хотите его заполнить. Атрибуты имени, инициалов и фамилии – соответственно, givenname, initials и sn (я уверен, что сотрудники комитета по стандарту X.500 придумали эти имена во время веселой вечеринки). Требуется заполнить пустые поля атрибута DisplayName, составляя их автоматически из этих трех атрибутов для каждого пользователя. Ситуация несколько надуманная, но достаточно непростая, чтобы служить хорошим примером.

Для решения этой задачи необходима команда ForEach-Object, имеющая псевдонимы foreach и % (символ процентов). Как и команда For, о которой я рассказывал несколько лет назад, это одна из тех команд PowerShell, которые способны из просто полезного инструмента сделать»супер инструмент«. ForEach работает следующим образом:

| foreach { }

Как загрузить конвейер? Данные подаются на конвейер после каждого запуска команды, выдающей какую-либо информацию. Например, если среда насчитывает 15 пользователей, то в результате запуска get-aduser -filter * на конвейер будет подано 15 объектов. Более простой способ загрузки конвейера – простое перечисление данных в командной строке через запятую. Например, если ввести строку

1,»orange«,77

и нажать клавишу ввода, то на экране появятся три строки: 1, orange и 77. Это самый простой способ подачи объектов на конвейер.

Данный пример иллюстрирует загрузку конвейера без каких-либо последующих действий. В этом случае PowerShell просто выводит объекты конвейера на экран. Для выполнения более сложной задачи необходима команда ForEach. За инструкцией ForEach должны следовать фигурные скобки, заключающие одну или несколько команд, разделенных точкой с запятой (структура, в терминах PowerShell именуемая «блоком сценария»).

Например, при вводе команды

»Wally«,7,33,»Cloud«| foreach {»There's something in the pipeline«}

на экран четыре раза будет выведена строка There's something in the pipeline. Иначе говоря, сначала на конвейер загружаются четыре объекта, после чего каждый из них передается на вход команды ForEach.

Для максимально эффективного использования возможностей ForEach необходимо понимать, что эта команда делает. ForEach последовательно берет очередной объект с конвейера и выполняет с ним три действия: временно сохраняет объект в качестве значения переменной $_, исполняет заданный блок сценария и выбрасывает объект. Затем аналогично обрабатывается следующий объект конвейера.

Таким образом, в нашем случае ForEach сначала берет с конвейера объект»Wally«, делает его значением переменной $_ и выполняет то, что предписано блоком сценария, а именно, выводит на экран There's something in the pipeline (заметим, что в этом простом примере переменная $_ не используется). Далее объект»Wally«отбрасывается, берется объект 7 и назначается в качестве $_. Затем на экран выводится There's something in the pipeline, и объект 7 отбрасывается. Эти шаги повторяются последовательно для объектов 33 и»Cloud«, после чего конвейер становится пустым.

Изменим блок сценария следующим образом:

»Wally«,7, 33,»Cloud«| foreach {»Pipeline contains:«+ $_ }

В результате на экран будут выведены четыре разных строки:

Pipeline contains:Wally
Pipeline contains:7

и т.д. Разница обусловлена тем, что на этот раз к статическому неизменяемому тексту добавлена переменная $_, значение которой каждый раз меняется. Символ «плюс» означает операцию сцепления статического текста»Pipeline contains:" и текущего значения $_, называемую конкатенацией.

Надеюсь, что на этих простых примерах вы получили представление о том, как работает ForEach, и готовы к изучению возможностей этой команды на примере задачи заполнения атрибута DisplayName, но об этом мы поговорим в следующий раз.