Windows PowerShellUn output bello e chiaro

Don Jones

Non è insolito desiderare che i propri script producano un output chiaro e piacevole e mi viene spesso chiesto quale sia il modo migliore per ottenere, ad esempio, delle tabelle. Esistono in effetti un paio di possibili metodi per produrre elementi del genere. La prima operazione da eseguire consiste nello scrivere uno script che inserisca i dati (qualsiasi tipo di dati che si desideri visualizzare con una determinata formattazione) in variabili denominate

$data1, $data2 e $data3. A questo punto si procede con la formattazione dei dati.

La modalità testo

Sul Web

Una dimostrazione veloce delle tecniche illustrate nell'articolo Windows PowerShell di questo mese è all'indirizzo technetmagazine.com/video, dove è possibile vedere come Don Jones utilizza i cmdlet.

Questa attività viene spesso eseguita allo stesso modo in cui si gestirebbe un'operazione simile in un linguaggio come VBScript, Perl, KiXtart o un altro linguaggio orientato al testo. È possibile iniziare scrivendo una serie di intestazioni di colonne nella schermata:

Write-Host "ColumnA'tColumnB'tColumnC"

È importante notare che `t è una sequenza di escape speciale in Windows PowerShellTM che inserisce un carattere di tabulazione. Per scrivere ciascuna riga della tabella, ricordando che i dati sono in $data1, $data2 e $data3, non si hanno molte scelte. Una possibilità consiste nello scrivere semplicemente le variabili, fidando sulla capacità della shell di sostituire le variabili con il relativo contenuto all'interno di virgolette doppie:

Write-Host "$data1't$data2't$data3"

Un'altra possibilità, che consente di ottenere un risultato un po' più ordinato, è l'utilizzo dell'operatore -f. Con questa tecnica si separa la formattazione dai dati e si ottiene una riga di codice di più facile lettura e manutenzione:

Write-Host "{0}'t{1}'t{3}" –f $data1,$data2,$data3

Questo approccio, tuttavia, presenta dei problemi sostanziali. Prima di tutto, quando si fa affidamento sulle tabulazioni fisse nella finestra della console, bisogna aspettarsi delle formattazioni strane. Se, ad esempio, una particolare riga di tabella ha un valore di 20 caratteri nella prima colonna, si scombussola l'intera formattazione della riga. Inoltre, poiché per l'output del testo si utilizza Write-Host, la visualizzazione viene limitata a una console.

Non esiste un metodo semplice per inviare l'output a un file o per renderlo in altri formati, in caso fosse necessario. Ciò che più conta, l'approccio basato sul testo non tiene in alcun conto la shell basata sugli oggetti che si sta utilizzando e non sfrutta tutte le incredibili tecniche e funzionalità che Windows PowerShell offre.

Il metodo di Windows PowerShell

Windows PowerShell è una shell orientata a oggetti. Vale a dire, teoricamente, che tutti gli elementi su cui si lavora devono essere all'interno di oggetti, consentendo alla shell di trasformare il tutto in visualizzazioni di testo, quando richiesto. Ma come si creano degli oggetti per blocchi di dati arbitrari?

Se si procede con l'esempio, si inizia creando un oggetto vuoto personalizzato che viene quindi memorizzato in una variabile:

 $obj = New-Object PSObject

Si ottiene così un nuovo oggetto vuoto su cui lavorare. Si aggiungono quindi i dati all'oggetto nella forma di proprietà. A tal fine, è sufficiente inviare l'oggetto al cmdlet Add-Member. Si aggiunge quindi un elemento denominato NoteProperty, si attribuisce un nome alla proprietà (è una buona idea utilizzare le intestazioni di colonna come nomi di proprietà) e si inseriscono i dati come valori per le proprietà:

 $obj | Add-Member NotePropertyColumnA $data1
$obj | Add-Member NotePropertyColumnB $data2
$obj | Add-Member NotePropertyColumnC $data3

A questo punto è sufficiente eseguire l'output dell'oggetto, non alla console ma alla pipeline:

Write-Output $obj

È quindi possibile ripetere questi passaggi per ciascuna riga della tabella di cui si desidera ottenere l'output. Di seguito è riportata una breve funzione che accetta una stringa ed esegue l'output di una versione maiuscola e di una versione minuscola, oltre alla stringa originale:

functionStringVersions {
param([string]$inputString)
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Original($inputString)
  $obj | Add-Member NoteProperty Uppercase($inputString.ToUpper())
  $obj | Add-Member NoteProperty Lowercase($inputString.ToLower())
  Write-Output $obj
}  
$strings = @("one","two","three")
foreach ($item in $strings) {
StringVersions $item
}

Ai fini dell'esempio si inizia da una matrice di variabili di stringa, considerate singolarmente una per volta e inviate alla funzione. L'output della funzione viene quindi scritta nella pipeline.

Esistono metodi più rapidi per scrivere questo codice, ma ho scelto di descrivere questa tecnica perché illustra in modo chiaro il punto da esaminare. Il risultato, come illustrato nella Figura 1, è una tabella perfettamente formattata. Ciò accade perché la shell sa già come formattare gli oggetti in una tabella.

Figura 1 L'output di Windows PowerShell visualizzato in una tabella

Figura 1** L'output di Windows PowerShell visualizzato in una tabella **(Fare clic sull'immagine per ingrandirla)

Quando un oggetto ha quattro o meno proprietà, Windows PowerShell sceglie automaticamente una tabella. Quindi senza alcuna necessità di intervento da parte dello sviluppatore, si ottiene una tabella molto chiara e gradevole.

Non è finita qui.

Cmdlet del mese: Get-Command

Sono sicuro che molti hanno già utilizzato Get-Command o il suo utile alias (gcm), una o due volte per esaminare l'elenco dei cmdlet disponibili di Windows PowerShell. Ma non tutti sanno quanto è davvero flessibile gcm. Se, ad esempio, si è interessati a scoprire tutto ciò che Windows PowerShell può fare con un servizio, eseguire gcm -noun service. Se invece si desidera visualizzare tutte le opzioni di esportazione di Windows PowerShell, provare con gcm -verb export. Se, ancora, serve solo visualizzare i cmdlet che sono stati aggiunti da un determinato snap-in, come PowerShell Community Extensions, provare con gcm -pssnapin pscx (si può sostituire "pscx" con qualunque nome di snap-in per visualizzare i cmdlet dello snap-in corrispondenti).

Come si può vedere, Get-Command è fondamentale nella fase di scoperta di Windows PowerShell. Consente di conoscere le funzionalità disponibili senza dover neanche aprire un manuale. Inoltre gcm rappresenta un metodo più preciso per scoprire le funzionalità rispetto all'utilizzo di un comando come Help *. Con la funzione Help si ottiene solo un elenco degli argomenti della guida disponibili. I cmdlet che non sono dotati di guida non vengono neanche riportati nell'elenco, anche se i cmdlet sono disponibili quando necessario.

Il vantaggio offerto da questa tecnica supera di gran lunga il semplice ordinamento in tabella. Quando si lavora con gli oggetti, Windows PowerShell sa già come trattare una gamma molto ampia di elementi. Si devono esportare i dati in un file CSV? Basta utilizzare Export-CSV. Si preferisce una tabella HTML? Basta inviare gli oggetti a ConvertTo-Html. È necessario formattare un elenco? Basta inviare i dati a Format-List. Quando si utilizzano gli oggetti, si possono sfruttare tutte le funzioni che la shell sa già come eseguire. Ecco un esempio:

functionStringVersions {
  PROCESS {
   $obj = New-Object PSObject
   $obj | Add-Member NoteProperty Original($_)
   $obj | Add-Member NoteProperty Uppercase($_.ToUpper())
   $obj | Add-Member NoteProperty Lowercase($_.ToLower())
   Write-Output $obj
}
}

Questa volta la funzione è stata modificata in modo da accettare l'input della pipeline (sempre una buona idea quando si lavora con gli oggetti) e di eseguire l'output sulla pipeline.

Il codice della funzione ora è all'interno di uno scriptblock PROCESS. Ne consegue che la funzione accetterà l'input della pipeline ed eseguirà lo scriptblock PROCESS una volta per ciascun oggetto proposto dalla pipeline.

All'interno dello scriptblock PROCESS, la variabile speciale $_ fa riferimento all'oggetto di pipeline corrente in corso di elaborazione. Il risultato pratico è la possibilità di inviare semplicemente tramite pipeline una matrice di stringhe:

@("one","two","three") | StringVersions

Si ottiene una tabella perché la funzione invia l'output alla pipeline. Alla fine della pipeline, la shell richiama il sottosistema di formattazione, che prende autonomamente la decisione di utilizzare una tabella perché gli oggetti nella pipeline hanno meno di cinque proprietà (per impostazione predefinita, quando le proprietà sono più di cinque, la shell utilizza un elenco).

Ma non è necessario confidare sul comportamento predefinito. Per fare in modo che gli oggetti vengano trattati in modo diverso, è sufficiente inviarli a un altro cmdlet:

@("one","two","three") | StringVersions | Format-List
@("one","two","three") | StringVersions | ConvertTo-HTML | Out-File "strings.html"
@("one","two","three") | StringVersions | Export-CSV "strings.csv"
@("one","two","three") | StringVersions | Select Uppercase,Lowercase -unique

Nella Figura 2 viene illustrato l'HTML che risulta dal secondo esempio visualizzato in un browser Web. La semplice rappresentazione dei dati di output in oggetti, piuttosto che in testo semplice, consente di accedere a una ricca gamma di funzionalità integrate nella shell: una varietà di layout di formattazione; conversione in HTML; opzioni di esportazione; possibilità di ordinamento, filtraggio e raggruppamento e molto altro ancora.

Figura 2 Output dei dati di Windows PowerShell nel formato HTML

Figura 2** Output dei dati di Windows PowerShell nel formato HTML **(Fare clic sull'immagine per ingrandirla)

Si tratta di funzionalità molto potenti. Infatti, non esito a consigliare di scrivere tutti gli script in modo da produrre un oggetto come output, che potrà quindi essere utilizzato nei modi più diversi senza ricorrere alla scrittura di una sola riga di codice aggiuntiva.

Don Jones è un esperto di automazione dell'amministrazione di Windows e ha scritto libri come Windows PowerShell: TFM e VBScript, WMI, and ADSI Unleashed. È possibile contattarlo nei forum del sito ScriptingAnswers.com.

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