Skip to the main content.

ScriptRunner Blog

Effizientes Arbeiten mit der PowerShell-Pipeline: Hier kommt dein Leitfaden

Inhaltsverzeichnis

 

 

Post Featured Image

Wie sicher bist du im Umgang mit der Pipeline? Wir starten eine neue, kleine Reihe – los geht es mit dem Thema PowerShell Pipeline Grundlagen. So erleichterst du dir als Administrator den Alltag.

 

Einleitung – keine Scheu vor der Pipeline!

Für zahlreiche Administratoren erscheint die Pipeline-Funktionalität in PowerShell als ein kaum zu entschlüsselndes Mysterium, das sie trotz seines enormen Potenzials oft umgehen. Auch, wenn zumindest die Grundlagen bekannt sind, ziehen es viele vor, sie nicht eigenständig zu nutzen und verlassen sich stattdessen hauptsächlich auf kopierten Code. Tatsächlich ist die Anwendung in der Praxis weniger komplex, als mancher annimmt, und wird nach einer kurzen Einarbeitungszeit fast intuitiv. 

Das Pipelining ermöglicht eine nahtlose Verkettung mehrere Cmdlets, wodurch auch komplexe Aufgaben vereinfacht dargestellt werden können. Dieser Artikel beantwortet folgende Fragen:

  • Was sind die Grundlagen und die grundlegende Funktionsweise der Pipeline?
  • Wie kannst du Daten und Objekte mithilfe der Pipeline individuell filtern und sortieren?
  • Wie findest du heraus, welche Cmdlets man mit der Pipeline kombinieren kann?
  • Wie machst du deine eigenen Funktionen Pipeline-ready?

 

Grundlagen der PowerShell-Pipeline

Die Pipeline ermöglicht es zwei oder mehrere Cmdlets zu verketten. Die Ergebnisse eines Befehls werden an den nächsten Befehl weitergegeben. Als Verknüpfung der Befehle wird der senkrechte Strich (" | ") verwendet. Manch einer kennt dieses Vorgehen auch von der Linux-Bash. Die PowerShell hebt sich dabei insofern von der Bash-Pipe ab, als dass in der PowerShell komplette Objekte übergeben werden können statt reiner "dummer" Text.

Stell dir die PowerShell-Pipeline wie ein Fließband in einer Fabrik vor. Jedes Cmdlet ist wie eine Station auf diesem Fließband. Du setzt ein Produkt (z.B. ein Datenobjekt) am Anfang des Fließbands ab und es bewegt sich von Station zu Station. An jeder Station (Cmdlet) wird eine spezielle Handlung oder Bearbeitung an diesem Produkt vorgenommen, bevor es zur nächsten weitergeleitet wird. Wenn es das Ende des Fließbands erreicht, hast du ein fertiges Produkt, das alle erforderlichen Bearbeitungsschritte durchlaufen hat. Genau wie in einer Fabrik kannst du je nach Bedarf beliebig viele Stationen (Cmdlets) in der gewünschten Reihenfolge hinzufügen, um das perfekte Ergebnis zu erhalten.

01_cmdlets-and-PowerShell-pipeline

Das folgende Code-Beispiel illustriert die Anwendung der PowerShell-Pipeline:


Get-Service -Name 'wuauserv' | Stop-Service

Zunächst wird ein Service-Objekt mit dem Namen "wuauserv" abgefragt. Das Ergebnis dieser Abfrage (= das Service-Objekt) wird nun mittels Pipeline an das nächste Cmdlet weitergereicht. Stop-Service bewirkt nun ein Stoppen sämtlicher Service-Objekte, über die Pipe weitergereicht wurden (in diesem Fall das "wuauserv"-Service-Objekt).

Deutlich spannender ist die Verknüpfung mehrerer Cmdlets. So könnte man über einen Filter zunächst gezielt nach bestimmten Services suchen und diese anschließend beenden. Angenommen es sollen sämtliche Services einer bestimmten Anwendung (in diesem Fall "Xbox") beendet werden, so könnte man folgende Verkettung benutzen:


Get-Service | Where-Object Displayname -like "*xbox*" | Stop-Service

 

Wichtige Pipeline Cmdlets

Wie schon im letzten Code-Beispiel gezeigt, ist es möglich die Pipeline für das Filtern, Sortieren und Weiterleiten von Daten einzusetzen. Die wichtigsten Cmdlets hierfür sind: 

  • Where-Object
  • Sort-Object
  • Select-Object
  • Group-Object
  • Tee-Object
  • Foreach-Object

 

Filtern mit Where-Object

Das Cmdlet Where-Object ist wie ein Sieb, das nur die gewünschten Objekte durchlässt. Möchtest du beispielsweise alle Dienste auf deinem System auflisten, aber nur diejenigen sehen, die momentan gestartet sind, so kannst du folgenden Code verwenden:


Get-Service | Where-Object { $_.Status -eq 'Running' }

Natürlich können mittels Where-Object auch komplexere Abfragen durchgeführt werden, wie in diesem Beispiel:


Get-ChildItem -Path 'C:\Logs' -File | Where-Object { $_.Extension -eq '.log' -and $_.Length -gt 1GB }

In diesem Fall werden alle Dateien im Ordner "C:\Logs" ausgegeben welche beide der folgenden Bedingungen erfüllen:

  • .log als Datei-Endung und
  • Dateigröße über 1GB

 

Sortieren mit Sort-Object

Das Cmdlet Sort-Object sorgt für eine entsprechende Sortierung der Daten. So kann man die Ausgabe eines Objekts anhand eines ausgewählten Attributs sortieren - folgendem Beispiel filtern wir sämtliche Services anhand des jeweiligen Status und sortieren anschließend anhand des Prozessnamens. Mit den Parametern -Ascending (aufsteigend) und -Descending (absteigend) lässt sich dabei die Reihenfolge festlegen:


Get-Service | Where-Object { $_.Status -eq 'Running' } | Sort-Object Name -Ascending
Get-Service | Where-Object { $_.Status -eq 'Running' } | Sort-Object Name -Descending

 

Auswählen mit Select-Object

Das Cmdlet Select-Object ist ein nützliches Werkzeug, wenn man spezifische Eigenschaften aus den Objekten, die durch die Pipeline fließen, extrahieren möchte. Es ist besonders hilfreich, wenn man nur bestimmte Daten anzeigen oder weiterverarbeiten möchte. Hier ist ein einfacher Gebrauch von Select-Object, um nur die Namen und Status der auf einem System laufenden Dienste zu erhalten:



Get-Service | Select-Object Name, Status 

 

Gruppieren mit Group-Object

Das Cmdlet Group-Object erlaubt es, Objekte nach einer oder mehreren Eigenschaften zu gruppieren. Dies ist besonders nützlich, wenn man eine große Menge an Daten hat und diese in logische Gruppen unterteilen möchte. Hier ein Beispiel, wo Group-Object verwendet wird, um Dienste nach ihrem Status zu gruppieren:


# Befehl:
Get-Service | Group-Object -Property Status

# Ausgabe:

02_get-service group-object -property status-1

In diesem Code-Block werden die Dienste nach ihrem Status gruppiert, und man erhält eine Ausgabe, die zeigt, wie viele Dienste in jedem Status (Laufend, Gestoppt, etc.) vorhanden sind.

 

Weiterleiten mit Tee-Object

Das Cmdlet Tee-Object ist nützlich, wenn man die Pipeline-Daten sowohl auf dem Bildschirm anzeigen als auch in eine Datei schreiben möchte. Es leitet die Daten an zwei Orte weiter – daher der Name "Tee" (wie eine T-Abzweigung). Hier ist ein Beispiel:


Get-Process | Tee-Object -FilePath "C:\temp\processlist.txt"

In dem oben genannten Code-Block werden die Prozessinformationen sowohl auf dem Bildschirm angezeigt als auch in die angegebene Datei geschrieben.

 

Iterieren mit Foreach-Object

Das Cmdlet Foreach-Object ermöglicht es, eine Aktion oder eine Gruppe von Aktionen für jedes Objekt in der Pipeline durchzuführen. Dies ist besonders nützlich, wenn man eine spezifische Aufgabe für jedes Objekt in einer Liste ausführen möchte. Hier ist ein Beispiel:


Get-Service | Foreach-Object { if ($_.Status -eq 'Running') { Write-Output "$($_.Name) is running and its start type is $($_.StartType)" } }

In diesem Beispiel wird Foreach-Object verwendet, um durch alle Dienste zu iterieren. Wenn der Status eines Dienstes "Running" ist, wird eine Ausgabe erzeugt, die den Namen des Dienstes und seine Startart angibt.

 

Welche Cmdlets lassen sich verketten?

Nachdem du nun weißt, wie sich Cmdlets verketten lassen, fragst du dich sicherlich wie du herausfinden kannst, welche Cmdlets überhaupt miteinander "kompatibel" sind. 

Prinzipiell können Cmdlets verkettet werden, wenn das Ausgabeobjekt des ersten Cmdlets von dem zweiten Cmdlet als Eingabeobjekt akzeptiert wird. Dies geschieht entweder ByValue oder ByPropertyName

 

Verkettung ByValue

Cmdlets nehmen direkt den Wert des Ausgabeobjekts (OutputObject) des vorherigen Cmdlets als InputObject an, wie in folgendem Beispiel dargestellt:


Get-Service wuauserv | Stop-Service

Um den Typ des OutputObject eines Cmdlets zu ermitteln, kann man wie folgt vorgehen:

03_OutputType-1

Durch die Ausgabe erfahren wir, dass Get-Service den Objekttyp System.ServiceProcess.ServiceController zurückgibt. Es repräsentiert einen Controller, über welchen der dahinterliegende Service angesprochen und gesteuert werden kann.

Um zu prüfen, welche Objekt-Typen von Stop-Service erwartet werden, können wir wie folgt vorgehen:


# Befehl:
Get-Help Stop-Service -Parameter
InputObject

# Ausgabe:

04_stop-service-1

Der Parameter -InputObject für das Cmdlet Stop-Service erwartet einen Eingabewert des Typs System.ServiceProcess.ServiceController[]. Das bedeutet, dass Stop-Service eine Sammlung (ein Array) von ServiceController-Objekten akzeptiert. Wichtig ist hier der Teil "Accept pipeline input? true (ByValue)". Das bedeutet, dass Stop-Service diesen Input direkt aus der Pipeline akzeptiert, wenn er dem erwarteten Typ (Service) entspricht. 

Somit wissen wir, dass wir beide Cmdlets verketten können und Stop-Service die ServiceController-Objekte unterstützt (ByValue).

 

Verkettung ByPropertyName

Die Pipeline-Übergabe "ByPropertyName" ist eine andere Art der Verkettung. Hierbei wird der Input für ein Cmdlet nicht auf Basis des Typs des übergebenen Objekts, sondern auf Basis des Namens einer Eigenschaft oder eines Parameters des Objekts bestimmt.

Ein einfaches Beispiel dazu:

 
'wuauserv'| Stop-Service

In diesem Beispiel wird der Name des Dienstes vom Cmdlet Get-Service an Stop-Service übertragen. Das Cmdlet Stop-Service benötigt normalerweise den Dienstnamen als Eingabe, um einen Dienst zu stoppen.

Um herauszufinden, ob ein Cmdlet die Eingabe "ByPropertyName" akzeptiert, können wir den folgenden Befehl verwenden:


# Befehl:
Get-Help Stop-Service -Parameter Name

# Ausgabe:

05_ByPropertyName-1

Hier sehen wir, dass der Parameter -Name für das Cmdlet Stop-Service eine Eingabe des Typs String[] erwartet, und dass er die Eingabe aus der Pipeline aufgrund des Namens der Eigenschaft akzeptiert (siehe "Accept pipeline input? true (ByPropertyName)").

Das bedeutet, wenn das aus der Pipeline übergebene Objekt eine Eigenschaft namens "Name" hat (was bei Get-Service der Fall ist), dann kann dieses Cmdlet den Wert dieser Eigenschaft nutzen.

In der Praxis sollten wir immer die Dokumentation überprüfen, um sicherzustellen, dass die erwarteten Eingaben und die tatsächlichen Ausgaben eines Cmdlets übereinstimmen, bevor wir sie in einer Pipeline verketteten. Es ist auch wichtig zu beachten, dass viele Cmdlets sowohl "ByValue" als auch "ByPropertyName" unterstützen können, abhängig von den bereitgestellten Daten und den erwarteten Eingaben.

Cmdlets sind oft so konzipiert, dass sie mit ähnlichen Cmdlets in ihrer "Kategorie" oder ihrem Modul kompatibel sind. Zum Beispiel können viele Active Directory-Cmdlets, die User-Objekte ausgeben, mit anderen Active Directory-Cmdlets, die User-Objekte als Eingabe verwenden, in einer Pipeline kombiniert werden.

Letztlich erfordert die effektive Nutzung der Pipeline in PowerShell auch ein gewisses Experimentieren und Erfahrung. Es kann hilfreich sein, mit verschiedenen Cmdlets zu spielen und zu sehen, wie sie in der Praxis miteinander interagieren.

 

Fazit

Die Pipeline-Funktionalität in PowerShell stellt ein mächtiges Werkzeug für Administratoren dar und bietet eine effiziente Möglichkeit, verschiedene Aufgaben zu vereinfachen und zu automatisieren. Der Schlüssel zum Verständnis und zur erfolgreichen Anwendung liegt in der konsequenten Auseinandersetzung und Praxis. Einmal gemeistert, wird die Arbeit mit der PowerShell-Pipeline nicht nur die Effizienz steigern, sondern auch die Möglichkeit eröffnen, benutzerdefinierte Lösungen und Funktionen zu schaffen, die genau auf individuelle Bedürfnisse zugeschnitten sind.

 

 

Good2know

Dein ultimatives PowerShell Cheat Sheet

Entfalte das volle Potential von PowerShell mit unserem praktischen Poster. Egal ob Anfänger oder erfahrener Profi, dieses Cheat Sheet ist darauf ausgelegt, dein Anlaufpunkt für die wichtigsten und am häufigsten verwendeten Cmdlets zu sein.

Das Poster gibt es zum Download und in Papierform.

PowerShell Poster 2023

Hier entlang zum Poster

 

 

Weiterführende Links

Zusammenhängende Posts

2 min read

VMUG Webcast: VMware Management meistern mit PowerCLI

5 min read

PowerShell mit Get-Help meistern

Über den Autor: