Windows PowerShellFiltraggio e formattazione dei dati

Autore: Don Jones

Per qualsiasi problema Windows PowerShell può restituire una grande quantità di informazioni utili, senza richiedere grande intervento da parte dell'utente. Ad esempio, consideriamo il semplice cmdlet Get-WMIObject che può essere utilizzato per restituire un elenco di servizi sul computer locale. La visualizzazione predefinita che elenca lo stato, il nome e la modalità di avvio dei

servizi in esecuzione è essenzialmente una visualizzazione della riga di comando della console dei servizi. Windows PowerShell™ consente di ottenere questa visualizzazione molto più facilmente.

Ma per i servizi sono disponibili molte informazioni più utili di quelle illustrate nella visualizzazione predefinita. Provare a eseguire questo comando:

$s = get-wmiobject win32_service
$s[0] | gm

La prima riga del comando restituisce una raccolta di tutti i servizi o, nello specifico, di tutte le istanze della classe Win32_Service da Windows® Management Instrumentation (WMI), e li memorizza nella variabile $s. Nella seconda riga si trova il primo servizio di tale raccolta (con il numero zero, indicato nelle parentesi quadre) e lo invia al cmdlet Get-Mem­ber che ho abbreviato utilizzando il relativo alias, gm. L'output risultante illustra tutte le proprietà e i metodi disponibili per quel tipo di dati. Ho deciso di utilizzare la classe Win32_Service in WMI invece del cmdlet Get-Service incorporato in Windows PowerShell perché WMI espone maggiori informazioni di quelle fornite dall'oggetto Service­Controller di Microsoft® .NET, compresa la proprietà Start­Name. Tale proprietà mi fornisce il nome dell'account utente per il quale il servizio è in esecuzione. È possibile controllare il nome di una singola istanza, come la prima, nel modo seguente:

PS C:\> $s[0].StartName
LocalSystem

Occorre tenere presente che fare riferimento ai servizi in base al relativo numero ordinale all’interno della raccolta non è molto utile poiché i servizi non sono disposti con un particolare ordine. Sono infatti elencati di solito alfabeticamente, ma non sempre. Dal punto di vista della gestione, è probabilmente più interessante un elenco di tutti i servizi e l'account utilizzato per registrarsi. Questo sarebbe utile per un controllo della conformità. Dunque torniamo indietro un secondo e guardiamo quanto fornisce WMI per impostazione predefinita. Utilizzerò l’alias più breve di Get-WMIObject, gwmi (vedere la Figura 1).

Figure 1 Utilizzo di Gwmi

PS C:\> gwmi win32_service

ExitCode  : 0
Name      : AcrSch2Svc
ProcessId : 1712
StartMode : Auto
State     : Running
Status    : OK

ExitCode  : 1077
Name      : Adobe LM Service
ProcessId : 0
StartMode : Manual
State     : Stopped
Status    : OK

Questo è ovviamente solo un esempio, ma è possibile osservare che l'output non è realmente innovativo per un report gestionale. Ciò che voglio sapere è il nome del servizio e StartName, che è l'account per il quale viene eseguito il servizio. Voglio recuperare anche il report in un formato più leggibile rispetto a questo elenco, un po’ difficile da osservare. Ecco dove entrano in ballo i formidabili cmdlet di formattazione e filtraggio dei dati di Windows PowerShell.

Come ottenere i dati necessari

Inizio filtrando i dati provenienti da Get-WMIObject in modo che le proprietà che mi interessano siano visualizzate. Il modo migliore per farlo è di utilizzare il cmdlet di Windows PowerShell Select-Object o il relativo alias semplice, select. Select è progettato per accettare una raccolta di oggetti, come la raccolta restituita da Get-WMIObject, e per visualizzare solo le proprietà desiderate di tali oggetti. Questo significa che posso inviare l'output di gwmi per selezionare e specificare le due proprietà che mi interessano. Nella Figura 2 vengono illustrati i risultati che comprendono le proprietà Name e StartName formattate come una tabella.

Figura 2 Visualizzazione in una tabella delle sole proprietà Name e StartName

Figura 2** Visualizzazione in una tabella delle sole proprietà Name e StartName **(Fare clic sull'immagine per ingrandirla)

Se lo producessi per un controllo di conformità, questo report conterrebbe in realtà troppe informazioni. Alcuni dei servizi sono disattivati, quindi molto probabilmente non importerebbe a nessuno leggere nell'output quale account verrebbe utilizzato dai servizi disattivati. Quindi applico un filtro che esclude tutti i servizi aventi un tipo di avvio Disabled, cioè la proprietà StartMode della classe Win32_Service.

Windows PowerShell esegue il filtraggio degli oggetti utilizzando il cmdlet Where-Object o il relativo alias più breve, where. Il cmdlet where accetta una raccolta di oggetti di input ed esegue su ciascun oggetto uno scriptblock per determinare se ogni oggetto sarà presente nell’output di cmdlet in base a un set di criteri definiti. Ogni oggetto che risponde a tali criteri produce il valore True per il confronto e viene inserito nell'output. Gli oggetti che producono un valore False non vengono inseriti.

In tal modo, ho stabilito che mi interessano soltanto gli oggetti la cui proprietà StartMode è uguale a Disable. In Windows PowerShell, questa valutazione appare nel modo seguente:

$object.StartMode –eq “Disabled”

Naturalmente, $object è solo un esempio. In realtà non sto scrivendo uno script e quindi non dispongo di una variabile denominata $object. All’interno di uno scriptblock utilizzato da where, tuttavia, utilizzo una speciale variabile denominata $_ che rappresenta l'oggetto in corso di valutazione da parte del cmdlet. Dunque, il mio scriptblock di where potrebbe somigliare al seguente:

$_.StartMode –eq “Disabled”

Posso testarlo abbastanza facilmente:

PS C:\> gwmi win32_service | where 
{$_.StartMode -eq “Disabled”}

ExitCode  : 1077
Name      : Alerter
ProcessId : 0
StartMode : Disabled
State     : Stopped
Status    : OK

Certo, in questo test veloce, l'output viene nuovamente visualizzato con lo stile di elenco predefinito. E, per ridurre lo spazio utilizzato, ho incluso soltanto un servizio. Ma si noterà che questo output è al contrario: ho incluso i servizi disattivati invece di escluderli. Ecco perché ho ottenuto il mio scriptblock al contrario: Devo includere tutti i servizi quando StartMode non è uguale a Disable, come illustrato da questo esempio modificato:

PS C:\> gwmi win32_service | where 
{$_.StartMode -ne “Disabled”}

ExitCode  : 0
Name      : AcrSch2Svc
ProcessId : 1712
StartMode : Auto
State     : Running
Status    : OK

Ora va meglio! Adesso che l'output contiene soltanto i servizi che mi interessano realmente, posso inviare ancora una volta l'output scelto e specificare le proprietà che desidero:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | select name,startname

Questa operazione di invio dati da un cmdlet a un altro e a un altro ancora spiega realmente le funzionalità di Windows PowerShell. Non ho scritto ancora uno script, tuttavia per ora sono riuscito a filtrare un grande set di dati per ottenere proprio l'output che cerco.

Il look "giusto"

Si noti che l'output di select è ancora un insieme di oggetti. Quando recupero una tabella ben formattata utilizzando Windows PowerShell, PowerShell.exe esegue effettivamente il rendering di quegli oggetti. In altre parole, poiché non posso vedere gli oggetti, Windows PowerShell ne esegue il rendering restituendoli come testo. In questo caso, esegue il rendering degli oggetti restituendoli come tabella, con una colonna per ogni proprietà, come illustrato nella Figura 2.

Questo può essere sufficiente per i miei scopi di controllo. D'altra parte, potrebbe non essere del tutto vero. Ognuno ha esigenze differenti e Windows PowerShell non presume di sapere quali sono. Fornisce invece gli strumenti per formattare l'output in qualsiasi modo per adattarlo meglio alle esigenze dell’utente. Quattro cmdlet incorporati, Format-List, Format-Custom, Format-Table e Format-Wide, sono progettati per accettare una raccolta di oggetti (come la raccolta restituita da select) e formattare quegli oggetti in vari modi. Format-Table è in sostanza ciò che Windows PowerShell utilizza già per formattare l'output del mio cmdlet di select. Per un approccio diverso, utilizziamo Format-List:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | format-list

Il risultato si presenta più o meno come in questo esempio:

name      : AcrSch2Svc
startname : LocalSystem

name      : Adobe LM Service
startname : LocalSystem

Il cmdlet Format-Wide è progettato per produrre un elenco a più colonne, per impostazione predefinita, della prima proprietà da ogni oggetto. Prendiamo questa riga, ad esempio:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} |
 select name,startname | format-wide

Questa produce un elenco di nomi di servizi che non mi interessano. L'output non contiene StartName (vedere la Figura 3), che è un'informazione necessaria per il mio report di controllo.

Figura 3 L'output visualizzato utilizzando il cmdlet Format-Wide omette una informazione chiave: StartName

Figura 3** L'output visualizzato utilizzando il cmdlet Format-Wide omette una informazione chiave: StartName **(Fare clic sull'immagine per ingrandirla)

Poiché mi sto occupando soltanto di due proprietà, è probabile che Format-Table e Format-List siano accettabili. Ma è improbabile che un revisore accetti di guardare queste informazioni sullo schermo. Preferirebbe probabilmente un file di tipo diverso.

Esportazione dati

Mettiamoci nei panni di un revisore: come preferirebbe visualizzare i dati? Potrebbe essere sufficiente esportare l'elenco di servizi e dei nomi di accesso in un file CSV (Comma-Separated Values), poiché il file può essere poi facilmente aperto in Microsoft Excel®. Per creare un file CSV, inviare semplicemente il proprio output al cmdlet di Windows PowerShell Export-CSV:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | export-csv c:\services.csv

Naturalmente oggi CSV sembra un po’ sorpassato. Forse i revisori preferirebbero che i dati fossero visualizzati come pagina Web su un server Intranet. A tal fine, è possibile iniziare convertendo l'output in HTML, utilizzando il cmdlet ConvertTo-HTML:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | convertto-html

L’HTML non elaborato è difficile da visualizzare, dunque sarà necessario scrivere l'output in un file:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | convertto-html | out-file c:\services.html

Il risultato, come illustrato nella Figura 4, è una pagina HTML ben formattata che è possibile inviare su qualsiasi server Web senza ulteriori modifiche.

Figura 4 Output visualizzato come pagina HTML ben formattata

Figura 4** Output visualizzato come pagina HTML ben formattata **(Fare clic sull'immagine per ingrandirla)

Semplici fatti (fondamentali)

Windows PowerShell fornisce un rapido accesso a una vasta gamma di dati gestionali. Nello stato non elaborato, tuttavia, questi dati non sono sempre utili.

Filtrando i dati (utilizzando where), scegliendo le proprietà desiderate dell'oggetto (utilizzando select) e applicando un'opzione di formattazione appropriata (come Format-Table o Format-List) è possibile convertire rapidamente e facilmente questi dati in utili informazioni. In seguito, esportando i dati in formato file, che può essere condiviso facilmente, è possibile elaborare queste informazioni nel proprio desktop e comunicare informazioni utili ad altre persone della propria organizzazione

Autore: Don Jones Don Jones è il direttore progetti e servizi di SAPIEN Technologies e coautore di Windows PowerShell: TFM (SAPIEN Press). Contatta Don nel suo sito Web all'indirizzo www.ScriptingAnswers.com.

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