Co się do cholery dzieje z tym filtrem AD w PowerShell?

9

Niedawno napisałem tę odpowiedź i natknąłem się na coś interesującego.

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

i

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

zwracają dwie bardzo różne rzeczy, gdy działają na tych samych danych, przy czym pierwsze polecenie zwraca oczekiwaną wartość. Na pierwszy rzut oka wydaje się, że użytkownicy z wartością zerową w polu opisu nie są zwracani jako dopasowania w drugim poleceniu, mimo że NULL wyraźnie nie równa się „auto”.

Kilka osób na czacie spojrzało na to i potwierdziło, że nie jestem szalony. Co tu się dzieje?

MDMarra
źródło
1
Ciekawe, że przepuszczanie go przez Where-object i zastosowanie filtra, który nie działa powyżej, działa. get-aduser -filter * -Opis właściwości | ? {$ _. opis -ne „Auto”} | miara
Mike
@Mike Tak, wydaje się, że jest to zachowanie -neoperatora porównania tylko w obrębie -Filterbloku. W szczególności, gdy wartością wejściową porównania jest $null.
jscott,
1
Wygląda na to, że lubią i nie lubią. {description -notlike „coś”} nie działa, ale {-not (opis-coś „coś”)} działa. Również ten, który działa, zajmuje znacznie więcej czasu do oceny. Jak zepsuty nie ocenia wszystkich obiektów, które powinien.
Mike
@Mike Zgadza się. Właściwie natknąłem się na to, używając -notlikeoryginalnie, ale zmieniłem na, -negdy zdałem sobie sprawę, że nie dostaję tego, czego chciałem. TBH, zapomniałem, że nawet próbowałem tego, dopóki o tym nie wspomniałeś - ale mogę to również odtworzyć.
MDMarra,
2
Tylko myśl, ale może PoSH -eq/ -neklauzula próbuje zachowywać się jak SQL =/ <>? W SQL foo = NULLi foo <> NULLzawsze zwróci false, ponieważ NULL jest „nieporównywalny” - działają tylko operatory specjalne foo IS NULLi foo IS NOT NULL. Zachowanie musi być podobne w PoSH, gdzie twój -not (foo -eq "bar")filtr zwróci wszystko, za co (foo -eq "bar")zwrócił $false, co foo -eq $nullby zrobiło . Zamiast tego, co powiesz na if (!foo -or foo -ne "bar")(odpowiednik SQL foo IS NULL OR foo <> 'bar')?
jimbobmcgee

Odpowiedzi:

4

Kluczowa różnica między nimi polega na tym, że pierwsze polecenie nie wymaga bezpośredniego porównania wartości w celu uzyskania wszystkich wyników, a drugie polecenie tak. Pierwsze polecenie zawiera wyniki NULL, a drugie nie (jak już odkryto MDMarra). Oba polecenia zaczynają się od tego polecenia cmdlet:

get-aduser

Przechodząc poniżej, pamiętaj, że wyniki tego polecenia cmdlet obejmują wszystkich użytkowników AD bez względu na wszystko inne w -filterparametrze po nim.

Teraz podzielmy dwie części, które są różne. Pierwszy:

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

...znaczy

  1. „dowiedzieć się, gdzie atrybut opisu równa się ciągowi tekstowemu„ auto ”. Aby to porównanie zadziałało, w polu opisu musi istnieć ciąg znaków, aby -eqoperator mógł porównać go z„ auto ”. Wartości NULL są z tego usuwane porównanie, ponieważ nie można porównać wartości NULL z wartością ciągu.
  2. niezależnie od -eqparametr filtru daje mi WSZYSTKO, co NIE jest wynikiem (description -eq "auto"), w tym NULL, ponieważ oryginalne polecenie cmdlet get-aduserobejmuje wszystkich użytkowników AD. Nie musiał niczego porównywać z -notoperatorem. Po prostu dał ci wszystko oprócz wyników (description -eq "auto")filtru.

W twoim przykładzie załóżmy, że masz 1 użytkownika AD, którego opis jest równy „auto”, kilkaset z czymś innym niż „auto” i kilkaset z opisami NULL. Przejście przez logikę poleceń spowoduje:

  1. Daj mi wszystkich użytkowników AD (get-aduser), których opis jest równy „auto” - skutkuje 1 użytkownikiem
  2. Daj mi wszystkich użytkowników AD, którzy NIE są tym, co mi właśnie dałeś - wynikiem jest kilkaset z czymś innym ORAZ kilkaset, które mają NULL.

Ponieważ nie trzeba było porównywać niczego z niczym innym za pomocą -notoperatora, wynik obejmował użytkowników opisu NULL, którzy zostali przechwyceni w oryginalnym poleceniu get-adusercmdlet.

Drugie polecenie:

{description -ne "auto"}

...znaczy

  1. "dowiedzieć się, gdzie atrybut opisu nie jest równy dokładnemu ciągowi" auto ". Ponownie, aby to porównanie zadziałało, w polu opisu musi istnieć ciąg, aby -neoperator mógł go porównać z" auto ". Wartości NULL są usuwane z tego porównania, ponieważ nie można porównać wartości NULL z wartością ciągu.

W twoim przykładzie ponownie załóżmy, że masz 1 użytkownika AD, którego opis jest równy „auto”, kilkaset z czymś innym niż „auto” i kilkaset z opisami NULL. Przejście przez logikę poleceń spowoduje:

  1. Daj mi wszystkich użytkowników AD, których opis nie jest równy „auto” - powoduje, że kilkuset użytkowników ma w opisie coś innego niż „auto”. Nie przyciąga użytkowników z opisami NULL, ponieważ nie może porównywać wartości NULL z ciągiem tekstowym.

Tak czy inaczej cała różnica między tymi dwoma poleceniami jest zdecydowanie nieintuicyjna.

Za pomocą tego polecenia powinieneś być w stanie złapać NULL-y z „-and” również w ten sposób:

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

Nie jestem w 100% odpowiedzialny za składnię, ponieważ nie mogę jej teraz przetestować i prawdopodobnie jest na to lepszy sposób. Kiedy wszystko jest zepsute, jest dość anty-klimatyczne i wymagało dużo pisania, aby wyjaśnić, ale natknąłem się na takie dziwne rzeczy przed użyciem różnych operatorów i wielu prób i błędów, ponieważ nigdy nie pamiętam wszystkich zastrzeżeń które pasują do każdego z nich.

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

Operatory porównania

Użyj operatorów porównania (-eq, -ne, -gt, -lt, -le, -ge) do porównania wartości i warunków testowych. Na przykład można porównać dwie wartości ciągów, aby ustalić, czy są one równe.

Operatory porównania obejmują operatory dopasowania (-match, -notmatch), które znajdują wzorce za pomocą wyrażeń regularnych; operator replace (-replace), który używa wyrażeń regularnych do zmiany wartości wejściowych; podobne operatory (-podobne, -podobne), które wyszukują wzorce za pomocą znaków wieloznacznych (*); oraz operatory przechowujące (w, -notin, -contains, -notcontains), które określają, czy wartość testowa pojawia się w zestawie referencyjnym.

Zawierają także operatory bitowe (-bAND, -bOR, -bXOR, -bNOT) do manipulowania wzorcami bitowymi w wartościach.

Aby uzyskać więcej informacji, zobacz about_Comparison_Operators

Operatory logiczne

Użyj operatorów logicznych (-and, -or, -xor, -not,!), Aby połączyć instrukcje warunkowe w jeden złożony warunek warunkowy . Na przykład można użyć operatora logicznego i operatora, aby utworzyć filtr obiektów z dwoma różnymi warunkami.

Aby uzyskać więcej informacji, zobacz about_Logical_Operators.

sierpień
źródło
Dobry przegląd na pewno, ale dlaczego wartości null są wykluczone z operatorów -ne i -niepodobnych? To prawdziwy drapak. Zastanawiam się, czy to z założenia ma jakieś ezoteryczne wyjaśnienie specyfikacji .net, czy jest to błąd lub nieoczekiwane zachowanie?
MDMarra
Poczekaj, przeczytaj uważniej. Wygląda na to, że porównują tylko ciągi, a atrybuty zerowe są w rzeczywistości zerowe, a nie puste. Ciekawe, jeśli nieintuicyjne.
MDMarra
0

Dodanie do tego starego pytania, które pojawia się podczas wyszukiwania:

Użycie -Filter z dopasowaniem ujemnym, takim jak -ne lub -niepodobne, wyklucza wyniki z pustymi wartościami null. Aby je uwzględnić, musisz również jawnie dopasować, używając -niepodstawowego „*” jako -eq ” i -eq $ NULL nie są prawidłowymi filtrami. Zauważ, że jest to dziwactwo z -Filter, przy użyciu bezpośredniego -LdapFilter DOESZCZYĆ ujemne dopasowanie pustych wartości.

Oto przykład filtru i filtru LdapFilter z dopasowaniem wielokrotnym z ujemnym:

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

Get-ADUser -LdapFilter '(&(mail=*example*)(!description=example))'
WhoIsRich
źródło