Operadores de comparación PowerShell -Like vs -Contains

En algún momento de tu carrera en PowerShelling necesitarás probar si «algo» se encuentra (o no) dentro de un determinado objeto. Me parece que me suelo enfrentar a esta situación cuando estoy probando si una cadena «contiene» un valor o no.

En este punto, siempre estoy confundido en cuanto a qué operador de comparación utilizar. Desde el punto de vista del lenguaje lógico siempre me parece que -contains es el camino a seguir, pero luego recuerdo que podría no ser la opción correcta.

Para zanjar este tema de una vez por todas (al menos para mí), aquí hay un resumen de cuándo usar -like y cuándo usar -contains.

Operador de comparación PowerShell -like

Así es como Microsoft TechNet describe el uso de -like:

-Like
Descripción:
Empareja utilizando el carácter comodín (*).

Ejemplo:
PS C:\> «Windows PowerShell» -like «*shell»
Verdadero

PS C:\> «Windows PowerShell», «Server» -como «*shell»
Windows PowerShell

Aquí está mi versión:

-like se utiliza para comparar o encontrar si una cadena existe dentro de otra cadena. -like permite utilizar el carácter comodín (*) para poder buscar en cualquier parte de la cadena.

Así que volviendo a mi requisito inicial de determinar si una cadena contiene un valor concreto o no, utilizaríamos el operador -like. Veamos algunos ejemplos a continuación:

$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

En el ejemplo 1, el resultado es falso porque no hay comodines, por lo que se está comprobando si la cadena coincide exactamente.

$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

En el ejemplo 2 hemos añadido el comodín (*) al final del término de búsqueda. Esto significa esencialmente comprobar si xyz existe al principio de la cadena y luego ignorar el resto. En este caso no existe, por lo tanto el resultado es 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

En el ejemplo 3 estamos haciendo lo mismo que en el ejemplo 2 pero buscando abc* y por lo tanto devuelve true porque abc se encuentra al principio de la cadena. El resto se ignora debido al comodín.

$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

El ejemplo 4 es esencialmente inverso al ejemplo 3. Estamos buscando xyz al final de la cadena y no nos importa nada de lo que hay delante (de ahí el comodín en la parte delantera del término de búsqueda).

$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

El ejemplo 5 muestra la búsqueda de algo en medio de la cadena utilizando comodines a ambos lados del término de búsqueda.

Operador de comparación PowerShell -contains

Así es como Microsoft TechNet describe el uso de -contains:

Descripción:
Operador de contención. Indica si una colección de valores de referencia incluye un único valor de prueba. Siempre devuelve un valor booleano. Devuelve TRUE sólo cuando el valor de prueba coincide exactamente con al menos uno de los valores de referencia.

Cuando el valor de prueba es una colección, el operador Contiene utiliza la igualdad de referencias. Devuelve TRUE sólo cuando uno de los valores de referencia es la misma instancia del objeto valor de prueba.

Sintaxis:
-Contiene

Ejemplos:
PS C:> «abc», «def» -Contiene «def»
Verdadero

PS C:> «Windows», «PowerShell» -Contains «Shell»
False #No es una coincidencia exacta

# ¿La lista de ordenadores en $domainServers
# incluye $thisComputer?
# ————–
PS C:\> $domainServers -Contains $thisComputer
True

PS C:\> «abc», «def», «ghi» -Contains «abc», «def»
False

PS C:\> $a = «abc», «def»
PS C:\> «abc», «def», «ghi» -Contiene $a
False
PS C:> $a, «ghi» -Contiene $a
Verdadero

Aquí está mi versión….

El operador de comparación -contains se utiliza para determinar si una colección de objetos (por ejemplo, un array) contiene un objeto concreto o no. La evaluación se realiza contra todo el objeto y no contra una sola propiedad del mismo. En otras palabras, se tienen en cuenta todas las propiedades del objeto.

Esto puede ser un poco confuso, pero viendo algunos ejemplos se pueden aclarar las cosas un poco:

$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

El primer ejemplo es uno fácil, un array con cada objeto siendo una cadena y por lo tanto hace la comparación realmente fácil. El ejemplo anterior busca el objeto del array (elemento del array) de xyz. Como hay un elemento del array que coincide con xyz devolverá true.

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

Ahora esperarías que el ejemplo anterior devolviera true, porque todos los sistemas Windows tienen un servicio W32Time, pero no es así… ¿por qué? Pues porque estamos intentando buscar un objeto basándonos en una única propiedad, name. Sin embargo, el operador -contains no funciona así. Compara cada una de las propiedades del objeto y si todas ellas son iguales entonces devuelve True, de lo contrario devolverá false.

En el ejemplo anterior, estamos esencialmente comparando un objeto string con un objeto System.ServiceProcess.ServiceController, lo cual no va a funcionar.

Para encontrar un servicio con la propiedad name tendríamos que hacer:

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

Aunque esto funciona, podría no ser el mejor resultado porque W32Time podría ser el valor de una propiedad dentro de otro servicio y por lo tanto podrías obtener algunos falsos positivos.

Para eliminar el riesgo de falsos positivos, yo personalmente haría algo como:

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

Enumerar todos los servicios de la colección y determinar si cada una de sus propiedades name es igual al término de búsqueda es una forma muy precisa de determinar si el servicio concreto existe o no y eliminará todos los falsos positivos. Más código, pero una mejor solución.

¿Sin búsquedas?

Como una nota lateral rápida, ¿qué pasa si quieres determinar si algo no contiene un término de búsqueda en particular?

Pues en ese caso sólo tienes que usar -NotLike o -NotContains de la misma manera y en las mismas situaciones que usarías -like y -contains.

Más información sobre los operadores de comparación

Si quieres aprender más sobre todos los operadores de comparación, entonces echa un vistazo a la página de operadores de comparación de TechNet.

Bueno, espero que esto ayude a dejar las cosas un poco más claras sobre cuándo usar -Like y cuándo usar -Contains.

Déjame saber tu opinión abajo…

Gracias
Luca

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *