Adam the Automator

Uno dei primi comandi Linux che molti amministratori di sistema imparano è grep. Questo venerabile strumento è stato in giro per decenni ed è fondamentale per qualsiasi amministratore. Il nucleo di Grep è semplicemente la capacità di cercare un testo semplice per un modello RegEx. Grep può cercare file in una data directory o input in streaming per ottenere corrispondenze. Sapevate che PowerShell ha Grep? Beh…quasi.

PowerShell, essendo un linguaggio, è più di un semplice binario a scopo singolo. Pertanto, quali abilità incorporate esistono per cercare del testo semplice usando schemi RegEx, proprio come fa grep? In questo articolo esploreremo la miriade di modi per cercare del testo nei file usando PowerShell.

Esplorando il Select-String Cmdlet

Select-String (il nostro PowerShell grep) lavora su linee di testo e per default cerca la prima corrispondenza in ogni linea e poi visualizza il nome del file, il numero di riga e il testo all’interno della linea corrispondente. Inoltre, Select-String può lavorare con diverse codifiche di file, come il testo Unicode, utilizzando il byte-order-mark (BOM) per determinare il formato di codifica. Se la BOM manca, Select-String assumerà che si tratti di un file UTF8.

Parametri di Select-String

  • AllMatches – Normalmente, Select-String cercherà solo la prima corrispondenza in ogni riga, usando questo parametro il cmdlet cercherà più di una corrispondenza. Un singolo oggetto MatchInfo sarà ancora emesso per ogni riga, ma conterrà tutte le corrispondenze trovate.
  • CaseSensitive – Le corrispondenze non sono case-sensitive per impostazione predefinita, questo forza il cmdlet a cercare le corrispondenze che corrispondono esattamente al modello di input.
  • Context – Un parametro molto utile in quanto, è possibile definire il numero di righe prima e dopo la corrispondenza che verrà visualizzata. Aggiungendo questo parametro si modifica l’oggetto emesso MatchInfo per includere una nuova proprietà Context che contiene le righe specificate.

Si tenga presente che se si convoglia l’output di Select-String in un’altra chiamata Select-String, il contesto non sarà disponibile poiché si sta cercando solo sulla singola proprietà risultante MatchInfoline.

  • Culture – Usato con il parametro SimpleMatch, questo specifica una cultura da abbinare al modello specificato. Questo include opzioni come en-USes, o fr-FR come esempi. Alcune altre opzioni utili sono le opzioni Ordinal e InvariantOrdinal è per i confronti binari non linguistici e Invariant è per i confronti indipendenti dalla cultura.

Questo parametro è stato introdotto in PowerShell 7 e non è disponibile nelle versioni precedenti. Tieni anche presente che questo userà la cultura corrente del sistema, per impostazione predefinita, che può essere trovata usando Get-Culture.

  • Encoding – Specifica la codifica del file di destinazione da cercare, che di default è utf8NoBOM.
    • ascii: Utilizza la codifica per il set di caratteri ASCII (7-bit).
    • bigendianunicode: Codifica in formato UTF-16 utilizzando l’ordine di byte big-endian.
    • oem: Utilizza la codifica predefinita per MS-DOS e programmi per console.
    • unicode: Codifica in formato UTF-16 utilizzando l’ordine byte little-endian.
    • utf7: Codifica in formato UTF-7.
    • utf8: Codifica in formato UTF-8.
    • utf8BOM: Codifica in formato UTF-8 con Byte Order Mark (BOM)
    • utf8NoBOM: Codifica in formato UTF-8 senza Byte Order Mark (BOM)
    • utf32: Codifica in formato UTF-32.

    A partire da PowerShell Core 6.2, il parametro Encoding accetta anche ID numerici di pagine di codice registrate come 1251 o nomi di stringhe come windows-1251.

A partire da PowerShell Core 6.2, il parametro Encoding accetta anche ID numerici di pagine di codice registrate come 1251 o nomi di stringhe come windows-1251.

  • Exclude – Lavorando con il parametro Path, escludere elementi specifici utilizzando un pattern, come *.txt.
  • Include – Proprio come il parametro ExcludeInclude includerà solo gli elementi specificati utilizzando uno schema, come *.log.
  • List – Restituisce solo la prima istanza di testo corrispondente da ogni file di input. Questo è inteso come un modo veloce ed efficiente per recuperare un elenco di file che hanno contenuti corrispondenti.
  • LiteralPath – Questo dice a Select-String di usare i valori come input, invece di interpretare valori come * come un carattere jolly. Se il percorso include caratteri di escape, racchiudili in virgolette singole per non fare alcuna interpretazione.
  • NoEmphasis – Invece di evidenziare la stringa a cui corrisponde il pattern, disabilita l’evidenziazione delle corrispondenze. Per impostazione predefinita, l’evidenziazione usa colori negativi basati sui colori del testo di sfondo.
  • NotMatch – Cerca il testo che non corrisponde allo schema specificato.
  • Path – Specifica il percorso dei file da cercare. I caratteri jolly sono permessi, ma non è possibile specificare solo una directory. L’impostazione predefinita è la directory locale.
  • Pattern – Il modello per cercare il contenuto o i file di input basato su RegEx.
  • SimpleMatch – Usa una semplice corrispondenza invece delle espressioni regolari. Poiché RegEx non viene utilizzata, l’oggetto MatchInfo restituito non ha alcun valore nella proprietà Matches.
  • Raw – Visualizza le stringhe corrispondenti, senza un oggetto MatchInfo. Questo è il comportamento più simile a grep e non la natura più orientata agli oggetti di PowerShell.
  • Quiet – Restituisce solo un $true o $false se il modello viene trovato.

Utilizzare PowerShell Grep err… Select-String

Ovviamente sapere come funzionano i parametri e le opzioni di una cmdlet non è proprio la stessa cosa che usarla in un ambiente di produzione. Immergiamoci negli esempi e vediamo come possiamo sfruttare Select-String per facilitare la ricerca delle corrispondenze di testo.

Ci sono tre modi in cui possiamo usare Select-String per trovare le corrispondenze.

  • Inseriamo il testo quotato nel Select-String cmdlet, cioè facciamo lo streaming del testo.
  • Utilizzando il testo memorizzato in una variabile, passare la variabile al parametro InputObject.
  • Utilizzare il parametro Path per specificare i file in cui cercare il testo.

I file che stiamo usando per testare questo sono contenuti generati casualmente, ma dello stesso tipo che si trova spesso nei sistemi di produzione.

Semplice corrispondenza nei file

Partendo da un esempio molto semplice, cerchiamo Joe in una manciata di file CSV.

Select-String -Path "Users\*.csv" -Pattern "Joe"
Dimostrando un semplice pattern match Select-String.
Dimostrando una semplice corrispondenza di pattern Select-String.

Come potete vedere, questo è abbastanza semplice, vediamo come Joe è evidenziato sulla linea con il resto dei dati. Ma quali dati vengono effettivamente restituiti qui? Diamo un’occhiata a tutte le proprietà di una corrispondenza restituita.

Select-String -Path "Users\*.csv" -Pattern "Joe" | Select-Object * -First 1
Mostra le proprietà restituite da una corrispondenza Select-String.
Mostra le proprietà restituite da una corrispondenza Select-String.

Abbiamo un paio di proprietà che sono utili. In particolare il linepathpattern, e matches. La maggior parte di ciò che vogliamo sapere è nella proprietà matches.

Select-String -Path "Users\*.csv" -Pattern "Joe" | Select-Object -ExpandProperty Matches -First 1
Enumerazione della proprietà Matches e dati disponibili.
Enumerazione della proprietà Matches e dati disponibili.

Qui potete vedere come anche se abbiamo usato una semplice espressione, questa è ancora un’espressione RegEx e i successivi dettagli disponibili.

E se cercassimo diversi valori usando modelli separati da virgole? Questo è utile in quanto definisce effettivamente tre diversi pattern e non un valore RegEx complesso.

Select-String -Path "Users\*.csv" -Pattern "Joe","Marti","Jerry"
Risultano più corrispondenze da una ricerca Select-String.
Ritorno di corrispondenze multiple da una ricerca Select-String.

Si può vedere come questo sia il caso, se selezioniamo solo il filenamepattern, e line dalla nostra ricerca.

Select-String -Path "Users\*.csv" -Pattern "Joe","Marti","Jerry" | Select-Object FileName, Pattern, Line
Filtrare i risultati da una corrispondenza multipla Select-String.

Corrispondenza RegEx più complessa

Ora che abbiamo dimostrato alcuni dei metodi di corrispondenza più semplici, che ne dite di utilizzare RegEx per cercare effettivamente modelli più utili? I tre esempi qui sono alla ricerca di indirizzi e-mail, indirizzi IP e numeri di previdenza sociale (SSN). I modelli usati qui non sono l’unico modo per costruire una ricerca RegEx, e ci possono essere modi più semplici. PowerShell Grep (Select-String) è un cmdlet piuttosto avanzato.

Guardiamo se le email sono contenute nei nostri file. Utilizzando una corrispondenza RegEx un po’ complessa, come mostrato di seguito, dimostreremo di trovare queste corrispondenze.

Select-String -Path "Users\*.csv" -Pattern '\\b+\.{2,4}\b' | Select-Object -First 10
Dimostrazione dell'utilizzo di RegEx per la corrispondenza dei dati.
Dimostrando l’uso di RegEx per abbinare i dati.

Ovviamente, potrebbe essere più preoccupante se ci fossero SSN inclusi in un file. Una partita molto semplice per questo sarebbe la seguente.

Select-String -Path "Users\*.csv" -Pattern '\d\d\d-\d\d-\d\d\d\d' | Select-Object -First 10
Dimostrando una semplice ricerca SSN RegEx.
Dimostrando una semplice ricerca SSN RegEx.

Finalmente, cosa succede se vogliamo cercare alcuni indirizzi IP nel nostro file? Usando un’altra espressione RegEx per cercare quel modello, si fa un lavoro veloce.

Select-String -Path "Users\*.csv" -Pattern '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' | Select-Object -First 10
Dimostrando una semplice ricerca RegEx degli indirizzi IP.
Dimostrando una semplice ricerca RegEx dell’indirizzo IP.

Un avvertimento su questa RegEx. Tecnicamente, questo corrisponderà a valori fino a 999.999.999.999 che è un IP non valido. Potete costruire espressioni RegEx più accurate che diventeranno più lunghe, ma è un compromesso a seconda di ciò che state cercando di fare.

Cercare con il contesto

Il contesto è molto utile nella risoluzione dei problemi, aiuta a spiegare cosa sta succedendo prima e dopo un evento. Per esempio, cerchiamo in un log di Apache e troviamo questo suspendedpage.cgi testo.

Select-String -Path "Web\*.txt" -Pattern "suspendedpage.cgi" -Context 1 | Select-Object -First 1
Ricerca di una riga in un log di Apache.
Ricerca di una linea in un log Apache.

Il > semplice indica la linea corrispondente, e c’è una linea prima della corrispondenza e dopo la corrispondenza. In questo esempio, questo potrebbe dirci che il bot di Google stava cercando robots.txt e purtroppo ha ricevuto invece un risultato suspendedpage.cgi. Poi, è andato a provare la homepage e forse ha ottenuto lo stesso errore.

Cosa contiene esattamente la proprietà context emessa dall’oggetto MatchInfo? Se ci espandiamo su quella proprietà, potete vedere che c’è PreContent e PostContent. Questo significa che potete manipolare questo più avanti, se necessario.

Select-String -Path "Web\*.txt" -Pattern "suspendedpage.cgi" -Context 1 | Select-Object -ExpandProperty Context -First 1 | Format-List
Dimostrando la proprietà Context.
Dimostrando la proprietà Context.

Altri esempi di ricerca attraverso i file di log sono in articoli come Making Sense of the Microsoft DNS Debug Log che dimostra l’utilizzo di Select-String per guardare attraverso un log di debug DNS. Il PowerShell grep è forte in quel post.

Conclusione

Grep è uno strumento incredibilmente utile nel mondo Linux, e Select-String offre molte delle stesse funzionalità nel mondo PowerShell. Aggiungere la natura orientata agli oggetti di PowerShell serve solo a migliorare l’utilità e l’utilità che la cmdlet offre.

Per molti amministratori di sistema, essere in grado di cercare in modo rapido ed efficiente i file di log su vari tipi, insieme alla comprensione del contesto, è una capacità incredibilmente importante e necessaria. PowerShell Select-String rende questo facile da fare e risparmia innumerevoli ore di risoluzione dei problemi!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *