Escrever saída é uma das tarefas mais comuns em qualquer script, e no PowerShell isso vai muito além de simplesmente exibir texto na tela. A escolha do cmdlet certo para escrever saída pode impactar drasticamente o comportamento do seu script, especialmente quando ele é usado em pipelines, redirecionamentos ou em ambientes de automação. Nesta aula, vamos explorar os principais cmdlets de saída do PowerShell, entender suas diferenças sutis e aprender boas práticas para escolher a ferramenta certa para cada situação.

Além disso, vamos mergulhar no conceito de streams, que são canais separados para diferentes tipos de mensagens: saída normal, erros, avisos, informações detalhadas e mensagens de depuração. Compreender esses streams é fundamental para escrever scripts robustos e profissionais, que se comunicam de forma clara com o usuário e com outros sistemas.

Write-Output vs Write-Host

O cmdlet Write-Output é o cmdlet mais fundamental para escrever saída no PowerShell. Ele envia objetos para o pipeline, o que significa que esses objetos podem ser processados por outros cmdlets, redirecionados para arquivos ou atribuídos a variáveis. Na verdade, o Write-Output é tão essencial que ele é o equivalente implícito de simplesmente escrever uma expressão ou valor no console. Por exemplo, Write-Output "Olá" e "Olá" produzem exatamente o mesmo resultado: a string é enviada para o pipeline.

Por outro lado, Write-Host é um cmdlet que escreve diretamente no console (ou host), ignorando o pipeline. Ele é usado principalmente para exibir informações visuais para o usuário, como mensagens de progresso ou cabeçalhos, mas não deve ser usado quando você deseja que a saída seja processada ou capturada. Historicamente, Write-Host enviava apenas texto, mas a partir do PowerShell 5.0 ele também pode enviar objetos para o stream de informação (Information Stream), o que o torna mais flexível. No entanto, a recomendação geral é usar Write-Output para dados e Write-Host apenas para mensagens destinadas exclusivamente à exibição.

Vamos ver a diferença na prática:

# Exemplo 1: Write-Output envia para o pipeline
$resultado = Write-Output "Olá"
$resultado.GetType().FullName  # System.String

# Exemplo 2: Write-Host não envia para o pipeline
$resultado = Write-Host "Olá"
$resultado  # Nada é retornado, pois Write-Host não produz saída no pipeline

Observe que no primeiro exemplo, a variável $resultado recebe a string; no segundo, ela fica vazia. Isso demonstra que Write-Host não é adequado quando você precisa capturar a saída. Além disso, Write-Host pode ser usado com o parâmetro -ForegroundColor e -BackgroundColor para colorir a saída, o que é útil para melhorar a legibilidade em scripts interativos.

Write-Verbose e Write-Debug

O PowerShell oferece streams especiais para mensagens detalhadas (verbose) e de depuração (debug). O cmdlet Write-Verbose envia mensagens para o stream de verbose, que por padrão não é exibido, a menos que o parâmetro -Verbose seja usado no comando ou que a variável $VerbosePreference seja definida como Continue. Isso permite que você forneça informações detalhadas sobre o funcionamento do script sem poluir a saída normal.

Da mesma forma, Write-Debug envia mensagens para o stream de debug, que também é oculto por padrão. O debug é usado para mensagens de diagnóstico durante o desenvolvimento, e pode ser habilitado com o parâmetro -Debug ou definindo $DebugPreference como Continue. Além disso, quando o debug é habilitado, o PowerShell pode pausar a execução e permitir que você inspecione o estado atual, se a preferência for Inquire.

Vamos ver um exemplo prático:

function Teste-Saida {
    [CmdletBinding()]
    param()
    Write-Output "Iniciando processamento..."
    Write-Verbose "Processando item 1"
    Write-Debug "Valor de x = 42"
    Write-Output "Processamento concluído."
}

# Execução normal: apenas Write-Output aparece
Teste-Saida

# Execução com verbose habilitado
Teste-Saida -Verbose

# Execução com debug habilitado (pode pedir confirmação)
Teste-Saida -Debug

No exemplo, a função Teste-Saida usa Write-Verbose e Write-Debug para fornecer informações adicionais. Quando executada sem parâmetros, apenas as mensagens de Write-Output aparecem. Com -Verbose, as mensagens detalhadas são exibidas em amarelo. Com -Debug, as mensagens de depuração aparecem e, dependendo da preferência, podem pausar a execução.

Write-Warning

O cmdlet Write-Warning é usado para exibir mensagens de aviso no stream de warning. Essas mensagens são exibidas por padrão em texto amarelo, mas podem ser controladas pela variável $WarningPreference. A principal finalidade é alertar o usuário sobre condições que não são erros fatais, mas que merecem atenção, como a possibilidade de um arquivo ser sobrescrito ou a detecção de um valor incomum.

Diferente de Write-Error, que envia um erro para o stream de erro e pode interromper a execução, Write-Warning permite que o script continue. A mensagem de aviso também pode ser capturada, se necessário, usando o stream de warning.

Exemplo:

function Teste-Warning {
    [CmdletBinding()]
    param()
    Write-Warning "Este é um aviso: o arquivo já existe e será sobrescrito."
    Write-Output "Continuando..."
}

Teste-Warning

Na execução, você verá a mensagem de aviso em amarelo, mas o script continuará e exibirá a saída normal. É importante usar Write-Warning com moderação, para que os avisos não se tornem ruído para o usuário.

Streams

O PowerShell possui múltiplos streams de saída, cada um com um propósito específico. Entender esses streams é crucial para escrever scripts que se comportem bem em pipelines e que forneçam informações adequadas em diferentes cenários. Os streams são:

  • Output Stream (1): contém a saída normal do script, gerada por Write-Output ou por expressões. É o stream principal que flui para o pipeline.
  • Error Stream (2): contém erros não-terminantes, gerados por Write-Error ou por cmdlets que falham. Por padrão, os erros são exibidos em vermelho no console.
  • Warning Stream (3): contém avisos, gerados por Write-Warning.
  • Verbose Stream (4): contém mensagens detalhadas, geradas por Write-Verbose.
  • Debug Stream (5): contém mensagens de depuração, geradas por Write-Debug.
  • Information Stream (6): introduzido no PowerShell 5.0, usado por Write-Host e Write-Information para mensagens de informação.

Cada stream pode ser redirecionado de forma independente usando operadores de redirecionamento como 2> para erro, 3> para aviso, 4> para verbose, 5> para debug, e 6> para informação. Por exemplo, para redirecionar erros para um arquivo, você pode usar 2> erros.txt. Também é possível mesclar streams com *> para enviar todos para o mesmo destino.

Vamos ver um exemplo de redirecionamento:

# Cria um script que produz saída em vários streams
$script = @'
Write-Output "Mensagem normal"
Write-Warning "Aviso importante"
Write-Error "Erro simulado"
Write-Verbose "Detalhes" -Verbose
'@

# Executa o script e redireciona cada stream para um arquivo
& ([scriptblock]::Create($script)) 1> saida.txt 2> erros.txt 3> avisos.txt 4> verbose.txt

# Exibe o conteúdo dos arquivos
Get-Content saida.txt, erros.txt, avisos.txt, verbose.txt

No exemplo, cada stream é redirecionado para um arquivo separado, permitindo que você analise cada tipo de mensagem de forma isolada. Isso é particularmente útil em scripts de automação, onde você pode querer registrar erros e avisos separadamente.

Além disso, as variáveis de preferência ($VerbosePreference, $DebugPreference, $WarningPreference, etc.) controlam como esses streams são tratados por padrão. Por exemplo, definir $VerbosePreference = 'Continue' faz com que todas as mensagens verbose sejam exibidas, mesmo sem o parâmetro -Verbose. Essas preferências podem ser alteradas globalmente ou dentro de um script, e são herdadas por funções e cmdlets.

Boas Práticas e Observações Finais

Ao escrever scripts, é importante seguir algumas boas práticas para garantir que a saída seja clara e útil:

  • Use Write-Output (ou simplesmente a expressão) para dados que devem ser processados pelo pipeline ou capturados em variáveis.
  • Use Write-Host apenas para mensagens puramente visuais, como cabeçalhos ou separadores, e lembre-se de que ele não afeta o pipeline.
  • Use Write-Verbose para fornecer detalhes adicionais que podem ser ativados quando necessário, sem poluir a saída padrão.
  • Use Write-Debug para mensagens de diagnóstico durante o desenvolvimento, e remova ou desative-as em produção.
  • Use Write-Warning para alertar sobre condições potencialmente problemáticas, mas evite excessos.
  • Para erros, prefira Write-Error ou lançar exceções com throw, dependendo se o erro é não-terminal ou terminal.

Dominar os streams e os cmdlets de saída é essencial para criar scripts profissionais e fáceis de manter. Na próxima vez que escrever um script, pense em como cada mensagem será consumida e escolha o cmdlet adequado.

Referências

Exercícios

  1. Explique a diferença entre Write-Output e Write-Host em relação ao pipeline. Dê um exemplo onde usar Write-Host seria inadequado.

    ✓ Resposta: Write-Output envia objetos para o pipeline, permitindo que sejam processados, redirecionados ou capturados. Write-Host escreve diretamente no console e não envia nada para o pipeline. Um exemplo inadequado seria usar Write-Host para retornar um valor de uma função que será usado em uma expressão, pois a saída não estará disponível.
  2. Crie uma função que use Write-Verbose e Write-Debug para informar o início e o fim de um processamento, e mostre como executá-la com verbose e debug habilitados.

    ✓ Resposta: Exemplo de função:
    function Processar {
        [CmdletBinding()]
        param()
        Write-Verbose "Iniciando processamento..."
        Write-Debug "Debug: informações internas"
        Write-Output "Processamento concluído."
        Write-Verbose "Finalizando processamento..."
    }
    Processar -Verbose -Debug
    Para habilitar verbose e debug, use os parâmetros -Verbose e -Debug na chamada.
  3. Qual é a finalidade do Write-Warning? Dê um exemplo de situação em que um aviso seria apropriado.

    ✓ Resposta: Write-Warning é usado para exibir avisos não fatais, que não interrompem a execução. Um exemplo é avisar que um arquivo será sobrescrito, permitindo que o usuário decida se deseja continuar.
  4. Liste os principais streams de saída do PowerShell e indique qual cmdlet escreve em cada um.

    ✓ Resposta: Os principais streams são: Output (1) - Write-Output; Error (2) - Write-Error; Warning (3) - Write-Warning; Verbose (4) - Write-Verbose; Debug (5) - Write-Debug; Information (6) - Write-Host e Write-Information.
  5. Como você faria para redirecionar apenas os avisos de um script para um arquivo chamado avisos.log? Escreva um exemplo.

    ✓ Resposta: Use o redirecionador 3> para o stream de warning. Exemplo:
    Write-Warning "Aviso 1"
    Write-Warning "Aviso 2" 3> avisos.log
    Isso enviará apenas os avisos para o arquivo, enquanto a saída normal continua no console.