Windows PowerShellTeoria sulle stringhe

Don Jones

Indice

Un caso reale
Corrispondenze complesse
È un mondo di stringhe

Quando parlo alle conferenze, come Tech•Ed o TechMentor, mi ritrovo spesso a fare dichiarazioni di natura generale che aiutano gli utenti a ricordare le informazioni più importanti su argomenti come Windows PowerShell. La mia ultima dichiarazione è: "Se analizzi una stringa in Windows PowerShell, stai facendo una cosa sbagliata".

Questo deriva dalla mia filosofia in base alla quale Windows PowerShell™ è una shell orientata agli oggetti. Se si eseguono operazioni come copiare elenchi di servizi in un file di testo e analizzare tale file per vedere quali servizi sono stati avviati, si sta sprecando del tempo. Si tratta di un approccio valido in un sistema operativo basato su testo come UNIX, ma Windows PowerShell (come pure Windows®) consente di utilizzare gli oggetti in modo molto più efficiente.

Anche gli script utilizzati dovrebbero produrre oggetti, non testo formattato, in modo che la formattazione, i filtri, l'esportazione e gli altri comandi della shell possano essere utilizzati per manipolare l'output degli script. (Il mio articolo di luglio 2008 su Windows PowerShell contiene ulteriori informazioni sul concetto degli oggetti personalizzati come output degli script).

Alla recente conferenza TechMentor di Orlando, Florida, uno dei miei studenti mi ha ricordato che quasi tutte le regole, e soprattutto quelle generali, hanno delle eccezioni. "E per quanto riguarda la ricerca di informazioni in un file di registro di IIS? In questo caso non bisogna analizzare il testo?".

Effettivamente sì. E fortunatamente, per quanto possa essere orientato agli oggetti, Windows PowerShell non delude quando si tratta di analizzare stringhe di testo. Pensandoci bene, i file di registro di IIS, i file di registro del firewall e altri file di registro basati su testo costituiscono esempi perfetti.

Un caso reale

In passato ho dovuto analizzare una serie di file di registro del firewall per un'azienda per la quale lavoravo. Un dipendente era stato sorpreso a consultare alcuni siti Web inappropriati e, come parte dell'indagine che ne seguì, l'ufficio delle risorse umane aveva bisogno di un elenco completo dei siti Web che aveva visitato. Estrarre queste informazioni dal file di registro di un solo giorno già non è tanto semplice, e il personale delle risorse umane voleva avere informazioni relative a intere settimane — un'operazione che non avevo intenzione di eseguire manualmente.

Il server DHCP (Dynamic Host Configuration Protocol) dell'azienda indicava che il computer del dipendente aveva utilizzato lo stesso indirizzo IP (ad esempio 192.168.17.54) per diversi mesi. Questo non è insolito, poiché si trattava di un computer desktop che non veniva spento quasi mai. E poiché il file di registro del firewall conteneva informazioni sugli indirizzi IP di origine, sapevo che Windows PowerShell avrebbe potuto aiutarmi.

Il segreto sta nel comando Select-String, che viene spesso trascurato. Occorre anche una certa conoscenza delle espressioni regolari (di cui ho parlato nell'articolo di novembre 2007 riguardante Windows PowerShell).

Il comando Select-String accetta un percorso pieno di file di testo, un'espressione regolare o semplicemente una stringa da ricercare. Restituisce quindi tutte le righe di ciascun file di registro che corrispondono all'espressione regolare o alla semplice stringa. Per iniziare l'operazione, volevo semplicemente ottenere tutte le righe contenenti l'indirizzo IP del computer desktop del dipendente. Ogni riga del file di registro conteneva un timbro data/ora, che è proprio quello che cercava l'ufficio delle risorse umane.

Ecco il comando:

select-string -path c:\logs\*.txt -pattern "192.168.17.54" 
-allmatches –simplematch

Il parametro -simpleMatch specifica che il modello che ho fornito è una stringa semplice, non un'espressione regolare. La Figura 1 illustra una parte dell'output, che potrebbe anche essere trasferito in un file. È importante notare che l'output comprende sia il nome del file sia il numero della riga in cui è stata rilevata la corrispondenza, che può risultare molto utile se a un certo punto si desidera ritornare ai risultati e cercare ulteriori informazioni.

Cmdlet del mese: Start-Sleep

Si tratta di un cmdlet che può offrire proprio quello che serve nel corso di una lunga giornata di lavoro... un pisolino! Start-Sleep offre una piccola pausa, per gli script Windows PowerShell.

Non è insolito che ci sia bisogno di una pausa veloce in uno script. Se, ad esempio, occorre avviare un servizio, si consiglia di attendere alcuni secondi in modo che si avvii, quindi eseguire altre operazioni che dipendono da tale servizio. Start-Sleep è proprio quello che serve per questo tipo di comportamento. Se ad esempio si esegue Start-Sleep 10, la shell farà una pausa di 10 secondi. Se occorre esercitare un controllo più preciso, è possibile eseguire Start-Sleep -milli 100, ad esempio, per fare una pausa di 100 millisecondi. Start-Sleep sospende completamente la shell, compresi gli script, le pipeline e tutto il resto, per il periodo di tempo specificato. Sarebbe proprio bello se qualcuno si decidesse a scrivere il famoso cmdlet Start-Pisolino che aspetto da tanto tempo...

fig01.gif

Figura 1 Output del comando Select-String (fare clic sull'immagine per ingrandirla)

Corrispondenze complesse

Dopo che ho passato al personale delle risorse umane le informazioni che mi avevano chiesto, si sono accorti che non era quello che volevano. Il mio report indicava visite a vari indirizzi IP, come 207.68.172.246 (il sito Web MSN®). La richiesta successiva consisteva nel semplificare il mio report, in modo che contenesse soltanto le visite a un indirizzo IP specifico, che corrispondeva a uno dei siti Web inappropriati. In questo articolo, non rivelerò il vero indirizzo IP della ricerca. Utilizzerò 207.68.172.246 come esempio (sebbene il sito Web MSN solitamente non sia considerato inappropriato).

Questa richiesta potrebbe sembrare un po' più difficile. Nel file di registro su cui stavo lavorando, gli indirizzi IP di origine e di destinazione si trovavano l'uno accanto all'altro ed erano separati da una virgola. Quindi potevo semplicemente modificare la mia stringa di ricerca in "192.168.17.54,207.68.172.246" e ripetere la ricerca.

In un file di registro più complesso, tuttavia, è possibile che siano presenti dati variabili memorizzati tra i due indirizzi IP, quindi la semplice corrispondenza della stringa non è sufficiente. In tale scenario è necessario utilizzare un'espressione regolare, che funziona bene anche per i formati di file di registro più semplici, come dimostrerò qui.

All'interno di un'espressione regolare, il punto è un carattere jolly che indica un carattere qualsiasi. È possibile utilizzare l'espressione secondaria (.)* per cercare un numero qualsiasi di caratteri tra i miei due indirizzi IP. Tuttavia, è necessario utilizzare una barra rovesciata per evitare i punti letterali che compaiono negli indirizzi IP stessi.

Il comando risultante è:

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" –allmatches

Ho rimosso il parametro -simpleMatch perché questa volta utilizzo un'espressione regolare. L'output risultante illustra soltanto le visite effettuate dal computer del dipendente a un sito Web specifico identificato come inappropriato. L'output comprende anche le informazioni sulla data e l'ora che erano state richieste dal personale delle risorse umane. La Figura 2 illustra una porzione di output che potrebbe essere generata quando si esegue un comando come questo.

fig02.gif

Figura 2 Risultati della ricerca semplificati che illustrano soltanto le visite a un sito specifico (fare clic sull'immagine per ingrandirla)

Tuttavia, posso anche migliorare l'output utilizzando il comando Format-Table e visualizzare le colonne calcolate. Nella tabella è possibile includere il nome del file di registro e il numero di riga in cui è stata trovata la corrispondenza, ed è anche possibile visualizzare la riga stessa in cui la corrispondenza è stata rilevata. Tuttavia, farò anche in modo che la shell sostituisca la corrispondenza dell'espressione regolare con una stringa vuota, in modo che venga visualizzato soltanto il resto della riga, con le informazioni sulla data e l'ora nel mio esempio. Si tratta di un suggerimento avanzato, ma dimostra ulteriormente come Windows PowerShell sia in grado di manipolare i dati delle stringhe e produrre output estremamente personalizzato, il tutto con un'unica riga di comando:

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" -allmatches | 
ft  filename,linenumber,@{"Label"="Time";
"Expression"={$_.line.replace
($_.matches[0],"")}} –auto

La Figura 3 illustra i possibili risultati finali che potrei ottenere.

fig03.gif

Figura 3 Output formattato da un comando Select-String (fare clic sull'immagine per ingrandirla)

È un mondo di stringhe

Sono sempre pronto a riconoscere la natura orientata agli oggetti di Windows PowerShell come uno dei suoi maggiori punti di forza. Tuttavia, vi sono situazioni in cui gli oggetti non aiutano.

Windows PowerShell potrebbe vivere in un mondo orientato agli oggetti. Fortunatamente, il team di Windows PowerShell si è accorto che spesso si ha a che fare con dati esterni in stringhe formattate, quindi ha aggiunto il comando Select-String. Grazie al comando Select-String e a una certa familiarità con le espressioni regolari, è possibile utilizzare Windows PowerShell per scrivere comandi di una riga che analizzeranno anche le stringhe più complicate.

Don Jones è coautore di Windows PowerShell: TFM e autore di decine di altri libri di informatica. È possibile contattarlo dal suo blog: www.concentratedtech.com.