PowerShell -Like vs -Contains Comparison Operators

A un certo punto della tua carriera di PowerShelling avrai bisogno di testare se “qualcosa” si trova (o non si trova) all’interno di un certo oggetto. Trovo che di solito mi trovo di fronte a questa situazione quando devo testare se una stringa “contiene” un valore o no.

A questo punto, sono sempre confuso su quale operatore di confronto usare. Dal punto di vista del linguaggio logico ho sempre la sensazione che -contains sia la strada da seguire, ma poi mi ricordo che potrebbe non essere la scelta corretta.

Per mettere a tacere questo problema una volta per tutte (almeno per me), ecco un riassunto di quando usare -like e quando usare -contains.

Operatore di confronto PowerShell -like

Ecco come Microsoft TechNet descrive l’uso di -like:

-Like
Descrizione:
Match utilizzando il carattere jolly (*).

Esempio:
PS C:\> “Windows PowerShell” -like “*shell”
Vero

PS C:\> “Windows PowerShell”, “Server” -like “*shell”
Windows PowerShell

Ecco la mia versione:

-like è usato per confrontare o trovare se una stringa esiste all’interno di un’altra stringa. -like permette di usare il carattere jolly (*) in modo da poter cercare ovunque all’interno della stringa.

Quindi, tornando al mio requisito iniziale di determinare se una stringa contiene o meno un particolare valore, useremo l’operatore -like. Vedere alcuni esempi qui sotto:

$SearchTerm = 'xyz'$String = 'abc def ghi jkl mno pqr stu vw xyz'If ($String -like $SearchTerm) { Write-Output 'True' } Else { Write-Output 'False' }# Result = False

Nell’esempio 1, il risultato è falso perché non ci sono caratteri jolly, quindi sta controllando se la stringa corrisponde esattamente.

$SearchTerm = 'xyz*'$String = 'abc def ghi jkl mno pqr stu vw xyz'If ($String -like $SearchTerm) { Write-Output 'True' } Else { Write-Output 'False' }# Result = False

Nell’esempio 2 abbiamo aggiunto il carattere jolly (*) alla fine del termine di ricerca. Questo significa essenzialmente controllare se xyz esiste all’inizio della stringa e poi ignorare il resto. In questo caso non esiste, quindi il risultato è falso.

$SearchTerm = 'abc*'$String = 'abc def ghi jkl mno pqr stu vw xyz'If ($String -like $SearchTerm) { Write-Output 'True' } Else { Write-Output 'False' }# Result = True

Nell’esempio 3 stiamo facendo lo stesso dell’esempio 2 ma cercando abc* e quindi ritorna vero perché abc viene trovato all’inizio della stringa. Il resto viene ignorato a causa del carattere jolly.

$SearchTerm = '*xyz'$String = 'abc def ghi jkl mno pqr stu vw xyz'If ($String -like $SearchTerm) { Write-Output 'True' } Else { Write-Output 'False' }# Result = True

L’esempio 4 è essenzialmente l’inverso dell’esempio 3. Stiamo cercando xyz alla fine della stringa e non ci interessa nulla di quello che c’è davanti (da qui il carattere jolly davanti al termine di ricerca).

$SearchTerm = '*mno*'$String = 'abc def ghi jkl mno pqr stu vw xyz'If ($String -like $SearchTerm) { Write-Output 'True' } Else { Write-Output 'False' }# Result = True

L’esempio 5 mostra la ricerca di qualcosa nel mezzo della stringa usando i caratteri jolly ai lati del termine di ricerca.

Operatore di confronto PowerShell -contains

Ecco come Microsoft TechNet descrive l’uso di -contains:

Descrizione:
Operatore di contenimento. Dice se una collezione di valori di riferimento include un singolo valore di prova. Restituisce sempre un valore booleano. Restituisce TRUE solo quando il valore di prova corrisponde esattamente ad almeno uno dei valori di riferimento.

Quando il valore di prova è una collezione, l’operatore Contains usa l’uguaglianza di riferimento. Restituisce TRUE solo quando uno dei valori di riferimento è la stessa istanza dell’oggetto valore di prova.

Sintassi:
-Contiene

Esempi:
PS C:\> “abc”, “def” -Contiene “def”
Vero

PS C:\> “Windows”, “PowerShell” -Contiene “Shell”
False #Non è una corrispondenza esatta

# La lista dei computer in $domainServers
# include $thisComputer?
# ————–
PS C:\> $domainServers -Contiene $thisComputer
Vero

PS C:\> “abc”, “def”, “ghi” -Contiene “abc”, “def”
False

PS C:\> $a = “abc”, “def”
PS C:\> “abc”, “def”, “ghi” -Contiene $a
Falso
PS C:\> $a, “ghi” -Contiene $a
Vero

Ora ecco la mia versione….

L’operatore di confronto -contains è usato per determinare se una collezione di oggetti (ad esempio un array) contiene o meno un particolare oggetto. La valutazione è completata rispetto all’intero oggetto e non ad ogni singola proprietà dell’oggetto. In altre parole, vengono prese in considerazione tutte le proprietà dell’oggetto.

Questo potrebbe essere un po’ confuso, ma guardando alcuni esempi potrebbe chiarire un po’ le cose:

$SearchTerm = 'xyz'$Collection = 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vw', 'xyz'If ($Collection -contains $SearchTerm) { Write-Output 'True' } Else { Write-Output 'False' }#Result = True

Il primo esempio è facile, un array con ogni oggetto che è una stringa e quindi rende il confronto davvero facile. L’esempio sopra è la ricerca dell’oggetto array (elemento di array) di xyz. Poiché c’è un elemento dell’array che corrisponde a xyz restituirà true.

$SearchTerm = 'W32Time'$Collection = Get-ServiceIf ($Collection -contains $SearchTerm) { Write-Output 'True' } Else { Write-Output 'False' }#Result = False

Ora ci si aspetterebbe che l’esempio sopra restituisca true, perché ogni sistema Windows ha un servizio W32Time, ma non è così… perché? Beh, perché stiamo cercando di trovare un oggetto basato su una singola proprietà, name. L’operatore -contains però non funziona così. Confronta ogni singola proprietà dell’oggetto e se tutte sono uguali allora restituisce True, altrimenti restituisce false.

Nell’esempio sopra, stiamo essenzialmente confrontando un oggetto stringa con un oggetto System.ServiceProcess.ServiceController, il che non funziona.

Per trovare un servizio con la proprietà name dovremmo fare:

$SearchTerm = 'W32Time'$Collection = Get-ServiceIf ($Collection -like $SearchTerm) { Write-Output 'True' } Else { Write-Output 'False' }#Result = True

Anche se questo funziona, potrebbe non essere il miglior risultato perché W32Time potrebbe essere il valore di una proprietà in un altro servizio e quindi si potrebbero ottenere dei falsi positivi.

Per eliminare il rischio di falsi positivi, personalmente farei qualcosa come:

$SearchTerm = 'W32Time'$Collection = Get-ServiceForEach ($Service in $Collection) { If ($Service.Name -eq $SearchTerm) { Write-Output 'True' }}#Result = True

Enumerare tutti i servizi nella collezione e determinare se ciascuna delle loro name proprietà è uguale al termine di ricerca è un modo molto accurato per determinare se il particolare servizio esiste o meno ed eliminerà tutti i falsi positivi. Più codice, ma una soluzione migliore.

Non cerca?

Come nota a margine, cosa succede se si vuole determinare se qualcosa non contiene un particolare termine di ricerca?

Bene in questo caso basta usare -NotLike o -NotContains allo stesso modo e nelle stesse situazioni in cui usereste -like e -contains.

Più informazioni sugli operatori di confronto

Se volete saperne di più su tutti gli operatori di confronto, date un’occhiata alla pagina TechNet Comparison Operators.

Spero che questo aiuti a rendere le cose un po’ più chiare su quando usare -Like e quando usare -Contains.

Fatemi sapere i vostri pensieri qui sotto…

Grazie
Luca

Lascia un commento

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