Share via


Sobre pipelines

Descrição breve

Combinando comandos em pipelines no PowerShell

Descrição longa

Um pipeline é uma série de comandos conectados por operadores de pipeline (|) (ASCII 124). Cada operador de pipeline envia os resultados do comando anterior para o próximo comando.

A saída do primeiro comando pode ser enviada para processamento como entrada para o segundo comando. E essa saída pode ser enviada para outro comando. O resultado é uma cadeia de comandos complexa ou pipeline composto por uma série de comandos simples.

Por exemplo,

Command-1 | Command-2 | Command-3

Neste exemplo, os objetos que Command-1 emitem são enviados para Command-2. Command-2 processa os objetos e os envia para Command-3. Command-3 processa os objetos e os envia pelo pipeline. Como não há mais comandos no pipeline, os resultados são exibidos no console.

Em um pipeline, os comandos são processados na ordem da esquerda para a direita. O processamento é tratado como uma única operação e a saída é exibida conforme é gerada.

Veja um exemplo simples. O comando a seguir obtém o processo do Bloco de Notas e o interrompe.

Por exemplo,

Get-Process notepad | Stop-Process

O primeiro comando usa o Get-Process cmdlet para obter um objeto que representa o processo do Bloco de Notas. Ele usa um operador de pipeline (|) para enviar o objeto de processo para o Stop-Process cmdlet, que interrompe o processo do Bloco de Notas. Observe que o Stop-Process comando não tem um parâmetro Name ou ID para especificar o processo, pois o processo especificado é enviado por meio do pipeline.

Este exemplo de pipeline obtém os arquivos de texto no diretório atual, seleciona apenas os arquivos com mais de 10.000 bytes de comprimento, classifica-os por comprimento e exibe o nome e o comprimento de cada arquivo em uma tabela.

Get-ChildItem -Path *.txt |
  Where-Object {$_.length -gt 10000} |
    Sort-Object -Property length |
      Format-Table -Property name, length

Esse pipeline consiste em quatro comandos na ordem especificada. A ilustração a seguir mostra a saída de cada comando conforme ela é passada para o próximo comando no pipeline.

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

Usando pipelines

A maioria dos cmdlets do PowerShell foi projetada para dar suporte a pipelines. Na maioria dos casos, você pode redirecionar os resultados de um cmdlet Get para outro cmdlet do mesmo substantivo. Por exemplo, você pode redirecionar a saída do Get-Service cmdlet para os Start-Service cmdlets ou Stop-Service .

Este pipeline de exemplo inicia o serviço WMI no computador:

Get-Service wmi | Start-Service

Por outro exemplo, você pode redirecionar a saída de Get-Item ou Get-ChildItem dentro do provedor de registro do PowerShell para o New-ItemProperty cmdlet. Este exemplo adiciona uma nova entrada do Registro, NoOfEmployees, com um valor de 8124, à chave do Registro MyCompany .

Get-Item -Path HKLM:\Software\MyCompany |
  New-ItemProperty -Name NoOfEmployees -Value 8124

Muitos dos cmdlets do utilitário, como Get-Member, Where-Object, Sort-Object, Group-Objecte Measure-Object são usados quase exclusivamente em pipelines. Você pode redirecionar qualquer tipo de objeto para esses cmdlets. Este exemplo mostra como classificar todos os processos no computador pelo número de identificadores abertos em cada processo.

Get-Process | Sort-Object -Property handles

Você pode redirecionar objetos para os cmdlets de formatação, exportação e saída, como Format-List, Format-Table, Export-Clixml, Export-CSVe Out-File.

Este exemplo mostra como usar o Format-List cmdlet para exibir uma lista de propriedades de um objeto de processo.

Get-Process winlogon | Format-List -Property *

Com um pouco de prática, você descobrirá que combinar comandos simples em pipelines economiza tempo e digitação e torna o script mais eficiente.

Como os pipelines funcionam

Esta seção explica como os objetos de entrada são associados a parâmetros de cmdlet e processados durante a execução do pipeline.

Aceita entrada de pipeline

Para dar suporte à pipelining, o cmdlet de recebimento deve ter um parâmetro que aceite a entrada de pipeline. Use o Get-Help comando com as opções Full ou Parameter para determinar quais parâmetros de um cmdlet aceitam entrada de pipeline.

Por exemplo, para determinar quais dos parâmetros do Start-Service cmdlet aceitam entrada de pipeline, digite:

Get-Help Start-Service -Full

ou

Get-Help Start-Service -Parameter *

A ajuda para o Start-Service cmdlet mostra que apenas os parâmetros InputObject e Name aceitam entrada de pipeline.

-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

Quando você envia objetos por meio do pipeline para Start-Service, o PowerShell tenta associar os objetos aos parâmetros InputObject e Name .

Métodos de aceitação de entrada de pipeline

Os parâmetros de cmdlets podem aceitar a entrada de pipeline de uma das duas maneiras diferentes:

  • ByValue: o parâmetro aceita valores que correspondem ao tipo .NET esperado ou que podem ser convertidos nesse tipo.

    Por exemplo, o parâmetro Name de Start-Service aceita entrada de pipeline por valor. Ele pode aceitar objetos ou objetos de cadeia de caracteres que podem ser convertidos em cadeias de caracteres.

  • ByPropertyName: o parâmetro aceita a entrada somente quando o objeto de entrada tem uma propriedade de mesmo nome que o parâmetro .

    Por exemplo, o parâmetro Name de Start-Service pode aceitar objetos que têm uma propriedade Name . Para listar as propriedades de um objeto, redirecione-o para Get-Member.

Alguns parâmetros podem aceitar objetos por valor ou nome de propriedade, facilitando a entrada do pipeline.

Associação de parâmetro

Quando você redireciona objetos de um comando para outro comando, o PowerShell tenta associar os objetos canalizados a um parâmetro do cmdlet de recebimento.

O componente de associação de parâmetros do PowerShell associa os objetos de entrada aos parâmetros de cmdlet de acordo com os seguintes critérios:

  • O parâmetro deve aceitar a entrada de um pipeline.
  • O parâmetro deve aceitar o tipo de objeto que está sendo enviado ou um tipo que possa ser convertido no tipo esperado.
  • O parâmetro não foi usado no comando .

Por exemplo, o Start-Service cmdlet tem muitos parâmetros, mas apenas dois deles, Name e InputObject aceitam entrada de pipeline. O parâmetro Name usa cadeias de caracteres e o parâmetro InputObject usa objetos de serviço. Portanto, você pode canalizar cadeias de caracteres, objetos de serviço e objetos com propriedades que podem ser convertidas em objetos de cadeia de caracteres ou de serviço.

O PowerShell gerencia a associação de parâmetros da forma mais eficiente possível. Você não pode sugerir ou forçar o PowerShell a se associar a um parâmetro específico. O comando falhará se o PowerShell não puder associar os objetos canalizados.

Para obter mais informações sobre como solucionar problemas de erros de associação, consulte Investigando erros de pipeline mais adiante neste artigo.

Processamento único

A canalização de objetos para um comando é muito semelhante ao uso de um parâmetro do comando para enviar os objetos. Vamos examinar um exemplo de pipeline. Neste exemplo, usamos um pipeline para exibir uma tabela de objetos de serviço.

Get-Service | Format-Table -Property Name, DependentServices

Funcionalmente, isso é como usar o parâmetro InputObject de Format-Table para enviar a coleção de objetos.

Por exemplo, podemos salvar a coleção de serviços em uma variável que é passada usando o parâmetro InputObject .

$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices

Ou podemos inserir o comando no parâmetro InputObject .

Format-Table -InputObject (Get-Service) -Property Name, DependentServices

No entanto, há uma diferença importante. Quando você redireciona vários objetos para um comando, o PowerShell envia os objetos para o comando um de cada vez. Quando você usa um parâmetro de comando, os objetos são enviados como um único objeto de matriz. Essa pequena diferença tem consequências significativas.

Ao executar um pipeline, o PowerShell enumera automaticamente qualquer tipo que implemente a IEnumerable interface e envie os membros por meio do pipeline um de cada vez. A exceção é [hashtable], que requer uma chamada para o GetEnumerator() método .

Nos exemplos a seguir, uma matriz e uma tabela de hash são canalizadas para o Measure-Object cmdlet para contar o número de objetos recebidos do pipeline. A matriz tem vários membros e o hash tem vários pares chave-valor. Somente a matriz é enumerada uma de cada vez.

@(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 :

Da mesma forma, se você redirecionar vários objetos de processo do Get-Process cmdlet para o cmdlet, o Get-Member PowerShell enviará cada objeto de processo, um de cada vez, para Get-Member. Get-Member exibe a classe .NET (tipo) dos objetos de processo e suas propriedades e métodos.

Get-Process | Get-Member
TypeName: System.Diagnostics.Process

Name      MemberType     Definition
----      ----------     ----------
Handles   AliasProperty  Handles = Handlecount
Name      AliasProperty  Name = ProcessName
NPM       AliasProperty  NPM = NonpagedSystemMemorySize
...

Observação

Get-Member elimina duplicatas, portanto, se os objetos forem todos do mesmo tipo, ele exibirá apenas um tipo de objeto.

No entanto, se você usar o parâmetro InputObject de Get-Member, Get-Member receberá uma matriz de objetos System.Diagnostics.Process como uma única unidade. Ele exibe as propriedades de uma matriz de objetos. (Observe o símbolo da matriz ([]) após o nome do tipo System.Object .)

Por exemplo,

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()
...

Esse resultado pode não ser o que você pretendia. Mas depois de entender, você pode usá-lo. Por exemplo, todos os objetos de matriz têm uma propriedade Count . Você pode usar isso para contar o número de processos em execução no computador.

Por exemplo,

(Get-Process).count

É importante lembrar que os objetos enviados pelo pipeline são entregues um de cada vez.

Investigando erros de pipeline

Quando o PowerShell não pode associar os objetos canalizados a um parâmetro do cmdlet de recebimento, o comando falha.

No exemplo a seguir, tentamos mover uma entrada do Registro de uma chave do Registro para outra. O Get-Item cmdlet obtém o caminho de destino, que é canalizado para o Move-ItemProperty cmdlet. O Move-ItemProperty comando especifica o caminho atual e o nome da entrada do Registro a ser movida.

Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product

O comando falha e o PowerShell exibe a seguinte mensagem de erro:

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

Para investigar, use o Trace-Command cmdlet para rastrear o componente de associação de parâmetros do PowerShell. O exemplo a seguir rastreia a associação de parâmetros enquanto o pipeline está em execução. O parâmetro PSHost exibe os resultados do rastreamento no console e o parâmetro FilePath envia os resultados do rastreamento para o debug.txt arquivo para referência posterior.

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
}

Os resultados do rastreamento são longos, mas mostram os valores associados ao Get-Item cmdlet e, em seguida, os valores nomeados sendo associados ao Move-ItemProperty cmdlet.

...
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`]
...

Por fim, ele mostra que a tentativa de associar o caminho ao parâmetro Destination de Move-ItemProperty falhou.

...
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
...

Use o Get-Help cmdlet para exibir os atributos do parâmetro 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

Os resultados mostram que Destination usa a entrada do pipeline apenas "por nome da propriedade". Portanto, o objeto canalizado deve ter uma propriedade chamada Destination.

Use Get-Member para ver as propriedades do objeto provenientes de Get-Item.

Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member

A saída mostra que o item é um objeto Microsoft.Win32.RegistryKey que não tem uma propriedade Destination . Isso explica por que o comando falhou.

O parâmetro Path aceita a entrada de pipeline por nome ou por valor.

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

Para corrigir o comando, devemos especificar o destino no Move-ItemProperty cmdlet e usar Get-Item para obter o Caminho do item que desejamos mover.

Por exemplo,

Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product

Continuação de linha intrínseca

Como já discutido, um pipeline é uma série de comandos conectados por operadores de pipeline (|), geralmente escritos em uma única linha. No entanto, para facilitar a leitura, o PowerShell permite dividir o pipeline em várias linhas. Quando um operador de pipe é o último token na linha, o analisador do PowerShell une a próxima linha ao comando atual para continuar a construção do pipeline.

Por exemplo, o seguinte pipeline de linha única:

Command-1 | Command-2 | Command-3

pode ser escrito como:

Command-1 |
  Command-2 |
    Command-3

Os espaços à esquerda nas linhas subsequentes não são significativos. O recuo aumenta a legibilidade.

Consulte Também

about_PSReadLine

about_Objects

about_Parameters

about_Command_Syntax

about_ForEach