O pipeline: introdução
Esta aula introduz o pipeline do PowerShell, um recurso que permite encadear comandos passando objetos .NET entre eles, ao contrário de shells Unix que passam apenas texto. Você aprenderá a usar o operador |, entenderá a diferença fundamental entre os pipelines e verá exemplos práticos que demonstram a potência dessa abordagem.
O pipeline é um dos recursos mais poderosos e distintivos do PowerShell. Diferente de shells tradicionais que passam apenas texto entre comandos, o PowerShell transmite objetos .NET completos, permitindo que você manipule dados estruturados de forma direta e eficiente. Esta aula vai te mostrar como usar o pipeline, como ele funciona por baixo dos panos e por que ele torna a automação no Windows (e agora também no Linux) muito mais produtiva.
Se você vem do Bash ou do CMD, pode pensar no pipeline como uma esteira rolante onde cada comando recebe a saída do anterior, mas com um diferencial crucial: os objetos preservam suas propriedades e métodos, eliminando a necessidade de fazer parsing de texto. Vamos explorar isso em detalhes.
Passando objetos (não texto)
No PowerShell, praticamente tudo é um objeto. Quando você executa um comando como Get-Process, ele produz uma lista de objetos do tipo System.Diagnostics.Process, cada um com propriedades como Name, Id, CPU, etc. Esses objetos são passados pelo pipeline intactos.
Isso significa que o próximo comando pode acessar diretamente essas propriedades sem precisar extrair texto de uma string. Por exemplo, se você quiser filtrar processos que estão usando mais de 100 MB de memória, pode fazer:
Get-Process | Where-Object { $_.WorkingSet64 -gt 100MB }Aqui, Where-Object recebe cada objeto processo e avalia uma expressão usando $_, que representa o objeto atual no pipeline. O PowerShell entende a propriedade WorkingSet64 diretamente, sem precisar de regex ou manipulação de string.
O operador |
O operador pipeline é o símbolo de pipe (|). Ele conecta a saída de um comando à entrada do próximo. Sintaticamente, é simples: Comando1 | Comando2 | Comando3. Cada comando processa os objetos e os passa adiante.
Internamente, o PowerShell executa os comandos em sequência, mas de forma eficiente: ele começa a processar objetos assim que eles são produzidos, sem esperar que o primeiro comando termine completamente. Isso é chamado de processamento de fluxo (streaming) e é essencial para trabalhar com grandes volumes de dados. Por exemplo, o comando Get-Content arquivo.txt | Where-Object { $_ -match 'erro' } lê linha por linha e filtra em tempo real, sem carregar o arquivo inteiro na memória.
Além disso, muitos cmdlets aceitam entrada por pipeline de duas formas: por valor (o objeto inteiro) ou por nome de propriedade. Você pode ver isso com Get-Help Get-Service -Parameter *. Por exemplo, Get-Process | Stop-Process funciona porque Stop-Process aceita um objeto processo diretamente pelo pipeline.
Diferença para shells Unix
Em shells Unix (Bash, Zsh), o pipeline também usa |, mas a comunicação é baseada em texto. A saída de um comando é uma sequência de bytes (texto) que é passada para o próximo comando, que precisa interpretar esse texto. Isso força o uso de ferramentas como grep, awk, sed para extrair informações, o que é frágil e depende de formatação.
No PowerShell, os objetos são passados como tipos .NET. Isso traz vantagens enormes: acesso a propriedades tipadas (números, datas, booleanos), métodos diretamente invocáveis, e integração com APIs .NET. Por exemplo, para obter a data de modificação de um arquivo:
Get-ChildItem arquivo.txt | ForEach-Object { $_.LastWriteTime }Em Bash, você teria que usar stat -c %Y arquivo.txt ou date -r arquivo.txt e depois converter para o formato desejado. O PowerShell lida com isso nativamente.
Outra diferença: no PowerShell, você pode usar Export-Csv, ConvertTo-Json, Select-Object diretamente no pipeline para transformar objetos em outros formatos. No Unix, você precisaria de comandos externos ou scripts complexos.
Exemplos
Vamos ver alguns exemplos práticos que mostram o poder do pipeline orientado a objetos.
Exemplo 1: Listar processos com mais de 100 MB de memória
Get-Process | Where-Object { $_.WorkingSet64 -gt 100MB } | Select-Object Name, Id, @{Name='MemoryMB'; Expression={[math]::Round($_.WorkingSet64/1MB,2)}}Este comando filtra processos por memória e cria uma nova propriedade calculada MemoryMB.
Exemplo 2: Parar serviços que estão parados (Stopped) e reiniciá-los
Get-Service | Where-Object { $_.Status -eq 'Stopped' } | Start-ServiceAqui, o pipeline passa objetos de serviço diretamente para Start-Service, que os inicia.
Exemplo 3: Exportar eventos do log do sistema para CSV
Get-EventLog -LogName System -EntryType Error -Newest 10 | Export-Csv -Path erros.csv -NoTypeInformationOs objetos de evento são convertidos em linhas CSV automaticamente.
Exemplo 4: Encontrar arquivos grandes e ordená-los
Get-ChildItem -Path C:\ -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.Length -gt 100MB } | Sort-Object Length -Descending | Select-Object FullName, LengthNote o uso de ErrorAction SilentlyContinue para ignorar pastas sem acesso.
Exemplo 5: Usar o pipeline com expressões lambda
1..10 | ForEach-Object { $_ * $_ }Gera os quadrados de 1 a 10. O pipeline funciona até com números, pois são objetos Int32.
Boas práticas
- Evite quebrar o pipeline com parênteses ou atribuições desnecessárias – deixe os objetos fluírem.
- Use
$_dentro de blocos de script para referenciar o objeto atual. - Prefira cmdlets nativos a comandos externos quando possível, pois eles mantêm a tipagem.
- Lembre-se de que o pipeline é um fluxo, então comandos como
Sort-Objectprecisam receber todos os objetos antes de ordenar, o que pode consumir memória. - Use
Select-Object -First 10para limitar a saída e evitar processamento desnecessário.
Referências
- About Pipelines - Microsoft Docs
- PowerShell 101: Pipelines
- Everything you wanted to know about pipelines
- About Objects
- SS64 PowerShell Pipeline
- Understanding the PowerShell Pipeline - Scripting Blog
Exercícios
Crie um pipeline que liste todos os processos cujo nome começa com 'p' e exiba apenas o nome e o ID.
✓ Resposta:Get-Process | Where-Object { $_.Name -like 'p*' } | Select-Object Name, IdUse o pipeline para obter os 5 serviços que estão em execução (Running) e exibir seu nome e status.
✓ Resposta:Get-Service | Where-Object { $_.Status -eq 'Running' } | Select-Object Name, Status -First 5Escreva um comando que liste todos os arquivos .txt no diretório atual e mostre o nome e o tamanho em KB, arredondado para 2 casas decimais.
✓ Resposta:Get-ChildItem *.txt | Select-Object Name, @{Name='SizeKB'; Expression={[math]::Round($_.Length/1KB,2)}}Use o pipeline para parar todos os processos chamados 'notepad' (se existirem).
✓ Resposta:Get-Process -Name notepad -ErrorAction SilentlyContinue | Stop-ProcessCrie um pipeline que gere uma lista de números de 1 a 100, filtre apenas os pares e calcule o quadrado de cada um, exibindo o resultado.
✓ Resposta:1..100 | Where-Object { $_ % 2 -eq 0 } | ForEach-Object { $_ * $_ }