about_Pipelines
Краткое описание
Объединение команд в конвейеры в PowerShell
Подробное описание
Конвейер — это ряд команд, соединенных операторами конвейера (|
) (ASCII 124). Каждый оператор конвейера отправляет результаты предыдущей команды в следующую команду.
Выходные данные первой команды можно отправить для обработки в качестве входных данных для второй команды. И эти выходные данные можно отправить в еще одну команду. Результатом является сложная цепочка команд или конвейер , состоящий из ряда простых команд.
Например,
Command-1 | Command-2 | Command-3
В этом примере генерируемые Command-1
объекты отправляются в Command-2
.
Command-2
обрабатывает объекты и отправляет их в Command-3
. Command-3
обрабатывает объекты и отправляет их по конвейеру. Так как в конвейере больше нет команд, результаты отображаются в консоли.
В конвейере команды обрабатываются по порядку слева направо. Обработка обрабатывается как одна операция, а выходные данные отображаются по мере ее создания.
Вот простой пример. Следующая команда получает процесс Блокнота, а затем останавливает его.
Например,
Get-Process notepad | Stop-Process
Первая команда использует Get-Process
командлет для получения объекта, представляющего процесс Блокнота. Он использует оператор конвейера (|
) для отправки объекта процесса в Stop-Process
командлет , который останавливает процесс Блокнота. Обратите внимание, что команда Stop-Process
не имеет параметра Name или ID для указания процесса, так как указанный процесс отправляется через конвейер.
Этот пример конвейера получает текстовые файлы в текущем каталоге, выбирает только файлы длиной более 10 000 байт, сортирует их по длине и отображает имя и длину каждого файла в таблице.
Get-ChildItem -Path *.txt |
Where-Object {$_.length -gt 10000} |
Sort-Object -Property length |
Format-Table -Property name, length
Этот конвейер состоит из четырех команд в указанном порядке. На следующем рисунке показаны выходные данные каждой команды, передаваемые в следующую команду в конвейере.
Get-ChildItem -Path *.txt
| (FileInfo objects for *.txt)
V
Where-Object {$_.length -gt 10000}
| (FileInfo objects for *.txt)
| ( Length > 10000 )
V
Sort-Object -Property Length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
V
Format-Table -Property name, length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
| ( Formatted in a table )
V
Name Length
---- ------
tmp1.txt 82920
tmp2.txt 114000
tmp3.txt 114000
Использование конвейеров
Большинство командлетов PowerShell предназначены для поддержки конвейеров. В большинстве случаев результаты командлета Getможно передать в другой командлет того же существительного.
Например, можно передать выходные данные командлета в Get-Service
Start-Service
командлеты или Stop-Service
.
В этом примере конвейера запускается служба WMI на компьютере:
Get-Service wmi | Start-Service
В другом примере можно передать выходные данные Get-Item
поставщика реестра New-ItemProperty
PowerShell или Get-ChildItem
в командлет . В этом примере в раздел реестра MyCompany добавляется новая запись реестра NoOfEmployees со значением 8124.
Get-Item -Path HKLM:\Software\MyCompany |
New-ItemProperty -Name NoOfEmployees -Value 8124
Многие служебные командлеты, такие как Get-Member
, Where-Object
, Sort-Object
, Group-Object
и Measure-Object
, используются почти исключительно в конвейерах. В эти командлеты можно передать объект любого типа. В этом примере показано, как отсортировать все процессы на компьютере по количеству открытых дескрипторов в каждом процессе.
Get-Process | Sort-Object -Property handles
Объекты можно передавать по конвейеру в командлеты форматирования, экспорта и вывода, такие как Format-List
, Format-Table
, Export-Clixml
, Export-CSV
и Out-File
.
В этом примере показано, как использовать Format-List
командлет для отображения списка свойств объекта процесса.
Get-Process winlogon | Format-List -Property *
Вы также можете передать выходные данные собственных команд в командлеты PowerShell. Пример:
PS> ipconfig.exe | Select-String -Pattern 'IPv4'
IPv4 Address. . . . . . . . . . . : 172.24.80.1
IPv4 Address. . . . . . . . . . . : 192.168.1.45
IPv4 Address. . . . . . . . . . . : 100.64.108.37
Важно!
Потоки Success и Error аналогичны потокам stdin и stderr других оболочек. Однако stdin не подключен к конвейеру PowerShell для ввода. Дополнительные сведения см. в разделе about_Redirection.
Немного потренируясь, вы обнаружите, что объединение простых команд в конвейеры экономит время и ввод текста, а также делает скрипты более эффективными.
Принцип работы конвейеров
В этом разделе объясняется, как входные объекты привязываются к параметрам командлета и обрабатываются во время выполнения конвейера.
Принимает входные данные конвейера
Для поддержки конвейерной конвейерной передачи принимающий командлет должен иметь параметр, который принимает входные данные конвейера. Get-Help
Используйте команду с параметрами Full или Parameter, чтобы определить, какие параметры командлета принимают входные данные конвейера.
Например, чтобы определить, какие из параметров командлета Start-Service
принимают входные данные конвейера, введите следующее:
Get-Help Start-Service -Full
или
Get-Help Start-Service -Parameter *
В справке по командлету Start-Service
показано, что только параметры InputObject и Name принимают входные данные конвейера.
-InputObject <ServiceController[]>
Specifies ServiceController objects representing the services to be started.
Enter a variable that contains the objects, or type a command or expression
that gets the objects.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByValue)
Accept wildcard characters? false
-Name <String[]>
Specifies the service names for the service to be started.
The parameter name is optional. You can use Name or its alias, ServiceName,
or you can omit the parameter name.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? false
При отправке объектов через конвейер в PowerShell пытается Start-Service
связать объекты с параметрами InputObject и Name .
Методы приема входных данных конвейера
Параметры командлетов могут принимать входные данные конвейера одним из двух разных способов:
ByValue: параметр принимает значения, соответствующие ожидаемому типу .NET или которые можно преобразовать в этот тип.
Например, параметр Name объекта принимает входные данные конвейера
Start-Service
по значению. Он может принимать строковые объекты или объекты, которые можно преобразовать в строки.ByPropertyName: параметр принимает входные данные, только если входной объект имеет свойство с тем же именем, что и параметр.
Например, параметр
Start-Service
Name объекта может принимать объекты со свойством Name . Чтобы получить список свойств объекта, передайте его вGet-Member
.
Некоторые параметры могут принимать объекты как по значению, так и по имени свойства, что упрощает получение входных данных из конвейера.
Привязка параметра
Когда объекты передаются из одной команды в другую, PowerShell пытается связать полученные объекты с параметром принимающего командлета.
Компонент привязки параметров PowerShell связывает входные объекты с параметрами командлета в соответствии со следующими критериями:
- Параметр должен принимать входные данные из конвейера.
- Параметр должен принимать тип отправляемого объекта или тип, который можно преобразовать в ожидаемый тип.
- Параметр не использовался в команде .
Например, Start-Service
командлет имеет много параметров, но только два из них, Name и InputObject , принимают входные данные конвейера. Параметр Name принимает строки, а параметр InputObject принимает объекты службы. Таким образом, строки, объекты службы и объекты можно передавать по конвейеру со свойствами, которые можно преобразовать в строковые или служебные объекты.
PowerShell максимально эффективно управляет привязкой параметров. Вы не можете предложить или принудительно привязать PowerShell к определенному параметру. Команда завершается ошибкой, если PowerShell не может привязать объекты, которые передаются по конвейеру.
Дополнительные сведения об устранении ошибок привязки см. в разделе Исследование ошибок конвейера далее в этой статье.
Разовая обработка
Передача объектов в команду во многом похожа на использование параметра команды для отправки объектов. Рассмотрим пример конвейера. В этом примере мы используем конвейер для отображения таблицы объектов службы.
Get-Service | Format-Table -Property Name, DependentServices
Функционально это похоже на использование параметра InputObject для Format-Table
отправки коллекции объектов.
Например, можно сохранить коллекцию служб в переменной, передаваемой с помощью параметра InputObject .
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
Или мы можем внедрить команду в параметр InputObject .
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
Тем не менее, есть важное различие. Когда вы передаете несколько объектов в команду, PowerShell отправляет объекты команде по одному за раз. При использовании параметра команды объекты отправляются в виде одного объекта массива. Это незначительное различие имеет значительные последствия.
При выполнении конвейера PowerShell автоматически перечисляет любой тип, реализующий IEnumerable
интерфейс или его универсальный аналог. Перечисляемые элементы отправляются через конвейер по одному за раз. PowerShell также перечисляет типы System.Data.DataTable с помощью Rows
свойства .
Существует несколько исключений для автоматического перечисления.
- Необходимо вызвать
GetEnumerator()
метод для хэш-таблиц, типов, реализующихIDictionary
интерфейс или его универсальный аналог, и System.Xml. Типы XmlNode . - Класс System.String реализует
IEnumerable
, однако PowerShell не перечисляет строковые объекты.
В следующих примерах массив и хэш-сводка передаются в Measure-Object
командлет для подсчета количества объектов, полученных из конвейера. Массив содержит несколько элементов, а хэш-диаграмма содержит несколько пар "ключ-значение". По одному перечисляется только массив.
@(1,2,3) | Measure-Object
Count : 3
Average :
Sum :
Maximum :
Minimum :
Property :
@{"One"=1;"Two"=2} | Measure-Object
Count : 1
Average :
Sum :
Maximum :
Minimum :
Property :
Аналогичным образом, если передать несколько объектов процесса из командлета Get-Process
в Get-Member
командлет, PowerShell отправляет каждый объект процесса по одному в Get-Member
. Get-Member
отображает класс (тип) .NET объектов процесса, а также их свойства и методы.
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
Примечание
Get-Member
устраняет дубликаты, поэтому, если все объекты относятся к одному типу, отображается только один тип объекта.
Однако если вы используете параметр Get-Member
InputObject для , то Get-Member
получает массив объектов System.Diagnostics.Process как единое целое. Он отображает свойства массива объектов . (Обратите внимание на символ массива ([]
) после имени типа System.Object .)
Например,
Get-Member -InputObject (Get-Process)
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
Address Method System.Object& Address(Int32 )
Clone Method System.Object Clone()
...
Этот результат может быть не таким, как вы намеревались. Но после того, как вы поймете это, вы можете использовать его. Например, все объекты массива имеют свойство Count . Его можно использовать для подсчета количества процессов, запущенных на компьютере.
Например,
(Get-Process).count
Важно помнить, что объекты, отправленные по конвейеру, доставляются по одному.
Использование собственных команд в конвейере
PowerShell позволяет включать собственные внешние команды в конвейер. Однако важно отметить, что конвейер PowerShell является объектно-ориентированным и не поддерживает необработанные байтовые данные.
Передача или перенаправление выходных данных из собственной программы, которая выводит необработанные байтовые данные, преобразует выходные данные в строки .NET. Это преобразование может привести к повреждению выходных данных необработанных данных.
В качестве обходного решения вызовите собственные команды с помощью cmd.exe /c
или sh -c
и используйте |
операторы и >
, предоставляемые собственной оболочкой.
Исследование ошибок конвейера
Если PowerShell не удается связать объекты с конвейером с параметром принимающего командлета, команда завершается ошибкой.
В следующем примере мы пытаемся переместить запись реестра из одного раздела реестра в другой. Командлет Get-Item
получает конечный путь, который затем передается в Move-ItemProperty
командлет. Команда Move-ItemProperty
задает текущий путь и имя перемещаемой записи реестра.
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
Команда завершается ошибкой, и PowerShell отображает следующее сообщение об ошибке:
Move-ItemProperty : The input object can't be bound to any parameters for
the command either because the command doesn't take pipeline input or the
input and its properties do not match any of the parameters that take
pipeline input.
At line:1 char:23
+ $a | Move-ItemProperty <<<< -Path HKLM:\Software\MyCompany\design -Name p
Для исследования используйте Trace-Command
командлет для трассировки компонента привязки параметров PowerShell. В следующем примере выполняется трассировка привязки параметра во время выполнения конвейера. Параметр PSHost отображает результаты трассировки в консоли, а параметр FilePath отправляет результаты трассировки в файл для последующего debug.txt
использования.
Trace-Command -Name ParameterBinding -PSHost -FilePath debug.txt -Expression {
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
}
Результаты трассировки являются длинными, но они показывают, что значения привязаны к командлету Get-Item
, а затем именованные значения привязываются к командлету Move-ItemProperty
.
...
BIND NAMED cmd line args [`Move-ItemProperty`]
BIND arg [HKLM:\Software\MyCompany\design] to parameter [Path]
...
BIND arg [product] to parameter [Name]
...
BIND POSITIONAL cmd line args [`Move-ItemProperty`]
...
Наконец, он показывает, что попытка привязки пути к параметру Destination объекта завершилась сбоем Move-ItemProperty
.
...
BIND PIPELINE object to parameters: [`Move-ItemProperty`]
PIPELINE object TYPE = [Microsoft.Win32.RegistryKey]
RESTORING pipeline parameter's original values
Parameter [Destination] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
...
Get-Help
Используйте командлет для просмотра атрибутов параметра Destination.
Get-Help Move-ItemProperty -Parameter Destination
-Destination <String>
Specifies the path to the destination location.
Required? true
Position? 1
Default value None
Accept pipeline input? True (ByPropertyName)
Accept wildcard characters? false
Результаты показывают, что назначение принимает входные данные конвейера только "по имени свойства". Таким образом, конвейерный объект должен иметь свойство с именем Destination.
Используйте Get-Member
для просмотра свойств объекта, поступающих из Get-Item
.
Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member
В выходных данных показано, что элемент является объектом Microsoft.Win32.RegistryKey без свойства Destination . Это объясняет, почему команда завершилась сбоем.
Параметр Path принимает входные данные конвейера по имени или значению.
Get-Help Move-ItemProperty -Parameter Path
-Path <String[]>
Specifies the path to the current location of the property. Wildcard
characters are permitted.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? true
Чтобы исправить команду, необходимо указать назначение в командлете Move-ItemProperty
и использовать для Get-Item
получения пути к элементу, который требуется переместить.
Например,
Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product
Продолжение встроенной строки
Как уже говорился, конвейер — это ряд команд, соединенных операторами конвейера (|
), обычно написанных в одной строке. Однако для удобочитаемости PowerShell позволяет разделить конвейер на несколько строк. Если оператор конвейера является последним маркером в строке, средство синтаксического анализа PowerShell присоединяет следующую строку к текущей команде, чтобы продолжить построение конвейера.
Например, следующий однострочный конвейер:
Command-1 | Command-2 | Command-3
Можно написать следующим образом:
Command-1 |
Command-2 |
Command-3
Пробелы в начале в последующих строках не являются значительными. Отступ повышает удобочитаемость.
PowerShell 7 добавляет поддержку продолжения конвейеров с символом конвейера в начале строки. В следующих примерах показано, как можно использовать эту новую функцию.
# Wrapping with a pipe at the beginning of a line (no backtick required)
Get-Process | Where-Object CPU | Where-Object Path
| Get-Item | Where-Object FullName -match "AppData"
| Sort-Object FullName -Unique
# Wrapping with a pipe on a line by itself
Get-Process | Where-Object CPU | Where-Object Path
|
Get-Item | Where-Object FullName -match "AppData"
|
Sort-Object FullName -Unique
Важно!
При интерактивной работе в оболочке вставка кода с конвейерами в начале строки выполняется только при использовании клавиш CTRL+V для вставки. Операции вставки правой кнопкой мыши вставляют строки по одной за раз. Так как строка не заканчивается символом конвейера, PowerShell считает входные данные полными и выполняет их так, как введено.