В статьях «Where-Object и конвейер» и «Конвейер и ForEach», опубликованных в Windows IT Pro/RE № 1 и № 3 за 2014 год, рассказывалось о двух важных структурных элементах однострочных запросов – конвейере и ForEach. В этом выпуске речь пойдет о том, как их комбинировать для построения других «однострочников».
До сих пор мы рассматривали однострочные команды, подобные приведенной ниже, позволяющие найти и отключить учетные записи, под которыми регистрация в системе не производилась на протяжении последних 90 дней:
search-adaccount -UsersOnly -AccountInactive -TimeSpan «90" | disable-adaccount
Первая команда, search-adaccount, находит неактивных пользователей и передает их второй команде, disable-adaccount, которая выключает их учетные записи; передача выполняется по конвейеру. Тот факт, что PowerShell позволяет выполнять столь полезное действие с помощью такого простого однострочного запроса, уже примечателен, поскольку позволяет вместо использования сложных циклических команд и переменных решить поставленную задачу с помощью минимального синтаксиса. К сожалению, если вы решите выйти за рамки этого базового запроса, чтобы извлечь еще больше возможностей автоматизации из PowerShell, вам придется сделать некоторое отступление. Посмотрим, как можно решить задачу отключения неактивных учетных записей способом, хотя и не столь изящным, зато значительно более гибким.
Рассмотрим вторую команду, disable-adaccount. Для ее работы обычно требуется указывать имя отключаемой учетной записи. Если в окне командной строки PowerShell ввести просто disable-adaccount и нажать клавишу ввода, PowerShell отметит, что не указаны идентификационные данные выключаемого объекта. После указания входного имени команда выполняется без проблем:
disable-adaccount JFrost
Однако в однострочной команде, приведенной в начале статьи, после disable-adaccount не указано имен, но запрос выполняется без возражений. Дело в том, что автор данной команды заложил в нее определенную логику. При вызове без указания имени учетной записи команда исследует содержимое конвейера в поиске объекта, который может сойти за имя учетной записи, каковым может быть идентификатор безопасности (SID), идентификатор GUID или отличительное имя (DN). Поскольку команда search-adaccount выдает полные объекты пользователя, имеющие имя, DN, SID и GUID, на принимающей стороне конвейера disable-adaccount получает более чем достаточно информации для того, чтобы определить учетные записи, которые следует выключить. Можно подать на конвейер и вполне конкретные данные – SamAccountName или SID, а с другой стороны конвейера вызвать disable-adaccount:
»S-1-5-21-3471743624-104184042-3101405554-3104«| disable-adaccount
или:
»jdorn«| disable-adaccount
В обоих случаях я подал на конвейер конкретный текст (в терминах программирования – строку). PowerShell вызывает команду disable-adaccount и подает на вход содержимое конвейера, после чего disable-adaccount пытается сопоставить содержимое конвейера с известными именами для входа, SID, GUID или DN. Если соответствие найдено, то все в порядке. В противном случае disable-adaccount выдает ошибку, как если бы я ввел следующий запрос:
»розы красные«| disable-adaccount
В этом запросе на конвейере нет ничего, что может сойти за идентификатор учетной записи AD. К счастью, большая часть команд для Active Directory (AD) работает одинаково, и одни и те же действия с remove-aduser, unlock-adaccount, enable-adaccount и get-aduser выполняются с одинаковым успехом. Однако дважды подумайте, прежде чем экспериментировать с remove-aduser!
Теперь переделаем нашу однострочную команду, применив конструкцию ForEach и переменную $_, хранящую текущее содержимое конвейера. Как мы уже знаем, чтобы использовать ForEach, необходимо сначала заполнить конвейер, затем поставить символ конвейера (|) и foreach, после чего вставить необходимые команды в фигурные скобки или, на языке PowerShell, поместить блок сценария. Таким образом, наша однострочная команда на языке ForEach будет выглядеть следующим образом:
search-adaccount -UsersOnly -AccountInactive -TimeSpan»90«| foreach {disable-adaccount}
Такой запрос, однако, не сработает, поскольку команда disable-adaccount, вызываемая из блока сценария ForEach, не получает автоматически на вход содержимое конвейера, поэтому необходимо явное указание выключаемой учетной записи. В противном случае выполнение запроса остановится, как если бы мы просто указали disable-adaccount в командной строке. Небольшое изменение исправит положение:
search-adaccount -UsersOnly -AccountInactive -TimeSpan»90«| foreach {disable-adaccount $_ }
Переменная $_ удовлетворяет потребность disable-adaccount в информации, определяющей выключаемую учетную запись, поскольку в данный момент на конвейере находится объект пользователя AD. В чем польза более сложного синтаксиса? В более широких возможностях. Например, первоначальная однострочная команда не выдает никакой выходной информации, если только не возникает ошибка. Что если вам понадобится регистрировать удаляемые учетные записи в журнале? Команда add-content позволяет записывать указанную текстовую строку в существующий файл, например:
add-content c:\logs\disable.log»Удалена очередная учетная запись«
В блок сценария можно помещать несколько команд, разделяя их точкой с запятой, что позволяет организовать занесение в журнал имени каждой удаляемой учетной записи, которое хранит переменная $_.samaccountname:
search-adaccount -UsersOnly -AccountInactive -TimeSpan»90" | foreach {disable-adaccount $_; add-content c:\logs\disable.log $_.samaccountname}
Итак, мы сделали еще один шаг к построению поистине эффективных запросов. Продолжим в следующем номере!