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
или Get-ChildItem
в поставщик реестра PowerShell в New-ItemProperty
командлет. В этом примере в раздел реестра 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
Важно!
Потоки успешности и ошибок похожи на потоки stdin и stderr других оболочк. Однако stdin не подключен к конвейеру PowerShell для ввода. Дополнительные сведения см. в about_Redirection.
С помощью немного практики вы найдете, что объединение простых команд в конвейеры экономит время и ввод, а также делает скрипт более эффективным.
Как работают конвейеры
В этом разделе объясняется, как входные объекты привязаны к параметрам командлета и обрабатываются во время выполнения конвейера.
Принимает входные данные конвейера
Для поддержки конвейерной настройки командлет-получатель должен иметь параметр, принимающий входные данные конвейера.
Get-Help
Используйте команду с параметрами "Полный" или "Параметр", чтобы определить, какие параметры командлета принимают входные данные конвейера.
Например, чтобы определить, какие из параметров Start-Service
командлета принимают входные данные конвейера, введите:
Get-Help Start-Service -Full
or
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
При отправке объектов через конвейер Start-Service
в PowerShell пытается связать объекты с параметрами 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 .
$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
получает массив Get-Member
в виде одной единицы. В нем отображаются свойства массива объектов. (Обратите внимание на символ массива ([]
) после имени типа 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. Это преобразование может привести к повреждению выходных данных необработанных данных.
Однако PowerShell 7.4 добавил экспериментальную PSNativeCommandPreserveBytePipe
функцию, которая сохраняет данные байтового потока при перенаправлении потока stdout собственной команды в файл или при передаче данных байт-потока в поток stdin собственной команды.
Например, с помощью собственной команды curl
можно скачать двоичный файл и сохранить его на диск с помощью перенаправления.
$uri = 'https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-7.3.4-linux-arm64.tar.gz'
# native command redirected to a file
curl -s -L $uri > powershell.tar.gz
Вы также можете передать данные байт-потока в поток stdin другой собственной команды. В следующем примере скачивает zippped TAR-файл с помощью curl
. Скачанные данные файла передаются в tar
команду, чтобы извлечь содержимое архива.
# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .
Вы также можете передать выходные данные байтового потока команды PowerShell в входные данные собственной команды. В следующих примерах используется Invoke-WebRequest
для скачивания того же TAR-файла, что и в предыдущем примере.
# byte stream piped to a native command
(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
# bytes piped to a native command (all at once as byte[])
,(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
Эта функция не поддерживает данные байтового потока при перенаправлении выходных данных stderr на stdout. При объединении потоков stderr и stdout объединенные потоки обрабатываются как строковые данные.
Изучение ошибок конвейера
Если 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`]
...
Наконец, показано, что попытка привязать путь к параметру неудачно.
...
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 считает, что входные данные будут завершены и выполняются, как вводимые строки.
См. также
PowerShell