O pipeline do PowerShell é uma das características mais importantes (e úteis) do shell e linguagem de script do PowerShell. Uma vez que você compreenda o básico de como funciona e do que é capaz, pode aproveitar seu poder em suas próprias funções. Neste tutorial, é exatamente isso que você vai fazer! `
` O pipeline do PowerShell permite encadear comandos para construir um único ‘pipeline’, simplificando o código, permitindo processamento paralelo e muito mais. Se estiver pronto para aprender sobre o pipeline e construir suas próprias funções para aproveitá-lo, vamos começar! `
` **Pré-requisitos** `
` Este post será um tutorial e terá demonstrações práticas. Se quiser acompanhar, você precisará do PowerShell v3+. Este tutorial usará o Windows `PowerShell v5.1`. `
` **Compreendendo o Pipeline do PowerShell** `
` A maioria dos comandos do PowerShell recebe algum input por meio de um parâmetro. O comando recebe algum objeto como entrada, faz algo com ele e, opcionalmente, retorna algum objeto como saída. `
` Os comandos em um pipeline agem como corredores humanos em uma corrida de revezamento. Cada corredor na corrida, exceto o primeiro e o último, aceita o bastão (objetos) de seu antecessor e o passa para o próximo. `
Por exemplo, o cmdlet Stop-Service
possui um parâmetro chamado InputObject
. Esse parâmetro permite que você passe um tipo específico de objeto para o Stop-Service
representando o serviço do Windows que você deseja interromper.
Para usar o parâmetro InputObject
, você pode recuperar o objeto de serviço por meio do Get-Service
e depois passar o objeto para o parâmetro InputObject
, conforme mostrado abaixo. Este método de fornecer entrada para o cmdlet Stop-Service
através do parâmetro InputObject
funciona muito bem e realiza o trabalho necessário.
Este método de passar entrada para o comando Stop-Service
requer dois passos distintos. O PowerShell deve executar o Get-Service
primeiro, salvar a saída em uma variável e depois passar esse valor para o Stop-Service
através do parâmetro InputObject
.
Agora, compare o trecho acima com o trecho abaixo, que faz a mesma coisa. É muito mais simples porque você não precisa criar uma variável $services
ou mesmo usar o parâmetro InputObject
. Em vez disso, o PowerShell “sabe” que você pretende usar o parâmetro InputObject
. Isso é feito por meio de um conceito chamado “parameter binding”.
Agora você “encadeou” comandos usando o operador |
. Você criou um pipeline.
Mas você não precisa usar apenas dois comandos para criar um pipeline; você pode encadear quantos quiser (se os parâmetros do comando suportarem). Por exemplo, o trecho de código abaixo:
- Passa todos os objetos que o cmdlet
Get-Service
retorna para o cmdletWhere-Object
. - O cmdlet
Where-Object
então analisa a propriedadeStatus
de cada objeto e retorna apenas aqueles com um valor deRunning
. - Em seguida, cada um desses objetos é enviado para o
Select-Object
, que retorna apenas as propriedadesName
eDisplayName
dos objetos. - Como nenhum outro cmdlet aceita os objetos que o
Select-Object
produz, o comando os retorna diretamente para o console.
Os cmdlets
Where-Object
eSelect-Object
entendem como processar a entrada do pipeline por meio de um conceito chamado vinculação de parâmetros, discutido na próxima seção.
Para obter informações adicionais sobre pipelines, execute o comando
Get-Help about_pipelines
.
Vinculação de Parâmetros do Pipeline
À primeira vista, o pipeline pode parecer trivial. Afinal, está apenas passando objetos de um comando para outro. Mas na realidade, o pipeline é muito mais complicado. Os comandos aceitam entrada apenas por meio de parâmetros. O pipeline deve de alguma forma descobrir qual parâmetro usar, mesmo quando você não o define explicitamente.
A tarefa de descobrir qual parâmetro usar quando um comando recebe entrada via pipeline é conhecida como vinculação de parâmetro. Para vincular com sucesso um objeto que vem do pipeline a um parâmetro, o(s) parâmetro(s) do comando de entrada deve(m) suportar isso. Os parâmetros do comando suportam a vinculação de parâmetro do pipeline de duas maneiras; \texttt{ByValue} e/ou \texttt{ByPropertyName}.
\texttt{ByValue}
O parâmetro do comando aceita o objeto completo que entra como valor do parâmetro. Um parâmetro \texttt{ByValue} procura por um objeto de um tipo específico nos objetos de entrada. Se esse tipo de objeto for correspondido, o PowerShell assume que o objeto deve ser vinculado a esse parâmetro e o aceita.
O cmdlet \texttt{
Get-ChildItem
} possui um parâmetro chamado \texttt{Path} que aceita um tipo de objeto de string e entrada via pipeline por \texttt{ByValue}. Devido a isso, executar algo como \texttt{‘C:\Windows’ | Get-ChildItem} retorna todos os arquivos no diretório C:\Windows porque \texttt{C:\Windows} é uma string.
\texttt{ByPropertyName}
O parâmetro do comando não aceita um objeto inteiro, mas uma única propriedade desse objeto. Isso é feito não olhando para o tipo de objeto, mas sim para o nome da propriedade.
O cmdlet
Get-Process
possui um parâmetroName
configurado para aceitar entrada de pipelineByPropertyName
. Quando você passa um objeto com uma propriedadeName
para o cmdletGet-Process
, como[pscustomobject]@{Name='firefox'} | Get-Process
, o PowerShell faz a correspondência ou vinculação da propriedadeName
no objeto de entrada ao parâmetroName
e utiliza esse valor.
Descobrindo Parâmetros de Comando que Suportam o Pipeline
Como mencionado anteriormente, nem todo comando suporta entrada de pipeline. O autor do comando deve criar essa funcionalidade no desenvolvimento. O comando deve ter pelo menos um parâmetro que suporte o pipeline, usando ByValue
ou ByPropertyName
.
Como saber quais comandos e parâmetros suportam entrada de pipeline? Você poderia tentar com tentativa e erro, mas há uma maneira melhor com o sistema de ajuda do PowerShell usando o comando Get-Help
.
Por exemplo, observe o parâmetro Path
do cmdlet Get-ChildItem
abaixo. Você pode ver que ele suporta ambos os tipos de entrada de pipeline.

Uma vez que você conhece os parâmetros de comando que suportam a entrada de pipeline, você pode aproveitar essa funcionalidade, conforme mostrado abaixo.
Mas, por outro lado, o parâmetro DisplayName
no comando Get-Service
não suporta entrada de pipeline.

Construindo Sua Própria Função de Pipeline
Mesmo que os cmdlets padrão do PowerShell suportem entrada de pipeline, isso não significa que você não pode aproveitar essa funcionalidade. Felizmente, você pode construir funções que aceitam entrada de pipeline também.
Para demonstrar, vamos começar com uma função existente chamada Get-ConnectionStatus
.
- Esta função tem um único parâmetro (que não aceita entrada de pipeline) chamado
ComputerName
, que permite que você passe uma ou mais strings para ela. Você pode perceber que o parâmetroComputerName
não aceita entrada de pipeline porque não é definido como um atributo de parâmetro ([Parameter()]
). - A função então lê cada uma dessas strings e executa o cmdlet
Test-Connection
contra cada uma delas. - Para cada nome de computador passado, ele retorna um objeto com uma propriedade
ComputerName
eStatus
.
Em seguida, você invoca o Get-ConnectionStatus
passando o parâmetro ComputerName
com um ou mais nomes de host ou endereços IP como mostrado abaixo.
Passo 1: Permitindo Entrada de Pipeline
Para fazer com que esta função aceite entrada de pipeline, você deve primeiro definir o atributo de parâmetro apropriado. Este atributo pode ser ValueFromPipeline
para aceitar entrada de pipeline por valor ou ValueFromPipelineByPropertyName
para aceitar entrada de pipeline por nome de propriedade.
Para este exemplo, adicione o atributo de parâmetro ValueFromPipeline
dentro dos colchetes da definição [Parameter()]
conforme mostrado abaixo.
Neste ponto, tecnicamente, é tudo o que você precisa fazer. A função Get-ConnectionStatus
agora vinculará qualquer objeto de string passado para ele ao parâmetro ComputerName
. Mas, mesmo que o vínculo de parâmetro esteja ocorrendo, isso não significa que a função fará algo significativo com ele.
Passo 2: Adicionando um Bloco de Processamento
Quando você quer que o PowerShell processe todos os objetos que chegam pelo pipeline, você deve adicionar um bloco Process
. Este bloco diz ao PowerShell para processar cada objeto que chega pelo pipeline.
Sem um bloco
Process
, o PowerShell processará apenas o primeiro objeto que chega pelo pipeline. O blocoProcess
diz ao PowerShell para continuar processando objetos.
Adicione um bloco Process
conforme mostrado abaixo, envolvendo toda a funcionalidade da função.
Sempre envie a saída de dentro do bloco
Process
. Enviar saída de dentro do blocoProcess
“encaminha” os objetos para o pipeline, permitindo que outros comandos aceitem esses objetos do pipeline.
Passando Objetos para o Pipeline do PowerShell
Depois de ter um bloco Process
definido na função acima, agora você pode chamar a função passando valores para o parâmetro ComputerName
via pipeline conforme mostrado abaixo.
Neste ponto, você pode alavancar o verdadeiro poder do pipeline e começar a incorporar mais comandos na mistura. Por exemplo, talvez você tenha um arquivo de texto, C:\Test\computadores.txt, com uma linha de endereços IP separados por uma nova linha como abaixo.
Você poderia então usar o cmdlet Get-Content
para ler cada um desses endereços IP no arquivo de texto e passá-los diretamente para a função Get-ConnectionStatus
.
Levando essa configuração um passo adiante, você poderia encaminhar os objetos que Get-ConnectionStatus
retorna diretamente para o cmdlet ForEach-Object
.
O código abaixo:
- Lê todos os nomes de computador no arquivo de texto e os passa para a função
Get-ConnectionStatus
. - A função
Get-ConnectionStatus
processa cada nome de computador e retorna um objeto com as propriedadesComputerName
eStatus
. - Em seguida, a função
Get-ConnectionStatus
passa cada objeto para o cmdletForEach-Object
, que então retorna uma única string colorida de ciano com um status legível para humanos.
Se a entrada de pipeline não estiver habilitada no parâmetro
ComputerName
ou seGet-ConnectionStatus
não retornar um objeto dentro do blocoProcess
, o PowerShell não retornará nenhum status para o console até que todos os objetos (endereços IP) sejam processados.
Vinculação de Pipeline pelo Nome da Propriedade
Até agora, o cmdlet Get-ConnectionStatus
está configurado para aceitar entrada de pipeline por valor (ValueFromPipeline
) ao aceitar um array de strings como '127.0.0.1', '192.168.1.100'
. Essa função também funcionaria como esperado se a entrada fosse recebida de um arquivo CSV em vez de um arquivo de texto de endereços IP?
Talvez você tenha um arquivo CSV que se parece com o abaixo em C:\Test\pc-list.csv.
Observe que o campo
ComputerName
no arquivo CSV é o mesmo nome que o parâmetroComputerName
doGet-ConnnectionStatus
.
Se você tentar importar o CSV e passá-lo pelo pipeline para Get-ConnectionStatus
, a função retornará um resultado inesperado na coluna ComputerName
.
Você consegue adivinhar o que deu errado? Afinal, o nome do parâmetro corresponde, então por que o pipeline do PowerShell não vinculou a saída que o Import-CSV
retornou ao parâmetro ComputerName
no Get-ConnectionStatus
? Porque você precisa do atributo do parâmetro ValueFromPipelineByPropertyName
.
Até o momento, o parâmetro ComputerName
da função possui uma definição de parâmetro que se parece com [Parameter(ValueFromPipeline)]
. Portanto, você deve adicionar ValueFromPipelineByPropertyName
para configurar o parâmetro ComputerName
para suportar entrada por Nome de Propriedade, como mostrado abaixo.
Depois de ter suporte ao pipeline por Nome de Propriedade, você diz ao PowerShell para começar a olhar para os nomes das propriedades do objeto e o tipo de objeto. Após fazer essa alteração, você deve então ver a saída esperada.
Resumo
Neste tutorial, você aprendeu como o pipeline do PowerShell funciona, como ele vincula parâmetros e até mesmo como criar sua própria função com suporte ao pipeline do PowerShell.
Mesmo que as funções funcionem sem o pipeline, elas não “transmitem” objetos de um comando para outro e simplificam o código.
Você consegue pensar em uma função que você escreveu, ou talvez esteja prestes a escrever, que pode se beneficiar tornando-a pronta para o pipeline?