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”
VeroPS 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:
-ContieneEsempi:
PS C:\> “abc”, “def” -Contiene “def”
VeroPS C:\> “Windows”, “PowerShell” -Contiene “Shell”
False #Non è una corrispondenza esatta# La lista dei computer in $domainServers
# include $thisComputer?
# ————–
PS C:\> $domainServers -Contiene $thisComputer
VeroPS C:\> “abc”, “def”, “ghi” -Contiene “abc”, “def”
FalsePS 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