O pipeline é um dos recursos mais poderosos do PowerShell. Diferente de shells tradicionais que passam apenas texto, o PowerShell passa objetos .NET completos entre cmdlets. Isso significa que você pode usar cmdlets como Where-Object, Select-Object e ForEach-Object para filtrar, selecionar e transformar dados sem perder a estrutura original.

Nesta aula, você aprenderá como os objetos fluem pelo pipeline, como as propriedades são preservadas e como encadear múltiplos cmdlets para criar soluções elegantes. Vamos explorar exemplos práticos que demonstram a diferença entre pipelines textuais e orientados a objetos.

Como objetos fluem

Quando você executa um comando como Get-Process | Stop-Process, o PowerShell executa o cmdlet da esquerda (Get-Process) que produz objetos do tipo System.Diagnostics.Process. Cada objeto é enviado individualmente para o próximo cmdlet (Stop-Process), que o recebe como entrada. Esse fluxo é síncrono e orientado a objetos, permitindo que o segundo cmdlet acesse diretamente propriedades e métodos do objeto.

O pipeline não espera que todos os objetos sejam gerados antes de começar a processar. Ele funciona de forma streaming: assim que um objeto está pronto, ele é passado adiante. Isso reduz o uso de memória e permite processar conjuntos de dados grandes de forma eficiente. Por exemplo, 1..1000000 | ForEach-Object { $_ * 2 } processa um milhão de números sem armazenar todos na memória ao mesmo tempo.

Propriedades preservadas

Como os objetos passam pelo pipeline intactos, todas as suas propriedades e métodos permanecem acessíveis. Você pode usar Select-Object para escolher propriedades específicas, Where-Object para filtrar baseado em valores de propriedades e Sort-Object para ordenar. Por exemplo:

Get-Process | Where-Object { $_.CPU -gt 10 } | Select-Object Name, CPU, Id

Neste comando, Get-Process retorna objetos Process. O Where-Object filtra aqueles cuja propriedade CPU é maior que 10. O Select-Object então cria um novo objeto personalizado com apenas as propriedades Name, CPU e Id. Note que o objeto original não é destruído; um novo objeto é criado a partir das propriedades selecionadas.

Outra forma de trabalhar com propriedades é usando Format-Table ou Format-List para exibição, mas lembre-se de que esses cmdlets convertem objetos em texto, quebrando o pipeline de objetos. Para manter a estrutura, use Select-Object ou ForEach-Object.

Encadeando cmdlets

O pipeline permite encadear vários cmdlets, formando uma sequência de processamento. Cada cmdlet recebe objetos do anterior, processa e os envia para o próximo. Você pode combinar cmdlets de filtro, seleção, ordenação e agrupamento. Por exemplo:

Get-Service | Where-Object { $_.Status -eq 'Running' } | Sort-Object DisplayName | Select-Object Name, DisplayName, Status

Isso obtém todos os serviços, filtra apenas os em execução, ordena pelo nome de exibição e seleciona três propriedades. A ordem dos cmdlets importa: coloque filtros o mais cedo possível para reduzir o número de objetos processados.

Você também pode usar ForEach-Object para executar ações em cada objeto, como converter ou modificar dados. Por exemplo:

Get-Process | ForEach-Object { $_.Name.ToUpper() }

Isso retorna uma lista de nomes de processos em maiúsculas. O pipeline é flexível: você pode até mesmo passar objetos para cmdlets que aceitam entrada por pipeline, como Stop-Process ou Remove-Item.

Exemplos

Vamos ver alguns exemplos completos que mostram o poder do pipeline orientado a objetos.

Exemplo 1: Encontrar processos que consomem mais de 100 MB de memória

Get-Process | Where-Object { $_.WorkingSet64 -gt 100MB } | Sort-Object WorkingSet64 -Descending | Select-Object Name, Id, @{Name='Memory (MB)'; Expression={[math]::Round($_.WorkingSet64 / 1MB, 2)}}

Aqui usamos Where-Object para filtrar, Sort-Object para ordenar e Select-Object com uma propriedade calculada para exibir a memória em megabytes.

Exemplo 2: Parar todos os serviços que começam com 'X' e estão parados

Get-Service -Name 'X*' | Where-Object { $_.Status -eq 'Stopped' } | Stop-Service

O pipeline envia cada serviço parado diretamente para Stop-Service, que o interrompe. Isso só é possível porque Stop-Service aceita objetos ServiceController pelo pipeline.

Exemplo 3: Criar uma lista de arquivos em um diretório com tamanho formatado

Get-ChildItem -Path C:\Temp -File | Select-Object Name, Length, LastWriteTime | ForEach-Object { $_.Length = '{0:N2} KB' -f ($_.Length / 1KB); $_ }

Usamos ForEach-Object para modificar a propriedade Length para uma string formatada. Note que o objeto é modificado e depois enviado adiante (o $_ no final).

Boas práticas

  • Filtre cedo: coloque Where-Object o mais próximo possível da origem para reduzir a quantidade de objetos processados.
  • Evite quebrar o pipeline: cmdlets como Format-Table convertem objetos em texto; use Select-Object quando quiser manter objetos.
  • Use propriedades calculadas: em Select-Object você pode criar novas propriedades com expressões.
  • Teste com objetos pequenos: antes de processar grandes conjuntos, teste o pipeline com alguns objetos para garantir que funciona.

Referências

Exercícios

  1. Escreva um comando que liste todos os processos em execução, ordenados pelo consumo de CPU (maior para menor), mostrando apenas as propriedades Name, CPU e Id.

    ✓ Resposta:
    Get-Process | Sort-Object CPU -Descending | Select-Object Name, CPU, Id
  2. Utilizando o pipeline, encontre todos os serviços que estão parados e cujo nome contenha 'SQL', e então inicie-os.

    ✓ Resposta:
    Get-Service -Name '*SQL*' | Where-Object { $_.Status -eq 'Stopped' } | Start-Service
  3. Escreva um comando que obtenha todos os arquivos .txt no diretório C:\Temp, selecione Name e Length (em bytes), e adicione uma propriedade calculada 'SizeKB' que mostre o tamanho em KB com duas casas decimais.

    ✓ Resposta:
    Get-ChildItem -Path C:\Temp -Filter *.txt | Select-Object Name, Length, @{Name='SizeKB'; Expression={[math]::Round($_.Length / 1KB, 2)}}
  4. Usando pipeline, crie uma lista com os 5 processos que mais consomem memória (WorkingSet64), mostrando apenas Name e WorkingSet64 (em MB), ordenados do maior para o menor.

    ✓ Resposta:
    Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 5 Name, @{Name='MemoryMB'; Expression={[math]::Round($_.WorkingSet64 / 1MB, 2)}}
  5. Explique a diferença entre Get-Process | Format-Table Name, CPU e Get-Process | Select-Object Name, CPU em relação ao pipeline de objetos.

    ✓ Resposta:

    Format-Table converte os objetos em texto formatado para exibição, quebrando o pipeline de objetos. O resultado são strings, não objetos. Já Select-Object cria novos objetos com as propriedades selecionadas, mantendo a estrutura orientada a objetos no pipeline. Portanto, para processamento posterior com cmdlets como Where-Object, use Select-Object; para exibição final, use Format-Table.