21. March 2019

Where-Object

Jetzt wo wir die Arrays als Tabellen nutzen können, müssen wir auch wissen wie wir uns darin zurechtfinden.

Nehmen wir mal ein Beispiel mit mehr Einträgen:

$AllProcesses = Get-Process
$AllProcesses

Jetzt wollen wir vielleicht nur mal alle Prozesse bei denen „PowerShell“ im Namen ist… Dafür brauchen wir „Where-Object“, oder „Where“, oder „?“. Alles dasselbe, nur Aliasse:

Get-Help Where-Object

Wir nehmen nun unser Array und „pipen“ seinen Wert in den nächsten Befehl, nämlich Where-Object. Pipen geht mittels „|“:

$AllProcesses | Where-Object ProcessName

Zeigt uns alle Einträge aus dem Array $AllProcesses bei dem das Attribute ProcessName exisitiert… Ok, nicht ganz sinnig. Wir wollen alle PowerShell Prozess. Also brauchen wir Vergleichs-Operatoren. Mehr zu Vergleichs-Operatoren findest du IRGENDWANN EINMAL hier:

Vergleichs-Operatoren

$AllProcesses | Where-Object ProcessName -eq "powershell"

Aber Achtung! Das ist die Faullenzer-Variante. Korrekt wäre folgender Aufruf:

$AllProcesses | Where-Object {$_.ProcessName -eq "powershell"}

Hinter das Where-Object gehört eine geschweifte Klammer, da darin Code ausgeführt wird. Da verwirrenste am Anfang wird für die meisten das „$_.“ sein. Keine Angst, die Erklärung kommt.

Bei der Weitergabe von Objekten, weiß man prinzipiell erstmal nicht was darin vorgeht. Trotzdem muss man in der Lage sein ein jedes einzelne der Elemente in diesem Objekt adressieren und benutzen zu können. Das passiert mittels „$_“. Mit „|“ leiten wir den gesamten Satz von $AllProcesses zum nächsten Befehl. Nämlich zu „Where-Object“. Dieses Where-Object geht von oben nach unten durch und adressiert in diesem Zuge jedes dieser Elemente einmal. Praktisch $AllProcesses[0] dann $AllProcesses[1] dann $AllProcesses[2], etc. Jetzt könnte man hier mittels for (kommt später dran) selbst aktiv werden, oder man lässt das System das machen indem er jedes dieser Elemente mittels „$_“ einmal instanziiert. Je nachdem bei welchem Index er gerade ist, ist $_ entsprechend $AllProcesses[Index]. Danach ist $_ der nächste Index, usw.

Da wir und für das Attribute „ProcessName“ eines jeden Elements interessieren, fragen wir also nach

$_.ProcessName

Also das instanziierte Element bei dem entsprechenden (automatisch fortgeführten) Index und dem entsprechenden Attribut.

Um das noch weiter eingrenzen zu können, müssen wir logische Operatoren nutzen:

-AND
-OR

PowerShell ist hier etwas unschön in dem was es akzeptiert:

$AllProcesses | Where-Object {$_.ProcessName -eq "powershell" -and $_.Id -eq 6136}

Das ist z.B. ein valider Ausdruck:

  • Gib mir alle Prozesse (die vorher in die Variable gepusht wurden)
  • Leite diese weiter
  • Suche hierin nach
  • Attribut ProcessName muss „powershell“ sein
  • UND
  • Attribut Id muss 6136 sein

Ich versuche diese Filter (denn nichts anderes ist es) optisch so gut wie möglich darzustellen, indem ich pro Vergleich eine runde Klammer setze.

$AllProcesses | Where-Object {($_.ProcessName -eq "powershell") -and ($_.Id -eq 6136)}

Dasselbe würde ich dann auch für Filter machen, bei denen auch mehrere logische Operatoren vorhanden sind.

Es ist wichtig zu beachten, dass Klammern immer von Innen nach Außen priorisiert werden. Die innerste Klammer wird zuerst aufgelöst, usw.

Der Einfachhalt halber nehme ich stets das „?“ statt dem Where-Object oder dem Where:

$AllProcesses | ? {($_.ProcessName -eq "powershell") -and ($_.Id -eq 6136)}

Aber es macht keinen Unterschied.