No PowerShell, a saída gerada pelos comandos pode ser direcionada para diferentes lugares: o console, arquivos, pipelines ou até mesmo suprimida. Entender os cmdlets de saída e os streams é fundamental para controlar o fluxo de informações em scripts e funções. Cada cmdlet tem um propósito específico e escreve em um stream diferente, permitindo separar mensagens de erro, avisos, informações detalhadas e saída normal.

Nesta aula, vamos detalhar os principais cmdlets de saída: Write-Output, Write-Host, Write-Verbose, Write-Debug e Write-Warning. Também explicaremos o sistema de streams do PowerShell, que é a base para o redirecionamento e a filtragem de saída.

Write-Output vs Write-Host

Write-Output é o cmdlet padrão para enviar objetos para o pipeline. Ele escreve no stream de saída (número 1), que é o mesmo stream usado por qualquer comando que produz saída normal. Quando você usa Write-Output, os objetos podem ser passados para outros cmdlets, armazenados em variáveis ou redirecionados para arquivos. Por exemplo:

$result = Write-Output "Olá, mundo!"
$result  # Exibe "Olá, mundo!"

Write-Host escreve diretamente no console (ou host), ignorando o pipeline. Ele usa o stream de informação (número 6) e não pode ser capturado por variáveis ou redirecionado para arquivos (a menos que se use redirecionamento explícito 6>&1). Historicamente, Write-Host era usado para exibir mensagens coloridas, mas seu uso é desencorajado em scripts que precisam de saída processável. Exemplo:

Write-Host "Esta mensagem aparece no console" -ForegroundColor Green

Quando usar cada um? Use Write-Output para saída que fará parte do pipeline (dados). Use Write-Host apenas para mensagens visuais que não precisam ser capturadas, como cabeçalhos de relatórios no console. Em funções modernas, prefira Write-Output ou [Console]::WriteLine para controle fino.

Write-Verbose e Write-Debug

Write-Verbose escreve no stream detalhado (número 4). É usado para fornecer informações adicionais sobre o progresso de um script, como "Processando arquivo X". Por padrão, essas mensagens não aparecem no console. Para exibi-las, é necessário definir a variável $VerbosePreference ou usar o parâmetro -Verbose ao chamar o script/função. Exemplo:

function Test-Verbose {
    [CmdletBinding()]
    param()
    Write-Verbose "Iniciando processo..."
    Start-Sleep -Seconds 1
    Write-Verbose "Processo concluído."
}
Test-Verbose -Verbose

Write-Debug escreve no stream de depuração (número 5). É usado para mensagens de debug que ajudam a entender o fluxo interno. Assim como Write-Verbose, requer que a preferência de depuração esteja ativada ($DebugPreference ou -Debug). A diferença é que Write-Debug normalmente pausa a execução e pergunta se deseja continuar. Exemplo:

function Test-Debug {
    [CmdletBinding()]
    param()
    Write-Debug "Valor da variável: $var"
}
Test-Debug -Debug

Ambos são essenciais para scripts robustos, permitindo que o usuário opte por ver detalhes sem poluir a saída normal.

Write-Warning

Write-Warning escreve no stream de aviso (número 3). É usado para alertar o usuário sobre situações que não são erros, mas merecem atenção, como "Arquivo não encontrado, usando padrão". As mensagens de aviso são exibidas em amarelo (dependendo do console) e podem ser controladas pela variável $WarningPreference. Exemplo:

Write-Warning "O parâmetro -Force foi ignorado porque o arquivo não existe."

É uma boa prática usar Write-Warning em vez de Write-Host para avisos, pois permite que o usuário suprima ou redirecione essas mensagens.

Streams

O PowerShell possui seis streams numerados, cada um com uma finalidade específica:

  • Stream 1 (Sucesso/Output): saída normal de comandos, capturada por Write-Output e pela maioria dos cmdlets.
  • Stream 2 (Erro): usado por Write-Error e erros de terminação.
  • Stream 3 (Aviso): usado por Write-Warning.
  • Stream 4 (Detalhado): usado por Write-Verbose.
  • Stream 5 (Depuração): usado por Write-Debug.
  • Stream 6 (Informação): usado por Write-Host e Write-Information.

Os streams podem ser redirecionados usando operadores como 2> (erro), 3> (aviso), 4> (detalhado), 5> (depuração), 6> (informação) e *> (todos). Por exemplo, para redirecionar erros para um arquivo:

Get-ChildItem -Path "C:\inexistente" 2> erro.log

Para combinar streams, use 2>&1 para unir erro com saída normal. Entender streams é crucial para depuração e automação.

Boas práticas

  • Use Write-Output para dados que serão processados posteriormente.
  • Use Write-Verbose e Write-Debug para informações extras que não devem aparecer por padrão.
  • Use Write-Warning para alertas que não impedem a execução.
  • Evite Write-Host em scripts reutilizáveis; prefira Write-Output ou Write-Information.
  • Configure as preferências ($VerbosePreference, $DebugPreference, etc.) no início do script para controlar o comportamento.

Referências

Exercícios

  1. Crie um script que use Write-Output para exibir uma lista de números de 1 a 5 e, em seguida, redirecione essa saída para um arquivo chamado "numeros.txt".

    ✓ Resposta:
    1..5 | ForEach-Object { Write-Output $_ } > numeros.txt
    # Ou simplesmente:
    1..5 > numeros.txt
  2. Explique a diferença entre Write-Host e Write-Output em termos de pipeline e redirecionamento.

    ✓ Resposta:

    Write-Output envia objetos para o stream de saída (1), que pode ser capturado por variáveis ou redirecionado. Write-Host envia para o stream de informação (6) e exibe diretamente no console, não sendo capturável por padrão. Para redirecionar a saída de Write-Host, é necessário usar 6>&1.

  3. Escreva uma função que use Write-Verbose e Write-Debug para exibir mensagens detalhadas e de depuração. Execute a função com os parâmetros -Verbose e -Debug.

    ✓ Resposta:
    function Test-MyFunction {
        [CmdletBinding()]
        param()
        Write-Verbose "Iniciando função..."
        Write-Debug "Debug: variável X = 10"
        Start-Sleep -Seconds 1
        Write-Verbose "Finalizando função."
    }
    Test-MyFunction -Verbose -Debug
  4. Use Write-Warning para emitir um aviso quando um arquivo não for encontrado em um diretório. Em seguida, redirecione o aviso para um arquivo de log.

    ✓ Resposta:
    $file = "C:\temp\inexistente.txt"
    if (-not (Test-Path $file)) {
        Write-Warning "Arquivo $file não encontrado."
    } 3>> avisos.log
    # O operador 3>> anexa o stream de aviso ao arquivo.
  5. Crie um script que redirecione todos os streams (exceto saída normal) para um arquivo chamado "tudo.log". Use o operador *>&1 ou *>>.

    ✓ Resposta:
    # Exemplo: gerar saída em vários streams e redirecionar todos para um arquivo
    function Test-Streams {
        [CmdletBinding()]
        param()
        Write-Output "Stream 1"
        Write-Error "Stream 2"
        Write-Warning "Stream 3"
        Write-Verbose "Stream 4"
        Write-Debug "Stream 5"
        Write-Host "Stream 6"
    }
    Test-Streams -Verbose -Debug *>> tudo.log