Поделиться через


Сведения о конвейерах

Краткое описание

Объединение команд в конвейеры в 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-ServiceStart-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 *

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

Принцип работы конвейеров

В этом разделе объясняется, как входные объекты привязываются к параметрам командлета и обрабатываются во время выполнения конвейера.

Принимает входные данные конвейера

Для поддержки конвейерной конвейерной передачи принимающий командлет должен иметь параметр, который принимает входные данные конвейера. 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 интерфейс , и отправляет члены через конвейер по одному за раз. Исключением является [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-MemberInputObject для , то 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

Пробелы в последующих строках не являются значительными. Отступ повышает удобочитаемость.

См. также:

about_PSReadLine

about_Objects

about_Parameters

about_Command_Syntax

about_ForEach