Hey, Scripting Guy!Anche chi non lavora troppo duramente avrà le sue ricompense

I Microsoft Scripting Guy

Scarica il codice per questo articolo: HeyScriptingGuy2008_06.exe (150KB)

Per centinaia di anni, le persone hanno creduto che il lavoro duro rappresentasse in se stesso una ricompensa, che la vera soddisfazione fosse nello svolgere un lavoro onesto e che la vera felicità derivasse dalla meta da raggiungere e non dal viaggio da intraprendere. Bisogna lavorare sodo e senza lamentarsi (tipo Cenerentola) e, un giorno, verremo ricompensati.

Nota: ma è realmente vero che se si lavora duramente si sarà più felici e, un giorno, si verrà anche ricompensati? Perché ci si fa una domanda del genere?

Ovviamente, Cenerentola era fortunata; dopotutto, se si vive con una perfida matrigna e due perfide sorellastre, si avrà certamente l'opportunità di lavorare sodo. Ma per chi non è così fortunato? Cosa accade a chi non vive con una perfida matrigna e due perfide sorellastre? In che modo potrà fare un lavoro lungo ed estenuante? Come potrà mai riuscire a trovare la vera felicità?

Se si è destinati e determinati a lavorare sodo, gli Scripting Guy suggeriscono di provare a scrivere uno script che generi un output di dati in un formato tabulare preciso, come quello mostrato nella Figura 1.

Figura 1 Output tabulare

Figura 1** Output tabulare **(Fare clic sull'immagine per ingrandirla)

Come abbiamo già detto, Cenerentola era molto fortunata: poteva pulire la casa da cima a fondo e, dopo aver finito, poteva tranquillamente restarsene seduta tra la cenere e la fuliggine. Ma anche Cenerentola sarebbe stata riluttante a scrivere uno script per visualizzare i dati in formato tabulare. Rimanersene seduti tra la cenere e la fuliggine è una cosa. Scrivere uno script che generi un output di dati in formato tabulare è una cosa completamente diversa.

Nota: sono cose diverse se non si è costretti a starsene seduti vicino al focolare per scrivere lo script; in caso contrario, le due cose corrispondono.

Perché Cenerentola dovrebbe essere riluttante nei confronti di questa attività? Semplicemente perché è maledettamente faticosa. L'unico modo per visualizzare i dati in formato tabulare in VBSCRIPT è eseguire una delle operazioni indicate:

  • Iniziare determinando le dimensioni massime per ogni colonna. Ad esempio, si potrebbe desiderare che il nome visualizzato di un servizio sia di 52 spazi di carattere.
  • Partendo da ciò, calcolare il numero di caratteri in una parte di dati. Ad esempio, il nome visualizzato Adobe LM Service ha 16 caratteri.
  • Se il nome visualizzato supera il limite di 52 caratteri, determinare il numero di caratteri da eliminare per fare in modo che la stringa rientri nello spazio assegnato. Se il nome supera i 52 caratteri, determinare quanti spazi vuoti devono essere aggiunti alla fine della stringa per fare in modo che sia lunga esattamente 52 caratteri.
  • Ripetere la stessa procedura per il set di dati successivo. Quindi, farlo anche per quello dopo e così via.

Se si conosce bene la storia di Cenerentola, si saprà anche che la fatina buona potrebbe arrivare in qualsiasi momento, trasformare il mouse in un amministratore di sistema (in modo semplicissimo) e fare in modo che questi scriva lo script per noi. Ma non si dovrebbe fare troppo affidamento sul fatto che ciò accada. Probabilmente si è soli in questa iniziativa.

Tuttavia, il lato positivo è che potremo essere le persone più soddisfatte del mondo. E questo perché saremo le persone che sgobbano di più al mondo. Quelle che svolgono il lavoro di gran lunga più duro.

Alcuni certamente preferirebbero barattare una parte di soddisfazione con la possibilità di non dover lavorare così duramente. Ma non siamo noi quelle persone; probabilmente si starà pensando: "Grazie al cielo, ci sono gli Scripting Guy; mi diranno come fare per trasformare un mouse in un amministratore di sistema e riuscire a generare un output in formato tabulare". Ebbene, ci dispiace, ma ci sono delle cattive notizie: gli Scripting Guy non hanno assolutamente idea di come fare per trasformare un mouse in un amministratore di sistema. (Tuttavia, siamo in grado di trasformare un amministratore di sistema in un mouse, se essere utile.) Non sappiamo dire come si può spingere qualcuno a scrivere script per noi e tanto meno script che generino dati in formato tabulare.

Ma non c'è da preoccuparsi. Finché si esegue Windows® XP o Windows Server® 2003 (come fanno in molti), non si avrà bisogno di un mouse che scriva gli script per noi. (Ci dispiace, ma con Windows Vista® le cose sono diverse.) Potremo farlo da soli, e con il minimo sforzo, grazie all'oggetto Microsoft.CmdLib. A questo punto, osservare lo script di esempio della Figura 2.

Figure 2 Creazione di una visualizzazione tabulare

Dim arrResultsArray()
i = 0

Set objCmdLib = _
  CreateObject("Microsoft.CmdLib")
Set objCmdLib.ScriptingHost = _
  WScript.Application

arrHeader = Array("Display Name", _
  "State", "Start Mode")
arrMaxLength = Array(52, 12, 12)
strFormat = "Table"
blnPrintHeader = True
arrBlnHide = Array(False, False, False)

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" _
  & strComputer & "\root\cimv2")

Set colServices = objWMIService.ExecQuery _
  ("Select * FROM Win32_Service")

For Each objService In colServices
  ReDim Preserve arrResultsArray(i)
  arrResultsArray(i) = _
  Array(objService.DisplayName, _
    objService.State,objService.StartMode)
  i = i + 1
Next
objCmdLib.ShowResults arrHeader, _
  arrResultsArray, arrMaxLength, _
  strFormat, blnPrintHeader, arrBlnHide

Microsoft.CmdLib è un oggetto COM fornito con Windows XP e Windows Server 2003. Quest'oggetto dispone di un'ampia serie di funzioni; per ulteriori informazioni, digitare cmdlib.wsc /? al prompt dei comandi e leggere i commenti nel file script visualizzato. Per ora, ci interessa unicamente la funzionalità di Microsoft.CmdLib, ovvero la capacità di visualizzare i dati in formato tabulare.

Ciò conduce a una domanda ovvia: come fare per visualizzare i dati in formato tabulare? Vediamo se riusciamo a capirlo. Come è evidente, il nostro script di esempio inizia definendo un array dinamico denominato arrResultsArray:

Dim arrResultsArray()

In uno script tradizionale, i dati vengono riprodotti sullo schermo man mano che vengono recuperati. Ma perché ci si dovrebbe aspettare che gli Scripting Guy facciano qualcosa in maniera tradizionale? In questo script, non desideriamo visualizzare i dati sullo schermo man mano che vengono recuperati. Intendiamo invece archiviare tutti i dati restituiti in un array e quindi consentire a Microsoft.CmdLib di formattarli e visualizzarli al posto nostro.

In altre parole, questo è il motivo per il quale iniziamo creando un array dinamico (ovvero, un array che possa essere ridimensionato durante il corso dello script). Dopo aver definito l'array, impostiamo su 0 il valore di una variabile contatore denominata i; utilizzeremo questa variabile per tenere traccia delle dimensioni correnti dell'array.

A questo punto, impostiamo il valore di i su 0 perché il primo elemento di un array è sempre il numero di indice 0. Di conseguenza, quando aggiungiamo il primo elemento all'array, aggiungiamo l'elemento 0 anziché l'elemento 1.

Quindi, dobbiamo inizializzare la nostra istanza dell'oggetto Microsoft.CmdLib; le due righe di codice riportate di seguito hanno questo scopo:

Set objCmdLib = _
CreateObject("Microsoft.CmdLib")
Set objCmdLib.ScriptingHost = WScript.Application

E ciò ci porta a questo piccolo blocco di codice:

arrHeader = Array("Display Name", "State", "Start Mode")
arrMaxLength = Array(52, 12, 12)
strFormat = "Table"
blnPrintHeader = True
arrBlnHide = Array(False, False, False)

Ciò che stiamo facendo è impostare alcuni parametri per configurare il nostro output. Nella prima riga, assegniamo dei valori a un array denominato arrHeader; come previsto, sono le intestazioni per ciascuna delle colonne della nostra tabella di output. Per questo script di esempio, recupereremo le informazioni sui servizi in esecuzione su un computer e quindi visualizzeremo i valori delle proprietà DisplayName, State e StartMode per ogni servizio.

In modo abbastanza prevedibile, assegneremo al nostro array i nomi di colonna Nome visualizzato, Stato e Modalità di avvio (anche se avremmo potuto assegnare alle colonne i nomi A, B, e C; Larry e Moe o qualsiasi altro nome dato che non è necessario che i nomi delle colonne corrispondano ai nomi delle proprietà).

Nota: esistono molte varianti della storia di Cenerentola, che riguardano anche i nomi delle due sorellastre. Nella versione di Disney, le sorellastre si chiamano Genoveffa e Anastasia, che per caso corrispondono proprio al primo e secondo nome del nostro editor di script!

Nella seconda riga del codice, assegniamo dei valori a un altro array, denominato arrMaxLength. Questo array include le dimensioni di ogni colonna della tabella. Nel nostro output, desideriamo allocare 52 spazi di carattere alla colonna 1 (il nome visualizzato del servizio); allocheremo quindi 12 spazi ciascuno alla modalità di avvio e allo stato del servizio. (Microsoft.CmdLib inserirà automaticamente uno spazio vuoto tra le colonne.) Se desideriamo (come in questo caso) che le colonne abbiamo dimensioni di 52, 12 e 12 spazi di carattere, utilizzeremo un codice simile al seguente:

arrMaxLength = Array(52, 12, 12)

La terza riga specifica il formato di output per i nostri dati. Desideriamo che i dati vengano visualizzati sotto forma di tabella; pertanto, impostiamo su Table il valore di strFormat (la variabile che contiene il tipo di output). Supponiamo invece di voler visualizzare i dati sotto forma di elenco di valori delimitati da virgole. In quel caso, dovremmo impostare il formato CSV, come indicato:

strFormat = "CSV"

In questo modo, otterremmo un output simile al seguente:

"Display Name","State","Start Mode"
"Adobe LM Service","Stopped","Manual"
"Adobe Active File Monitor V4","Stopped","Manual"
"Alerter","Stopped","Manual"
"Application Layer Gateway Service","Running","Manual"
"Apple Mobile Device","Running","Auto"
"Application Management","Stopped","Manual"

Microsoft.CmdLib inserisce virgole tra un elemento e l'altro e racchiude i singoli valori tra virgolette. Questa funzione è più preziosa di quanto si potrebbe pensare di primo impatto. Dopotutto, per fare tutto ciò manualmente, si dovrebbe utilizzare un codice di questo tipo:

Wscript.Echo Chr(34) & objService.DisplayName & Chr(34) & "," & Chr(34) & objService.State & Chr(34) & "," & Chr(34) & objService.StartMode & Chr(34)

Complicato, vero?

Cosa c'è? Non piacciono le tabelle, ma neanche il formato CSV? Bene, in tal caso si può provare a impostare il formato su List si otterrà un output simile al seguente:

Display Name: Adobe LM Service
State:        Stopped
Start Mode:   Manual
Display Name: Adobe Active File Monitor V4
State:        Stopped
Start Mode:   Manual

Ma così stiamo facendo una digressione. (Come siamo inclini a fare di tanto in tanto.) Dopo aver definito il formato di output, impostiamo su True il valore di una variabile denominata blnPrintHeader:

blnPrintHeader = True

Utilizzeremo quindi blnPrintHeader per specificare che Microsoft.CmdLib stampi le intestazioni di colonna. Cosa fare se invece non vogliamo stampare le intestazioni di colonna? Bene, in tal caso è necessario impostare blnPrintHeader su False:

blnPrintHeader = False

In questo modo, otterremo questa riga di codice:

arrBlnHide = Array(False, False, False)

Quando arriva il momento di visualizzare i dati, Microsoft.CmdLib ci offre l'opportunità di visualizzare o nascondere una colonna. Per nascondere una colonna (ovvero, per sopprimere i dati per una particolare proprietà), impostare il valore della proprietà su False; per visualizzare una colonna, impostare il valore su False.

Nel nostro output, visualizzeremo i valori per la proprietà DisplayName, State e StartMode, esattamente in tale ordine; quindi, utilizzeremo i valori False, False, False nell'array. Cosa fare per visualizzare DisplayName, nascondere State e visualizzare StartMode? In tal caso, utilizzeremmo questa riga di codice:

arrBlnHide = Array(False, True, False)

Ricordare sempre di utilizzare False per visualizzare una colonna e True per nasconderla.

A questo punto, siamo pronti per generare dei dati, o lo saremmo se avessimo dei dati. (Gli Scripting Guy hanno mai scritto uno script che non riesce a generare dati e quindi impiegato una smisurata quantità di tempo per eseguire il debug dello script e scoprire, infine, che non avrebbero dovuto recuperare alcun dato inizialmente? No, naturalmente; cosa potrebbe mai farlo pensare?)

Ricordando ciò, la nostra prossima operazione consisterà nell'eseguire l'associazione al servizio Strumentazione gestione Windows (WMI) sul computer locale e quindi nell'utilizzare il metodo ExecQuery per recuperare le informazioni su tutti i servizi installati su tale computer:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colServices = objWMIService.ExecQuery ("Select * FROM Win32_Service")

Probabilmente dovremmo ricordare che in questo caso non si ha l'obbligo di lavorare con i dati WMI. Come previsto, Microsoft.CmdLib può funzionare con qualsiasi tipo di dati. WMI è semplicemente un metodo facile per recuperare una serie di dati.

Una volta ottenuta la nostra raccolta di dati relativi ai servizi, impostiamo un ciclo For Each per eseguire tutti i servizi nella raccolta. Tuttavia, anziché restituire i valori delle proprietà per ogni servizio, eseguiamo questo codice:

ReDim Preserve arrResultsArray(i)
arrResultsArray(i) = Array(objService.DisplayName, objService.State,objService.StartMode)
i = i + 1

Cosa facciamo in questo blocco di codice? Bene, nella riga 1 ridimesioniamo il nostro array, utilizzando il comando ReDim Preserve anche per preservare gli eventuali dati esistenti nell'array. (Senza la parola chiave Preserve, l'array verrebbe ridimesionato, ma gli eventuali dati inclusi nell'array verrebbero cancellati.)

Quali dimensioni abbiamo scelto per l'array? La prima volta che eseguiamo il ciclo, creiamo un array di dimensioni pari a 0; in altre parole, creiamo un array contenente un unico elemento. E come possiamo esser certi di creare un array di dimensioni pari a 0? Perché utilizziamo la variabile contatore i, che è uguale a 0.

Quindi, se utilizzassimo la variabile i per rappresentare le dimensioni dell'array, vorrebbe dire che impostiamo le dimensioni su 0? Sì, è così, tranne se incrementiamo il valore di i di 1 ogni volta che eseguiamo il ciclo; come è evidente, è esattamente ciò che facciamo nella riga 3 del nostro blocco di codice.

In questo modo, ci resta un'unica riga di codice a cui pensare:

arrResultsArray(i) = Array(objService.DisplayName, objService.State,objService.StartMode)

In questo esempio, prendiamo semplicemente in considerazione i valori delle proprietà desiderati (DisplayName, State e StartMode) e li aggiungiamo all'array arrResultsArray. Non intendiamo aggiungere il valore di ogni singola proprietà, ma preferiamo aggiungerli come array di valori. È vero, la cosa è un po' insolita: significa che ogni elemento dell'array arrResultsArray sarà un altro array; Microsoft.CmdLib funziona esattamente in questo modo.

Ovviamente, ciò potrebbe essere fonte di ulteriori preoccupazioni. "Un array di array? In che modo posso mai accedere a ogni singolo valore in un array pieno di array?" Non bisogna allarmarsi. È semplice: è sufficiente lasciare il compito a Microsoft.CmdLib.

Nota: ci dispiace, ma accedere ai singoli valori di un array di array è esattamente l'unica cosa che Microsoft.CmdLib può fare per noi. Tuttavia, pulire le camere della nostra perfida matrigna, lavare i piatti e cucire i vestiti delle nostre perfide sorellastre vengono considerate attività adatte alla versione successiva dell'oggetto.

In realtà, possiamo generare l'output dei nostri dati in un formato tabulare preciso semplicemente chiamando il metodo ShowResults e passandolo a tutti gli array e le variabili configurati in precedenza nello script:

objCmdLib.ShowResults arrHeader, arrResultsArray, arrMaxLength, strFormat, blnPrintHeader, arrBlnHide

Quali risultati si otterranno? Si otterrà esattamente l'output ben formattato che speravamo di ottenere quando abbiamo osservato la Figura 1.

Non male, no? Si ottiene l'output desiderato e quasi senza svolgere alcuna attività. (E il prossimo script sarà anche più facile, perché sarà semplicemente necessario apportare alcune piccole modifiche a questo primo script.)

A questo punto, bisogna ammetterlo, non si proverà lo stesso senso di soddisfazione provato da Cenerentola che sgobba tutto il giorno per visualizzare l'output dello script in una tabella. E, a essere sinceri, probabilmente non si riuscirà neanche a trovare un principe azzurro da sposare; ma ciò non rientra nell'accordo. Tra l'altro, sembra un prezzo da pagare davvero piccolo per riuscire a ottenere l'output ideale da uno script VBScript, soprattutto se si pensa a come sono i principi azzurri al giorno d'oggi.

E chissà: si potrebbe ugualmente riuscire a trovare un principe azzurro. Dopotutto, anche i principi hanno bisogno di ottenere informazioni su tutti i servizi installati sui loro computer, non è vero?

Il rompicapo di script del Dottor Scripto

La sfida mensile che verifica non solo le sue capacità di risoluzione dei puzzle, ma anche le sue competenze di scripting.

Giugno 2008: Percorso di attivazione di PowerShell

In ciascuno di questi puzzle, associare le lettere in orizzontale, verticale e diagonale per creare il nome di cmdlet di Windows PowerShell. Ogni lettera verrà utilizzata una sola volta: Ecco un esempio:

Il cmdlet creato in questo puzzle è New-Alias. Adesso è il suo turno. Ecco altri tre puzzle:

ANSWER:

Il rompicapo di script del Dottor Scripto

Risposte: Percorso di attivazione di PowerShell, giugno 2008

Read-Host

br />Set-AuthenticodeSignature

I Microsoft Scripting Guy lavorano o, per meglio dire, sono stipendiati da Microsoft. Quando non si dedicano al baseball (o a varie altre attività) da giocatori, allenatori o semplici spettatori, gestiscono il TechNet Script Center. Consultare la pagina www.scriptingguys.com.

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