Сведения о конвейерах
Краткое описание
Объединение команд в конвейеры в 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 *
Немного потренируясь, вы обнаружите, что объединение простых команд в конвейеры экономит время и ввод текста, а также делает скрипты более эффективными.
Принцип работы конвейеров
В этом разделе объясняется, как входные объекты привязываются к параметрам командлета и обрабатываются во время выполнения конвейера.
Принимает входные данные конвейера
Для поддержки конвейерной передачи принимающий командлет должен иметь параметр, принимающий входные данные конвейера. 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
При отправке объектов через конвейер в 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 для отправки 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
интерфейс, и отправляет члены через конвейер по одному за раз. Исключением является [hashtable]
, для которого требуется GetEnumerator()
вызов метода .
В следующих примерах массив и хэш-сводка передаются командлету 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 не удается связать переданные объекты с параметром принимающего командлета, команда завершается ошибкой.
В следующем примере мы пытаемся переместить запись реестра из одного раздела реестра в другой. Командлет 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
Пробелы в последующих строках не являются значительными. Отступ повышает удобочитаемость.