В статье «Продолжаем изучать ForEach», опубликованной в предыдущем номере журнала, было показано, как любой однострочный запрос к Active Directory (AD) можно сделать более гибким, переписав его в более сложном виде с использованием переменной $_ и команды ForEach. На этот раз мы рассмотрим более интересный пример применения ForEach, пройдя пошаговый процесс его компоновки, позволяющий понять, как построить собственную однострочную команду.

Тема односторочных команд с использованием ForEach была начата с простой, но любопытной задачи: в предположении, что все учетные записи AD содержат атрибуты AD givenname (имя) и sn (фамилия), скомпоновать отображаемые имена (DisplayName) учетных записей в виде имени (givenname) и фамилии (sn), разделенных пробелом.

Прежде чем вы спросите, почему для имени используется атрибут givenname, а для фамилии – укороченная запись sn вместо surname, замечу, что вины Microsoft здесь нет. Схема AD строилась на основе стандарта X.500, который создавался в качестве шаблона для любой службы связи, требующей ввода имени пользователя и пароля. Работа над его структурой и определением имен атрибутов была начата еще в 1984 году. Если вспомнить еще один стандартный атрибут X.500, FavoriteBeverage, то можно предположить, что атрибут givenname был определен до обеда, а sn – уже в послеобеденное время. Стоит также упомянуть, что группа разработчиков AD сжалилась над нами и добавила дополнительный «синтетический» атрибут surname, известный только для PowerShell.

Любую однострочную команду проще всего строить с верхнего уровня, определяя «фильтр» (учетные записи, которые являются объектом применяемого действия) и «действие». В нашем примере фильтр прост, поскольку действие применяется ко всем учетным записям AD:

get-aduser -filter * -properties *

Далее надлежит изменить атрибуты DisplayName учетных записей. Как мы уже знаем, для изменения атрибутов пользователей AD существует команда Set-ADUser. Ее синтаксис будет сложнее, чем у Get-ADUser, поэтому начнем с простого примера. Запрос Set-ADUser, позволяющий для пользователя с именем john задать отображаемое имя John Smith, будет выглядеть следующим образом:

set-aduser john -displayname «John Smith»

Теперь построим однострочную команду по схеме, рассмотренной в предыдущей статье:

get-aduser -filter * -properties * | foreach {действие с использованием $_}

Задача состоит в том, чтобы из приведенного выше статического запроса Set-ADUser скомпоновать {действие с использованием $_}. Для этого сначала перепишем запрос Set-ADUser в обобщенном виде, но на «человеческом» языке:

set-aduser [имя текущего пользователя на конвейере] -displayname (имя и фамилия текущего пользователя на конвейере, разделенные пробелом)

Я взял в скобки вторую часть по двум причинам. Прежде всего, это удобно для пояснения смысла синтаксиса. Кроме того, размещение скобок в окончательном варианте однострочной команды сделает ее более удобочитаемой для того, кто спустя полгода попытается выяснить суть данного запроса и механизм его действия (с большой долей вероятности этим «кем-то» будете вы).

Мы уже знаем, что для сцепления (конкатенации) в PowerShell используется знак плюс, а для размещения пробела – пустой символ, окруженный кавычками. Таким образом, команда Set-ADUser сводится к следующему виду:

set-aduser [имя текущего пользователя на конвейере] -displayname (имя пользователя + «" + фамилия пользователя)

Заключительная часть преобразования записи на язык PowerShell состоит в формальном описании имени учетной записи пользователя и добавлении атрибутов givenname и sn текущего объекта с конвейера, хранимого переменной $_:

set-aduser $_.samaccountname -displayname ($_.givenname +» «+ $_.sn)

Кроме того, команду Set-ADUser нет необходимости направлять к атрибуту samaccountname, поскольку она достаточно «сообразительна» для правильного восприятия объекта. Вставляем запрос Set-ADUser в блок сценария ForEach и получаем следующее:

get-aduser -filter * -properties * | foreach { set-aduser $_ -displayname ($_.givenname +» " + $_.sn)}

Воспринимается это сложнее, чем однострочные команды без ForEach, которые мы рассматривали ранее, но оно того стоит.