¿Qué diablos está pasando con este filtro AD en PowerShell?

9

Me hace poco escribí esta respuesta y topé con algo interesante.

get-aduser -filter {-not (description -eq "auto")} | measure-object

y

get-aduser -filter {description -ne "auto"} | measure-object

devuelve dos cosas muy diferentes cuando se ejecuta contra los mismos datos, con el primer comando devolviendo el valor esperado. A primera vista, parece que los usuarios con un valor nulo en el campo de descripción no se devuelven como coincidencias en el segundo comando, aunque NULL claramente no es igual a "auto".

Un par de personas en el chat han mirado esto y verificado que no estoy loco. ¿Que está pasando aqui?

MDMarra
fuente
1
Es interesante que lo canalice a través de Where-object y aplique el filtro que no funciona arriba. get-aduser -filter * -Descripción de propiedades | ? {$ _. descripción -ne "Auto"} | medida
Mike
@ Mike Sí, este parece ser el comportamiento del -neoperador de comparación dentro del -Filterbloque solamente. Específicamente, cuando el valor de entrada de la comparación es $null.
jscott
1
Me gusta y no me gusta parece funcionar de manera similar. {description-notlike "something"} no funciona, pero {-not (description -like "something")} sí. También el que funciona toma mucho más tiempo para evaluar. Al igual que el roto no está evaluando todos los objetos que debería.
Mike
@ Mike Eso es correcto. De hecho, me topé con esto usando -notlikeoriginalmente, pero cambié -nedespués de darme cuenta de que no estaba obteniendo lo que quería. TBH, olvidé que incluso lo había intentado hasta que lo mencionaste, pero también puedo reproducirlo.
MDMarra
2
Solo un pensamiento, pero tal vez la cláusula -eq/ PoSH -neintenta comportarse como un SQL =/ <>? En SQL, foo = NULLy foo <> NULLsiempre devolverá falso, porque NULL es 'incomparable': solo funcionarán los operadores especiales foo IS NULLy foo IS NOT NULL. El comportamiento debe ser similar en PoSH, donde su -not (foo -eq "bar")filtro devolvería todo lo que (foo -eq "bar")devolvió $false, lo foo -eq $nullque haría. En cambio, ¿qué tal if (!foo -or foo -ne "bar")(SQL equivalente foo IS NULL OR foo <> 'bar')?
jimbobmcgee

Respuestas:

4

La diferencia clave entre los dos es que el primer comando no implica una comparación directa de valores para obtener todos los resultados, y el segundo comando sí. El primer comando incluye resultados NULL y el segundo no (como MDMarra ya descubrió). Ambos comandos comienzan con este cmdlet:

get-aduser

Cuando revise lo siguiente, recuerde que los resultados de este cmdlet incluyen a todos los usuarios de AD, independientemente de cualquier otra cosa en el -filterparámetro posterior.

Ahora analicemos las dos partes que son diferentes. El primero:

{-not (description -eq "auto")}

...medio

  1. "averiguar dónde el atributo de descripción es igual a la cadena de texto" auto ". Para que esta comparación funcione, es necesario que exista una cadena en el campo de descripción para que el -eqoperador pueda compararla con" auto ". Los valores NULL se eliminan de esto comparación ya que no puede comparar un valor NULL con un valor de cadena.
  2. independientemente de la -eqEl parámetro de filtro me da TODO lo que NO es el resultado de (description -eq "auto"), que incluirá NULL, porque el cmdlet original get-aduser, incluye a todos los usuarios de AD. No tenía que comparar nada con el -notoperador con nada más . Simplemente te dio todo además de cuáles fueron los resultados del (description -eq "auto")filtro.

En su ejemplo, suponga que tiene 1 usuario de AD que tiene una descripción igual a "auto", unos pocos cientos con algo diferente a "auto" y unos pocos cientos con descripciones NULL. Recorriendo la lógica del comando hará:

  1. Déme todos los usuarios de AD (get-aduser) donde la descripción sea igual a "auto" - resulta en 1 usuario
  2. Dame todos los usuarios de AD que NO son lo que me acabas de dar: el resultado son los pocos cientos con algo más Y los pocos cientos que tienen NULL.

Como no tenía que comparar nada con el -notoperador, el resultado incluyó a los usuarios de descripción NULL que se capturaron en el get-adusercmdlet original .

El segundo comando:

{description -ne "auto"}

...medio

  1. "averiguar dónde el atributo de descripción no es igual a la cadena exacta" auto ". Nuevamente, para que esta comparación funcione, es necesario que exista una cadena en el campo de descripción para que el -neoperador pueda compararla con" auto ". Valores NULL se eliminan de esta comparación ya que no puede comparar un valor NULL con un valor de cadena.

En su ejemplo nuevamente, suponga que tiene 1 usuario de AD que tiene una descripción igual a "auto", unos pocos cientos con algo diferente a "auto" y unos pocos cientos con descripciones NULL. Recorriendo la lógica del comando hará:

  1. Déme todos los usuarios de AD donde la descripción no sea igual a "auto": los cientos de usuarios tienen algo diferente a "auto" en su descripción. No atrae a los usuarios con descripciones NULL porque no puede comparar un NULL con una cadena de texto.

De cualquier manera, la diferencia entre los dos comandos es definitivamente no intuitiva.

Usando este comando, deberías poder atrapar los NULL con un "-y" allí también así:

{description -ne "auto" -and description -ne $NULL}

No estoy 100% en la sintaxis ya que no puedo probarlo en este momento, y probablemente también haya una mejor manera de hacerlo. Cuando todo está descompuesto, es bastante anti-climático y me costó mucho explicarlo, pero me he encontrado con cosas raras como esta antes de usar los diversos operadores y muchas pruebas y errores, ya que nunca puedo recordar todas las advertencias. que van junto con el uso de cada uno.

Referencia: http://technet.microsoft.com/en-us/library/hh847732.aspx :

Operadores de comparación

Utilice operadores de comparación (-eq, -ne, -gt, -lt, -le, -ge) para comparar valores y condiciones de prueba. Por ejemplo, puede comparar dos valores de cadena para determinar si son iguales.

Los operadores de comparación incluyen los operadores de coincidencia (-match, -notmatch), que encuentran patrones utilizando expresiones regulares; el operador de reemplazo (-replace), que usa expresiones regulares para cambiar los valores de entrada; operadores similares (-like, -notlike), que encuentran patrones usando caracteres comodín (*); y los operadores de contención (en, -notin, -contains, -notcontains), que determinan si un valor de prueba aparece en un conjunto de referencia.

También incluyen los operadores bit a bit (-bAND, -bOR, -bXOR, -bNOT) para manipular los patrones de bits en valores.

Para obtener más información, consulte about_Comparison_Operators

Operadores logicos

Utilice operadores lógicos (-and, -or, -xor, -not,!) Para conectar declaraciones condicionales en un solo condicional complejo . Por ejemplo, puede usar un operador lógico y para crear un filtro de objeto con dos condiciones diferentes.

Para obtener más información, consulte about_Logical_Operators.

agosto
fuente
Una buena descripción general, pero ¿por qué se excluyen los valores nulos de los operadores -ne y-notlike? Ese es el verdadero rascador de cabeza. Me pregunto si es por diseño y tiene alguna explicación esotérica de especificaciones .net o si es un error o un comportamiento inesperado.
MDMarra
Espera, solo lee más de cerca. Parece que solo comparan cadenas y los atributos nulos son realmente nulos y no una cadena vacía. Interesante si no es intuitivo.
MDMarra
0

Agregando a esta vieja pregunta como surge cuando busca:

El uso de -Filter con coincidencia negativa, como -ne o -notlike, excluye los resultados con valores nulos vacíos. Para que se incluyan, también debe hacer coincidir explícitamente el uso de -notlike '*' como -eq '' y -eq $ NULL no son filtros válidos. Tenga en cuenta que esta es una peculiaridad con -Filter, utilizando un -LdapFilter directo que hace coincidir los valores vacíos negativos.

Aquí hay un ejemplo de filtro y LdapFilter de coincidencia múltiple con negativo:

Get-ADUser -Filter { mail -like '*example*' -and (description -ne 'example' -or description -notlike '*') }

Get-ADUser -LdapFilter '(&(mail=*example*)(!description=example))'
WhoIsRich
fuente