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? **(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? **(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..