В статье «PowerShell, урок 1» рассматривалась концепция составных команд и выполнение базовых команд PowerShell. Кроме того, я показал, как используются псевдонимы и как реализованные в PowerShell команды Get- применяются для получения справочной информации в процессе формирования команд. Так, можно использовать команду Get-ChildItem для считывания списка элементов папки или команду Get-Content — для считывания содержимого текстового файла. С помощью составных команд и их параметров можно выполнять множество действий, которые отображают системную информацию либо выполняют те или иные задачи.

Но сама по себе команда не всегда способна выполнить все функции, которые на нее возлагает пользователь. По этой причине в оболочке PowerShell предусмотрена возможность создания конвейеров, объединяющих команды для выполнения сложных операций и отфильтровывающих полученную информацию. На втором уроке речь пойдет о том, как объединять команды в конвейер с целью создания инструкций PowerShell. Кроме того, я покажу, как форматировать и сортировать выходные данные инструкций.

Реализация конвейера

Конвейер PowerShell — это серия составных команд, в которой объект передается от одной команды к другой. Каждая команда генерирует объект и передает его по конвейеру. Принимающая команда использует полученный объект в качестве входных данных и генерирует собственные выходные данные опять же в виде объекта. Команды объединяются в конвейер с помощью оператора конвейера (|).

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

Публикуемый ниже пример поможет понять, как функционирует конвейер. Если вы запустите команду

Get-Service

то получите список служб, установленных в системе (см. экран 1). Обратите внимание, что команда возвращает состояние, имя и отображаемое имя каждой службы. Теперь предположим, что вы хотите получить список, где будут перечислены только выполняемые в данный момент службы. Можно передать выходные данные команды Get-Service команде Where-Object, которая выполнит фильтрацию выходных данных в соответствии с заданными критериями, как показано в инструкции

Экран 1. Получение списка служб

Get-Service |
Where-Object {$_.status -eq ‘running’}

Таким образом, для объединения двух составных команд используется оператор конвейера. Команда Get-Service создает объект, который содержит данные, касающиеся служб. Далее этот объект передается по конвейеру команде Where-Object. Последняя принимает объект и использует содержащуюся в нем информацию как входные данные. Объект Where-Object выполняет фильтрацию этих данных в соответствии со значением свойства Status. Отметим, что в команду Where-Object входит выражение, заключенное в скобки ({ }). Если это выражение является истинным, Where-Object передает объект далее по конвейеру и отфильтровывает любой другой объект.

В данном случае выражение Where-Object констатирует, что значение свойства Status должно быть приравнено (как указано оператором -eq) к строке running. Status — это одно из свойств объекта, созданного командой Get-Service. Когда объект передается по конвейеру, можно обратиться к его свойствам, как это сделал я в выражении Where-Object. Чтобы обратиться подобным образом к свойству в конвейере, нужно использовать встроенную переменную $_. Эта переменная получает текущий объект в конвейере всякий раз, когда команда Where-Object перебирает полученные в конвейере результаты. Пользователь может ссылаться на свойства объекта, как в выражении $_.Status. Теперь полученные выходные данные по виду аналогичны данным, представленным на экране 2. Дополнительные сведения о команде Where-Object, о свойствах объектов и об операторах будут изложены в следующих уроках.

Экран 2. Получение списка запущенных служб 

Отметим, что обычно в окне консоли PowerShell только что приведенная инструкция вводится одной строкой. Однако ширина столбцов журнальной полосы такова, что для размещения этой инструкции нам приходится использовать более одной строки. Кроме того, обратите внимание на символы >> в начале нескольких строк на экране 2. Эти символы составляют многострочное приглашение. Сведения о том, когда в окне консоли PowerShell следует вводить инструкцию на нескольких строках и как правильно это делать, приведены во врезке «Как работать с длинными инструкциями PowerShell».

Теперь представим себе, что нам нужно перечислить только отображаемые имена всех запущенных служб. Можно по конвейеру передать выходные данные команды Where-Object команде Select-Object:

Get-Service |
where {$_.status -eq ‘running’} |
select displayname

В данной инструкции команда Select-Object получает объект от команды Where-Object. В этом случае инструкция использует псевдоним where для ссылки на команду Where-Object и псевдоним select для ссылки на команду Select-Object. В команде select указывается имя свойства (или свойств), которые предполагается отобразить. В рассматриваемом примере я указал имя displayname. Теперь результаты, полученные при выполнении инструкции, будут подобны тем, что показаны на экране 3.

Экран 3. Получение отображаемых имен запущенных служб

Главное при работе с конвейерами — постоянно помнить о том, что вы всегда имеете дело с объектами. Каждая команда генерирует объект, который передается следующей по конвейеру команде. Последняя команда тоже генерирует объект, в котором содержатся результаты выполнения инструкции. На следующих уроках вы научитесь пользоваться этими объектами, а также их свойствами, что позволит составлять разнообразные инструкции PowerShell.

Форматирование выходных данных

По умолчанию PowerShell форматирует выходные данные инструкции в зависимости от их типа. Например, следующая инструкция возвращает данные о процессе PowerShell:

Get-Process powershell

В этом случае PowerShell отображает выходные данные команды в таблице, как показано на экране 4. Если вы не хотите, чтобы выходные данные были представлены в этом используемом по умолчанию формате, можете по конвейеру передать рассматриваемую выходную инструкцию команде, выполняющей форматирование. PowerShell поддерживает четыре команды, обеспечивающие форматирование выходных данных.

Экран 4. Форматирование данных в виде таблицы

  • Команда Format-Table отображает данные в виде таблицы (экран 4). Этот формат применяется по умолчанию в большинстве составных команд, поэтому команду Table указывают не часто.
  • Команда Format-List отображает данные в виде списка.
  • Команда Format-Wide отображает данные в виде широкой таблицы, в которой для каждого объекта указывается лишь одно значение свойства.
  • Команда Format-Custom отображает данные в пользовательском формате, базирующемся на данных конфигурации, которые содержатся в файле формата .ps1xml. Для обновления файла формата можно использовать команду Update-FormatData. Дополнительные сведения об этом можно найти в справочном файле PowerShell «Update-FormatData».

Чтобы изменить формат выходных данных рассмотренной ранее инструкции, нужно передать ее по конвейеру команде Format-List:

Get-Process powershell |
Format-List

Теперь мы получаем результаты, подобные показанным на экране 5. В формате списка демонстрируется лишь подмножество данных, отображаемых в формате таблицы. В разных форматах отображаются разные сведения. Как форматировать результаты, PowerShell определяет в зависимости от типа данных. Иными словами, возвращаемый тип формата, компоновка и свойства обусловлены типом объекта. Так, результаты, возвращаемые командой Get-ChildItem при считывании данных о файловой системе, будут отличаться от результатов, возвращаемых при считывании сведений о реестре, потому что речь идет о двух разных типах объектов, хотя при этом используется одна и та же команда. Для определения того, каким образом следует отображать результаты, PowerShell использует набор сложных файлов формата XML (файлов .ps1xml).

Экран 5. Вывод данных списком 

Управление выходными данными инструкций

При выполнении инструкции PowerShell применяет к выходным данным стандартное форматирование и направляет эти данные в окно консоли — если только пользователь не переопределяет этот порядок с помощью одного из только что описанных четырех составных команд форматирования. Однако наряду с этим можно также указывать, куда именно следует направлять выходные данные. Для управления выходными данными в PowerShell предусмотрено шесть составных команд.

  • Команда Out-Host направляет выходные данные на консоль PowerShell. Эта команда применяется по умолчанию, поэтому указывать ее не требуется.
  • Команда Out-Default передает выходные данные применяемой по умолчанию команде форматирования. Кроме того, Out-Default делегирует процесс вывода данных команде Out-Host. Специально указывать команду Out-Default не нужно.
  • Команда Out-File направляет выходные данные в указанный файл.
  • Команда Out-Null удаляет выходные данные и не направляет их на консоль PowerShell.
  • Команда Out-Printer направляет выходные данные на принтер.
  • Команда Out-String преобразует объект конвейера в строковый массив. Дополнительные сведения о каждой команде можно найти в справочных файлах оболочки PowerShell.

Для управления выходными данными инструкции нужно в конце конвейера указать соответствующую команду выходных данных. Так, следующая инструкция представляет сведения о процессе PowerShell в формате списка и затем направляет этот список в файл C:SysInfops.txt:

Get-Process powershell |
Format-List |
Out-File C:SysInfops.txt

При передаче выходных данных в файл PowerShell сохраняет содержимое файла, но не отображает его в консоли. Команду Out-File можно использовать для направления выходных данных в любой подходящий файл. Файл .bmp, к примеру, для этой цели не годится. Сообщение об ошибке не появится, но и прочитать что-либо при открытии такого файла тоже не удастся.

Команда Out- File позволяет пользователю указывать, нужно ли присоединять выходные данные к концу файла или замещать этими данными все его содержимое. По умолчанию он выполняет полное замещение. Чтобы присоединить выходные данные к концу файла, в команде Out-File следует использовать переключатель -append:

Get-Process powershell |
Format-List |
Out-File C:SysInfops.txt `
–append

Сортировка выходных данных

Часто бывает необходимо не только отформатировать выходные данные, но и отсортировать их. Для выполнения этой операции используется команда Sort-Object. Эта команда принимает в качестве входных данных объекты, поступающие из конвейера, и сортирует их в соответствии с указанными пользователем критериями. Как уже отмечалось выше, PowerShell передает результаты по конвейеру в виде потока от одной команды к другой. Но в процессе сортировки данных команда Sort-Object выжидает до тех пор, пока не поступят все результаты (объекты), и лишь после этого сортирует их. В итоге процесс потоковой передачи останавливается до завершения операции сортировки. Если речь идет о небольшом результирующем наборе, проблемы не возникает, но при извлечении больших объемов данных производительность системы может снизиться.

Тем не менее команда Sort-Object может быть весьма полезной. Допустим, к примеру, что нам требуется получить список объектов, находящихся в папке C:Windows. Мы можем использовать команду Get- ChildItem в рамках следующей инструкции:

dir c:windows |
where {$_.length -gt 500000} |
sort -property length -descending

Данная инструкция передает выходной объект от команды Get-ChildItem (ссылка на который производится с помощью псевдонима dir) команде Where-Object (ссылка на который производится с помощью псевдонима where). Команда Where-Object определяет, что длина должна быть больше 500000 байт (как указывает переключатель -gt). Затем результаты перемещаются по конвейеру. Когда команда Sort-Object (к которой обращаются с помощью псевдонима sort) получает все объекты, она сортирует их в соответствии с заданными критериями.

В данном случае команда Sort-Object первым делом определяет, что сортировка должна производиться по свойству Length. Переключатель -descending указывает, что результаты нужно сортировать в порядке убывания, как показано на экране 6. Если мы не укажем переключатель -descending, результаты будут сортироваться в порядке возрастания. Кроме того, можно указать несколько свойств (разделенных запятыми), на которых будет основываться порядок сортировки. PowerShell сортирует данные сначала по первому указанному свойству, потом по второму и т. д.

Экран 6. Сортировка по значениям свойства

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

Роберт Шелдон (contact@rhsheldon.com ) — технический консультант и автор большого количества книг по технологиям Microsoft Windows и базам данных


Как работать с длинными инструкциями PowerShell

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

Проиллюстрируем примером. Когда первая строка инструкции заканчивается знаком оператора, как в следующем примере

Get-Service |
where {$_. status -eq ‘running’} |
select displayname

PowerShell исходит из того, что продолжение инструкции перенесено на следующую строку. Результаты упомянутой инструкции подобны показанным на экране 3. Обратите внимание на символы многострочного приглашения (>>), с которых начинается каждая строка после первой. Когда PowerShell предполагает, что текущая строка будет продолжена на второй строке, перед последней указывается многострочное приглашение. И тогда после этого приглашения пользователь вводит на второй строке следующую строку кода. После того как оболочка PowerShell переходит в этот многострочный режим, она будет продолжать работу в данном режиме и предлагать пользователю многострочное приглашение. По завершении ввода последней строки нажмите клавишу «Ввод» во второй раз для выполнения команды и для возвращения к обычному приглашению.

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

Get-Service
   | where {$_. status -eq ‘running’}
   | select displayname

Теперь PowerShell воспринимает первую строку как завершенную и обрабатывает ее как целостную инструкцию. После этого PowerShell пытается обработать вторую строку, что приводит к появлению сообщения об ошибке. Использование пустого элемента конвейера не допускается. Выйти из положения можно, завершая строки символами обратной кавычки (`).

Get-Service `
   | where {$_. status -eq ‘running’} `
   | select displayname

Символ обратной кавычки извещает PowerShell о том, что инструкция будет продолжена на следующей строке. Теперь рассматриваемая инструкция возвращает те же данные, что и на экране 3.

Оболочка PowerShell обрабатывает каждую строку, которая рассматривается ею как завершенная инструкция. Иными словами, она автоматически прекращает выполнение инструкции, когда доходит до новой строки, кроме тех случаев, когда PowerShell полагает, что инструкция будет продолжена. Однако помните, что можно прекратить выполнение инструкции вручную; для этого нужно добавить в конце символ точки с запятой (;):

Get-Service |
   where {$_. status -eq ‘running’} |
   select displayname;

Эта инструкция возвращает результаты, которые представлены на экране 3.