Windows PowerShellReport di stato

Don Jones

Di recente mi è capitato di scrivere uno script di Windows PowerShell piuttosto lungo e complicato che, man mano che veniva eseguito, funzionava sempre meno. Tale script doveva essere eseguito come un'attività pianificata, dunque non ha prodotto di fatto un output visibile. Quando ho eseguito lo script per sottoporlo al primo grande test, ho iniziato tuttavia a preoccuparmi

di aver scritto accidentalmente un ciclo infinito o un tipo di script problematico.

E vedendo la Shell immobile, con il cursore che lampeggiava pateticamente, mi sono chiesto: "L'ho uccisa?" Non avendo alcuna fiducia in me stesso ho premuto rapidamente la combinazione di tasti Ctrl+C per interrompere lo script. Tempo necessario per aggiungere il report di stato.

Parole, parole, parole

La prima cosa da fare è aggiungere un gruppo di messaggi di stato che mi consentano di conoscere esattamente il funzionamento dello script. Questa operazione è resa possibile dalla Shell con il cmdlet Write-Verbose. Procediamo e proviamolo nella Shell:

Write-Verbose "Test Message"

Se hai già provato, avrai notato che non funziona. Ciò avviene perché Write-Verbose invia gli oggetti alla pipeline Verbose speciale che, per impostazione predefinita, non visualizza l'output. Una variabile Shell incorporata, $VerbosePreference, controlla questa pipeline. Il valore predefinito di questa variabile è SilentlyContinue, che elimina l'output dettagliato. Se viene impostata su Continue, tuttavia, apre la pipeline:

$VerbosePreference = "Continue"

A questo punto, è possibile aggiungere allo script un gruppo di istruzioni Write-Verbose ed esaminare più a fondo cosa accade durante la relativa esecuzione. Uno degli aspetti più affascinanti di questa tecnica è che, una volta terminate le fasi di verifica e di risoluzione dei problemi, è possibile impostare $VerbosePreference nuovamente su SilentlyContinue all'inizio dello script.

Non è affatto necessario rimuovere tutte le istruzioni Write-Verbose. Infatti, poiché rimangono nello script, se fosse necessario eseguire lo script manualmente, sarebbe possibile attivare nuovamente la pipeline Verbose.

Ma la cosa importante è che lo script possa proseguire

Una volta stabilito che lo script non era stato imprigionato in un ciclo infinito e che, di fatto, funzionava bene, ho interrotto la pipeline Verbose e ho eseguito nuovamente lo script, tanto per essere sicuro.

Il problema a questo punto è che nonostante fosse noto che lo script funzionava perfettamente bene, non potevo sopportare di rimanere incantato davanti a un cursore lampeggiante. (Per affrontare i miei problemi di attenzione, ho cercato disperatamente della vernice, mi sono seduto e l'ho guardata mentre si asciugava.)

Ciò di cui avevo bisogno era un'indicazione generale sullo stato di avanzamento dello script e un'idea su quando sarebbe terminato. Fondamentalmente, desideravo qualcosa di simile a un indicatore di stato

e, fortunatamente, Windows PowerShellTM contiene il cmdlet Write-Progress. Questo cmdlet non fornisce un indicatore di stato come quello di Windows® ma ciononostante produce un indicatore di stato utile, come illustrato nella Figura 1. Si presenta più o meno come l'indicatore di stato della copia di file utilizzato dall'impostazione basata sul testo di Windows Server® 2003 o Windows XP.

Figura 1 Qual è lo stato di avanzamento dello script?

Figura 1** Qual è lo stato di avanzamento dello script? **(Fare clic sull'immagine per ingrandirla)

L'utilizzo di Write-Progress richiede alcune spiegazioni. Anzi, in realtà, penso sia meglio un esempio. Prendiamo in considerazione questo script:

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

Lo script in questione utilizza Write-Progress per visualizzare un indicatore di stato. Ho utilizzato Start-Sleep affinché lo script si interrompesse per un secondo, questo per ogni iterazione del ciclo, in modo che la sua esecuzione fosse sufficientemente lenta da consentire di visualizzarne lo stato; senza pausa, il ciclo passa da 0 a 100 così rapidamente che l'indicatore di stato lampeggia brevemente sullo schermo.

Come si può notare, l'attività, impostata su Working, viene illustrata nella parte superiore dell'indicatore di stato, seguita dallo stato, mentre CurrentOperation viene illustrato nella parte inferiore. La Shell supporta soltanto un unico indicatore di stato alla volta. Qualsiasi utilizzo di Write-Progress crea un nuovo indicatore di stato, nel caso non ve ne fosse già uno, o aggiorna l'indicatore esistente attualmente visualizzato.

Ciò che non ho fatto qui è far sparire la barra al termine dello script. A tale scopo, è possibile aggiungere semplicemente quanto segue alla fine dello script:

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

In generale, al termine dello script l'indicatore di stato svanisce automaticamente ma, se lo script non è stato completato, è possibile nascondere l'indicatore di stato mediante il parametro -Completed che rimuove semplicemente l'indicatore dal display.

Tick, Tick, Tick

Write-Progress viene utilizzato comunemente anche per creare un display che visualizza i "secondi restanti", invece dell'effettivo indicatore di stato. Ecco un esempio:

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

Ho semplicemente modificato il ciclo affinché l'esecuzione avvenisse da 100 a 1 e ho utilizzato il parametro SecondsRemaining di Write-Progress, invece di PercentComplete. Il risultato è illustrato nella Figura 2. Come si può notare, il misuratore di stato è sparito, sostituito da un orologio per il conto alla rovescia. La Shell converte automaticamente il numero totale dei secondi in ore, minuti e secondi, offrendo informazioni più utili. La percentuale di completamento illustrata di seguito parte da 100, proprio per il parametro CurrentOperation fornito. In realtà non è stato completato alcun calcolo di percentuale; Windows PowerShell visualizza semplicemente il valore corrente di $a seguito dalla stringa "% complete".

Figura 2 Quanto tempo occorre perché lo script sia completo?

Figura 2** Quanto tempo occorre perché lo script sia completo? **(Fare clic sull'immagine per ingrandirla)

Script che comunicano

Sono un grande fan della creazione di script che comunicano cosa sono in grado di fare. Tali script possono assumere la forma di un output dettagliato o semplicemente di un indicatore di stato. Possono essere utili per sopperire alle carenze di attenzione o per chiunque desideri eseguire sin d'ora il mio script del mese. Per concludere, è sicuramente un enorme vantaggio poter visualizzare qualsiasi tipo di informazione sullo stato e sull'avanzamento.

Cmdlet del mese: Tee-Object

Nell'articolo di questo mese intendo esaminare uno dei miei cmdlet preferiti per la risoluzione dei problemi. Prendiamo, ad esempio, questa riga:

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

In apparenza, sembrerebbe avviare tutti i servizi impostati su avvio automatico, ma che per un motivo non precisato non sono stati ancora avviati. In effetti lo script non funziona e cercare di scoprirne il motivo non è facile poiché non è possibile analizzare a fondo la pipeline. O meglio, non è possibile analizzare a fondo la pipeline a meno che non si utilizzi Tee-Object.

Tee-Object reindirizza gli oggetti a un file (o in una variabile) e li passa alla pipeline. Ad esempio:

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

Questa modifica mi consente di capire cosa accade dopo ogni comando della pipeline e scopro quasi subito che il mio file FilteredServices.csv non contiene nulla! Non c'è da meravigliarsi se questo script non funziona! Una ricerca più approfondita rivela la causa principale del problema: StartMode è "Auto" non "Automatico" e Tee-Object mi consente di individuare esattamente dove risiede il problema.

Don Jones collabora con TechNet Magazine come redattore ed è coautore del libro Windows PowerShell: TFM (SAPIEN Press, 2007). È docente di corsi su Windows PowerShell (www.ScriptingTraining.com) ed è possibile contattarlo sul sito Web ScriptingAnswers.com.

© 2008 Microsoft Corporation e CMP Media, LLC. Tutti i diritti riservati. È vietata la riproduzione completa o parziale senza autorizzazione.