O pipeline é um dos recursos mais poderosos do PowerShell. Diferente de shells tradicionais que passam apenas texto entre comandos, o PowerShell transmite objetos .NET completos. Isso significa que cada cmdlet pode acessar diretamente propriedades e métodos dos objetos recebidos, sem necessidade de parsing textual. Nesta aula, exploraremos como os objetos fluem pelo pipeline, como as propriedades são preservadas, como encadear cmdlets de forma eficiente e exemplos práticos que ilustram esses conceitos.

Entender o pipeline é essencial para escrever scripts concisos e performáticos. Ao dominar o fluxo de objetos, você poderá combinar cmdlets em sequências poderosas, filtrar dados com precisão e transformar informações sem sair do contexto do PowerShell.

Como objetos fluem

Quando você conecta dois cmdlets com o operador pipe (|), o cmdlet da esquerda produz objetos que são enviados um a um para o cmdlet da direita. O cmdlet da direita processa cada objeto assim que ele chega, sem esperar que todos sejam gerados. Esse fluxo é chamado de processamento em streaming e permite trabalhar com grandes volumes de dados sem consumir muita memória.

Por exemplo, ao executar Get-Process | Stop-Process, o cmdlet Get-Process começa a emitir objetos de processo. Cada objeto é imediatamente recebido por Stop-Process, que encerra o processo correspondente. Se houver muitos processos, o pipeline os processa em tempo real, sem armazenar todos na memória.

Get-Service | Where-Object { $_.Status -eq 'Running' }

Nesse exemplo, Get-Service produz objetos de serviço, e Where-Object filtra apenas aqueles cuja propriedade Status seja igual a 'Running'. O objeto atual é referenciado por $_ dentro do bloco de script.

Propriedades preservadas

Como o pipeline transmite objetos, todas as propriedades e métodos do objeto original permanecem disponíveis ao longo da cadeia. Isso elimina a necessidade de extrair texto e fazer expressões regulares para obter informações. Por exemplo, um processo tem propriedades como Name, Id, CPU, WorkingSet, etc. Você pode acessá-las diretamente em qualquer cmdlet que receba o objeto.

O cmdlet Select-Object permite escolher quais propriedades você deseja manter no pipeline, criando um novo objeto com um subconjunto de propriedades. Já Format-List ou Format-Table são usados apenas para exibição, mas não alteram o objeto subjacente.

Get-Process -Name notepad | Select-Object Name, CPU, WorkingSet

Isso retorna objetos com apenas as propriedades Name, CPU e WorkingSet. Se você quiser adicionar propriedades calculadas, pode usar uma hashtable:

Get-Process | Select-Object Name, @{Name='MemMB'; Expression={[math]::Round($_.WorkingSet/1MB,2)}}

Encadeando cmdlets

O verdadeiro poder do pipeline está em encadear múltiplos cmdlets para realizar tarefas complexas em uma única linha. Os cmdlets mais comuns para encadeamento são Where-Object (filtro), Select-Object (seleção de propriedades), ForEach-Object (processamento personalizado) e Sort-Object (ordenação).

Por exemplo, para listar os 5 processos que mais consomem memória, formatando o resultado:

Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5 Name, WorkingSet | Format-Table -AutoSize

Outro exemplo: parar todos os serviços que estão em execução e cujo nome começa com 'A':

Get-Service | Where-Object { $_.Status -eq 'Running' -and $_.Name -like 'A*' } | Stop-Service

Note que Stop-Service aceita objetos de serviço diretamente, então não é necessário extrair o nome.

Exemplos

Vamos consolidar com exemplos práticos que ilustram o uso do pipeline com objetos.

Exemplo 1: Obter informações de arquivos em uma pasta, filtrar por tamanho e exibir nome e tamanho em MB.

Get-ChildItem C:\Temp\*.log | Where-Object { $_.Length -gt 1MB } | Select-Object Name, @{Name='SizeMB'; Expression={[math]::Round($_.Length/1MB,2)}}

Exemplo 2: Encerrar todos os processos do Chrome que estão rodando há mais de 1 hora.

Get-Process -Name chrome | Where-Object { $_.StartTime -lt (Get-Date).AddHours(-1) } | Stop-Process -Force

Exemplo 3: Exportar serviços em execução para um arquivo CSV com apenas nome e status.

Get-Service | Where-Object { $_.Status -eq 'Running' } | Select-Object Name, Status | Export-Csv -Path services.csv -NoTypeInformation

Esses exemplos mostram como o pipeline permite compor operações de forma clara e eficiente, mantendo a integridade dos objetos.

Boas práticas

  • Prefira usar Where-Object antes de Select-Object ou ForEach-Object para reduzir o número de objetos processados.
  • Evite quebrar o pipeline com parênteses desnecessários; use subexpressões apenas quando precisar de um resultado intermediário.
  • Utilize propriedades calculadas com Select-Object para transformar dados sem recorrer a loops explícitos.
  • Teste pipelines com poucos objetos antes de aplicá-los a grandes conjuntos.

Referências

Exercícios

  1. Escreva um comando que liste todos os processos que estão consumindo mais de 100 MB de memória (WorkingSet > 100MB), exibindo apenas o nome e o WorkingSet em MB.

    ✓ Resposta:
    Get-Process | Where-Object { $_.WorkingSet -gt 100MB } | Select-Object Name, @{Name='WorkingSetMB'; Expression={[math]::Round($_.WorkingSet/1MB,2)}}
  2. Obtenha todos os serviços que estão parados e cujo nome começa com 'W', e então inicie-os.

    ✓ Resposta:
    Get-Service | Where-Object { $_.Status -eq 'Stopped' -and $_.Name -like 'W*' } | Start-Service
  3. Liste os 3 maiores arquivos (em tamanho) na pasta C:\Windows\System32, exibindo nome, tamanho em KB e data de criação.

    ✓ Resposta:
    Get-ChildItem C:\Windows\System32 | Sort-Object Length -Descending | Select-Object -First 3 Name, @{Name='SizeKB'; Expression={[math]::Round($_.Length/1KB,2)}}, CreationTime
  4. Crie um comando que calcule a média de CPU (propriedade CPU) de todos os processos do navegador Chrome (nome 'chrome') e exiba o resultado.

    ✓ Resposta:
    Get-Process -Name chrome | Measure-Object -Average CPU | Select-Object Average
  5. Exporte para um arquivo CSV chamado 'eventos.csv' os 10 eventos mais recentes do log de sistema (System) que tenham nível de erro (EntryType -eq 'Error'), exibindo TimeGenerated, Message e EntryType.

    ✓ Resposta:
    Get-EventLog -LogName System -EntryType Error | Sort-Object TimeGenerated -Descending | Select-Object -First 10 TimeGenerated, Message, EntryType | Export-Csv -Path eventos.csv -NoTypeInformation