Windows PowerShellRelatório de andamento

Don Jones

Recentemente, estava escrevendo um script do Windows PowerShell um tanto longo e complicado, que, em execução, praticamente não respondia. Escrevi-o para ser executado como uma tarefa programada; portanto, ele realmente não produzia muito em termos de saída visível. Quando o executei para seu primeiro grande teste, comecei a ficar um pouco preocupado que

tivesse escrito acidentalmente um loop infinito ou alguma outra parte de script problemática.

Como o shell continuava lá, parado, e seu cursor piscava pateticamente, me perguntei, “O que eu faço agora?”. Aparentemente, não tenho muita segurança, pois pressionei rapidamente Ctrl+C para interromper o script. É o momento de acrescentar algum relatório de progresso.

Blá, blá, blá

A primeira ação que eu queria tomar era adicionar várias mensagens de status, permitindo que eu soubesse exatamente o que o script estava fazendo. O shell permite que você faça isso facilmente com o cmdlet Write-Verbose. Siga em frente e experimente isto no shell:

Write-Verbose "Test Message"

Se você já tiver tentado, observou que não resolve. Isso acontece porque o Write-Verbose envia objetos ao pipeline Verbose especial, que, por padrão, não exibe sua saída. Uma variável interna do shell, $VerbosePreference, controla esse pipeline. O valor padrão dessa variável é SilentlyContinue, que suprime a saída detalhada. Defini-lo como Continue, no entanto, abre o pipeline:

$VerbosePreference = "Continue"

Agora, posso adicionar várias instruções Write-Verbose ao meu script e obter uma visão detalhada do que está acontecendo à medida que a execução for progredindo. E a beleza dessa técnica é que, quando eu tiver concluído os testes e a solução de problemas, posso desativar todos os extras ao definir $VerbosePreference novamente como SilentlyContinue no início do meu script.

Não há necessidade de prosseguir e remover todas as instruções Write-Verbose. Na realidade, como elas permanecem no script, a qualquer momento que eu precisar executar o script manualmente, posso alternar facilmente o pipeline Verbose de novo, se necessário.

Mas eu preciso de verdadeiros avanços

Assim que eu estiver satisfeito com o fato de o script não ser chamado em um loop infinito e estar, de fato, funcionando perfeitamente, posso desativar o pipeline Verbose e executá-lo novamente – apenas para me certificar.

O problema agora é que, apesar de saber que o script está funcionando perfeitamente, não suporto esse cursor piscando. (Tenho problemas para me concentrar. Por isso, procurei desesperadamente algo para me distrair.)

O que eu precisava era de uma indicação geral de quanto o script tinha progredido e alguma idéia de quando seria concluído. Basicamente, desejo algo como uma barra de andamento.

Felizmente, o Windows PowerShellTM inclui o cmdlet Write-Progress. Esse cmdlet não fornece uma barra de progresso gráfico, como a que você vê no Windows®, mas produz uma barra de progresso interessante, como mostra a Figura 1. Ela é semelhante à barra de progresso de cópia de arquivo usada na Instalação no Windows Server® 2003 ou até mesmo no Windows XP.

Figura 1 Quanto o script já progrediu?

Figura 1** Quanto o script já progrediu? **(Clique na imagem para aumentar a exibição)

O uso do Write-Progress requer um pouco de explicação. Na verdade, penso que um exemplo seria ainda melhor. Considere este script:

for ($a=1; $a -lt 100; $a++) {
  Write-Progress -Activity "Working..." `
   -PercentComplete $a -CurrentOperation
   "$a% complete" `
   -Status "Please wait."
  Start-Sleep 1
}

Ele utiliza Write-Progress para exibir uma barra de progresso. Utilizei o Start-Sleep para fazer com que o script fizesse uma pausa de um segundo sempre que estivesse em loop, de modo que fosse executado lentamente, o suficiente para vermos o andamento, de fato – sem a pausa, o loop conta de 0 a 100 tão rapidamente que a barra de progresso apenas pisca na tela.

Como você pode ver, a Activity – que defini como Working – é exibida no início da barra de progresso. O Status é mostrado logo depois dele e CurrentOperation é exibido na parte inferior. O shell é compatível somente com uma barra de progresso individual por vez. Qualquer uso de Write-Progress irá criar uma nova barra de andamento se não houver uma sendo atualmente exibida ou irá atualizar a que está sendo exibida.

O que não fiz aqui foi informar à barra para desaparecer ao final do andamento. Posso fazer isso simplesmente adicionando o seguinte ao final do meu script:

Write-Progress -Activity "Working..." `
 -Completed -Status "All done."

Em termos gerais, a barra de progresso desaparecerá por si só assim que o seu script for concluído, mas se o seu script tiver outros itens a executar, você desejará ocultar a barra quando tiver concluído; o parâmetro Completed simplesmente remove a barra do monitor.

Tique-taque, tique-taque

Outro uso comum de Write-Progress é para criar uma exibição de “segundos restantes”, em vez de uma barra de progresso real. Por exemplo:

for ($a=100; $a -gt 1; $a--) {
  Write-Progress -Activity "Working..." `
   -SecondsRemaining $a -CurrentOperation
   "$a% complete" `
   -Status "Please wait."
  Start-Sleep 1
}

Tudo que fiz aqui foi alterar o loop para contar de 100 a 1 e utilizei o parâmetro SecondsRemaining de Write-Progress, em vez de PercentComplete. O resultado é mostrado na Figura 2. Como você pode ver, o medidor de progresso desapareceu e foi substituído por um relógio de contagem progressiva. O shell converterá automaticamente o número total de segundos restantes em horas, minutos e segundos, oferecendo informações mais acessíveis. O percentual completo mostrado aqui realiza, na verdade, uma contagem progressiva de 100, pois é simplesmente o parâmetro CurrentOperation fornecido. Não há cálculo real do percentual concluído; o Windows PowerShell está simplesmente exibindo o valor atual de $a seguido pela seqüência de caracteres "% complete".

Figura 2 Quanto falta para concluir o script?

Figura 2** Quanto falta para concluir o script? **(Clique na imagem para aumentar a exibição)

Scripts com objetivos claros

Adoro escrever scripts que têm um objetivo claro. Posso utilizar a forma de saída detalhada ou apenas uma barra de progresso simples. Isso pode ser para o meu próprio benefício, pela minha falta de atenção, ou para o benefício de outra pessoa que precisará executar meu script do mês a partir de agora. No final das contas, exibir algum tipo de status e informações sobre o andamento será um grande benefício para todos.

Cmdlet do mês: Tee-Object

Este mês, vou analisar um dos meus cmdlets de solução de problemas favoritos. Veja este, por exemplo:

Get-WMIObject Win32_Service | Where { $_.State -ne "Running"
-and $_.StartMode -eq "Automatic" } | ForEach-Object { $_.Start() }

À primeira vista, ele parece iniciar todos os serviços definidos para iniciar automaticamente, mas que ainda não iniciaram por algum motivo. Isso, na verdade, não funciona, e descobrir o motivo pelo qual não funciona poderia ser complicado, pois você não pode fazer um ponto no meio do pipeline. Ou seja, você não pode fazer um ponto no pipeline, a não ser que esteja usando Tee-Object.

O Tee-Object redireciona objetos para um arquivo (ou uma variável) e os passa para o pipeline. Por exemplo:

Get-WMIObject Win32_Service | Tee-Object AllServices.csv | Where 
{ $_.State -ne "Running" -and $_.StartMode -eq "Automatic" } | 
Tee-Object FilteredServices.csv | ForEach-Object { $_.Start() }

Essa modificação me permite ver o que acontece depois de cada comando de pipeline e descubro rapidamente que meu arquivo FilteredServices.csv está vazio! Não importa, esse script não funciona! Um pouco mais de pesquisa revela a causa principal do problema – StartMode está como "Auto", não "Automatic" – e o Tee-Object me permite verificar exatamente onde o problema estava ocorrendo.

Don Jones é editor-colaborador da TechNet Magazine e co-autor de Windows PowerShell: TFM (SAPIEN Press, 2007). Ele é professor de Windows PowerShell (consulte www.ScriptingTraining.com) e pode ser contatado pelo site ScriptingAnswers.com.

© 2008 Microsoft Corporation e CMP Media, LLC. Todos os direitos reservados. A reprodução parcial ou completa sem autorização é proibida..