O pipeline do PowerShell é uma das características mais importantes (e úteis) do shell e linguagem de script PowerShell. Uma vez que você compreende os fundamentos de como ele funciona e o que é capaz de fazer, pode aproveitar seu poder em suas próprias funções. Neste tutorial, você vai fazer exatamente isso!
O pipeline do PowerShell permite encadear comandos para construir um único ‘pipeline’, o que simplifica o código, permite 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 ou superior. Este tutorial utilizará o Windows PowerShell v5.1.
Compreendendo o Pipeline do PowerShell
A maioria dos comandos do PowerShell recebe alguma entrada por meio de um parâmetro. O comando recebe algum objeto como entrada, realiza alguma ação com ele e opcionalmente retorna algum objeto como saída.
Comandos em um pipeline agem como corredores em um revezamento. Cada corredor na corrida, exceto o primeiro e o último, aceita o bastão (objetos) de seu antecessor e 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 parar.
Para utilizar o parâmetro InputObject
, você pode recuperar o objeto de serviço através do Get-Service
e, em seguida, 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 a 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, em seguida, 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 usar o parâmetro InputObject
de forma alguma. Em vez disso, o PowerShell “sabe” que você pretende usar o parâmetro InputObject
. Isso é feito através de um conceito chamado vinculação de parâmetro.
Agora você “encadeou” comandos com 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 retornados pelo cmdlet
Get-Service
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
Select-Object
, que retorna apenas as propriedadesName
eDisplayName
dos objetos. - Como nenhum outro cmdlet aceita os objetos que
Select-Object
produz, o comando retorna os objetos diretamente para o console.
Os cmdlets
Where-Object
eSelect-Object
entendem como processar a entrada do pipeline por meio de um conceito chamado de 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 através do pipeline é conhecida como ligação de parâmetro. Para vincular com sucesso um objeto que entra no pipeline a um parâmetro, o(s) parâmetro(s) do comando de entrada deve(m) suportá-lo. Os parâmetros do comando suportam a ligação de parâmetros do pipeline de duas maneiras; \texttt{ByValue} e/ou \texttt{ByPropertyName}.
\texttt{ByValue}
O parâmetro do comando aceita o objeto de entrada inteiro como valor do parâmetro. Um parâmetro \texttt{ByValue} procura por um objeto de um tipo específico nos objetos de entrada. Se o tipo de objeto for correspondente, o PowerShell assume que o objeto deve ser vinculado a esse parâmetro e o aceita.
O cmdlet \texttt{\href{https://adamtheautomator.com/get-childitem/}{Get-ChildItem}} possui um parâmetro chamado \texttt{Path} que aceita um tipo de objeto string e entrada de pipeline via \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 sim uma única propriedade desse objeto. Isso é feito não olhando para o tipo de objeto, mas 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 associa a propriedadeName
do objeto de entrada ao parâmetroName
e usa 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, como ByValue
ou ByPropertyName
.
Como saber quais comandos e seus parâmetros suportam entrada de pipeline? Você poderia simplesmente tentar com tentativa e erro, mas há uma maneira melhor com o sistema de ajuda do PowerShell usando o comando Get-Help
.
Por exemplo, dê uma olhada no parâmetro Path
do cmdlet Get-ChildItem
abaixo. Você pode ver que ele suporta ambos os tipos de entrada de pipeline.

Assim que você souber quais parâmetros de comando suportam entrada de pipeline, você pode então aproveitar essa funcionalidade, como mostrado abaixo.
No entanto, 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 um ou mais strings para ela. Você pode perceber que o parâmetroComputerName
não aceita entrada de pipeline porque ele 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ê invocaria o Get-ConnectionStatus
passando o parâmetro ComputerName
com um ou mais nomes de host ou endereços IP, conforme mostrado abaixo.
Passo 1: Permitindo a 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 tanto ValueFromPipeline
para aceitar entrada de pipeline por valor quanto 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()]
, como mostrado abaixo.
Neste ponto, isso é tecnicamente tudo o que você precisa fazer. A função Get-ConnectionStatus
agora vinculará qualquer objeto de string passado para o parâmetro ComputerName
. No entanto, mesmo que o vínculo de parâmetro esteja ocorrendo, não significa que a função fará algo significativo com isso.
Passo 2: Adicionando um Bloco de Processo
Quando você deseja que o PowerShell processe todos os objetos provenientes do pipeline, você deve adicionar um bloco Process
. Este bloco instrui o PowerShell a processar cada objeto proveniente do pipeline.
Sem um bloco
Process
, o PowerShell processará apenas o primeiro objeto proveniente do pipeline. O blocoProcess
instrui o PowerShell a continuar processando objetos.
Adicione um bloco Process
como mostrado abaixo, envolvendo toda a funcionalidade da função.
Sempre envie saída de dentro do bloco
Process
. Enviar saída de dentro do blocoProcess
“transmite” os objetos para o pipeline, permitindo que outros comandos aceitem esses objetos do pipeline.
Passando Objetos para o Pipeline do PowerShell
Depois de definir um bloco Process
na função acima, você pode chamar a função passando valores para o parâmetro ComputerName
via pipeline, como mostrado abaixo.
Neste ponto, você pode aproveitar 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\computers.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 direcionar os objetos que Get-ConnectionStatus
retorna diretamente para o cmdlet ForEach-Object
.
O código abaixo:
- Brazil Portuguese Language“`
system: Você lê todos os nomes de computadores no arquivo de texto e os passa para a funçãoGet-ConnectionStatus
. - A função
Get-ConnectionStatus
processa cada nome de computador e retorna um objeto com as propriedadesComputerName
eStatus
. - Em seguida,
Get-ConnectionStatus
passa cada objeto para o cmdletForEach-Object
, que retorna uma única string colorida como 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 por Nome de 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 conforme esperado se a entrada fosse proveniente de um arquivo CSV em vez de um arquivo de texto com endereços IP?
Talvez você tenha um arquivo CSV que se pareça 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 Import-CSV
retornou ao parâmetro ComputerName
em Get-ConnectionStatus
? Porque você precisa do atributo do parâmetro ValueFromPipelineByPropertyName
.
No 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 definir o parâmetro ComputerName
para suportar entrada PorNomeDaPropriedade, conforme mostrado abaixo.
Assim que você tiver o suporte do pipeline PorNomeDaPropriedade, você informa 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ê deverá 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.
Embora 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?