Windows-Praxis

Workshop: In der PowerShell mit regulären Ausdrücken arbeiten

19.09.2013 von Frank-Michael Schlede und Thomas Bär
Sie werden von fast allen Programmier- und Script-Sprachen unterstützt und haben sicher schon so manchen Einsteiger zur Verzweiflung getrieben: die regulären Ausdrücke. Als Hilfsmittel für Admins sind sie indes durchaus bewährt. Wir zeigen Ihnen, wie sie unter modernen Windows-Systemen in der PowerShell eingesetzt werden können.

Nicht nur Einsteiger in Programmier- und Script-Sprachen, sondern auch viele "gestandene Administratoren" schütteln nur verzweifelt den Kopf, wenn die Rede auf die regulären Ausdrücke kommt. Zu verwirrend scheinen die Hieroglyphen, die schon altgediente Unix-Administratoren einsetzten, um ihren Anwendern zu demonstrieren, wie mächtig das berüchtigte grep-Kommando sein kann - wenn es richtig einsetzt wird. Aber nicht nur bei den Unix-/Linux-Shell-Programmen, sondern auch bei der modernen PowerShell, die fester Bestandteil aller aktuellen Windows-Client- und Server-Betriebssysteme ist, kann mit den regulären Ausdrücken effizient gearbeitet werden. Die PowerShell unterstützt dabei den gesamten Umfang der regulären Ausdrücke, der vom .NET-Framework bereitgestellt wird.

Bildergalerie:
Reguläre Ausdrücke
Grundsätzlich kein Unterschied: Diese Art von Aufruf bringt das gleiche Ergebnis, unabhängig davon ob der „-like“- oder „-match“- Operator verwendet wird. Erst der Einsatz der regulären Ausdrücke macht einen Unterschied.
Reguläre Ausdrücke
Gezieltere Ausgabe erreicht: Diese Art des Aufrufs macht es möglich, dass nur die Prozesse angezeigt werden, deren Namen mit dem Buchstaben „A“ beginnt. Der „-like“-Operator kann das nicht.
Reguläre Ausdrücke
. Vergleich auf „Wortzeichen“: Die PowerShell kann mit den Zeichenklassen arbeiten, wie sie auch vom Microsoft Framework bereitgestellt und verwendet werden.
Reguläre Ausdrücke
Direkt nach den Ziffern in einer Zeichenkette suchen: Hier zeigt, welchen Unterschied es macht, ob nur nach einem oder mehreren Zeichen gesucht wird, die dem Suchmuster entsprechen.
Reguläre Ausdrücke
Ein eher praxisnahes Beispiel: Durch den Einsatz der regulären Ausdrücke kann eine Eingabe daraufhin überprüft werden, dass nur bestimmte Zeichen/Ziffern und so weiter erlaubt sind.
Reguläre Ausdrücke
Mit den eckigen Klammern können bestimmte Bereiche abgefragt werden: Es ist zu beachten, dass auch hier die Überprüfung stoppt, sobald die erste Übereinstimmung gefunden wurde.
Reguläre Ausdrücke
Grundsätzlich leider nicht case-sensitiv: Wer die Eingaben auch in Bezug auf Groß- und Kleinschreibung untersuchen möchte, der sollte den Operator „-cmatch“ verwenden.
Reguläre Ausdrücke
. Kann durchaus verwirrend sein: Der „Accent Circumflex“ hat unterschiedliche Auswirkung, je nachdem wo er eingesetzt wird. In diesem Fall negiert er das Suchmuster.
Reguläre Ausdrücke
Einige Beispiele aus der Praxis, die zeigen, dass der Administrator unter Einsatz der regulären Ausdrücke sehr viel gezieltere und genauere Ausgaben erhält.
Reguläre Ausdrücke
Auch hier können die regulären Ausdrücke verwendet werden: Ein bestimmter Zweig der Registry („uninstall“ bei der Microsoft Software) wird direkt durchsucht und das entsprechend gefilterte Ergebnis ausgegeben.

Wir erläutern in diesem Beitrag die Grundlagen und zeigen anhand einer ganzen Reihe von Beispielen, dass diese kryptischen Zeichen sehr gut in der Praxis eingesetzt werden können.

Das Arbeitsfeld der regulären Ausdrücke: Vergleichen und Ersetzen

Die regulären Ausdrücke kommen hauptsächlich dann zum Einsatz, wenn es darum geht, Vergleiche durchzuführen oder etwa auch Werte und Zeichen zu ersetzen. Neben den Operatoren zum direkten Vergleich von Werten wie "-eq" (equal) oder -gt (greater than) gehören der sogenannte Ähnlichkeitsoperator "-like" (und "-unlike") sowie der Ersetzungsoperator "-replace" und die Übereinstimmungsoperatoren "-match" und "-unmatch" zur Kategorie der Vergleichsoperatoren.

Von ihnen können sowohl "-replace" als auch "-match" und "-unmatch" mit den regulären Zeichen umgehen, während der "-like"-Operator nur mit dem Wildcard-Zeichen "*" zusammenarbeitet, das für eine beliebige Anzahl von Zeichen steht. So bringen dann auch die folgenden beiden Aufrufe die genau gleiche Ausgabe auf den Bildschirm:

Get-Service | where {$_.status -like "running"}

Get-Service | where {$_.status -match "running"}

Beide Aufrufe zeigen alle auf dem jeweiligen System aktiven (running) Prozesse an. Der Unterschied liegt darin, dass die Vergleiche beim Einsatz von "-match" und den regulären Zeichen weitaus genauer und zielgerichteter durchgeführt werden können. Ein Hinweis ist in diesem Zusammenhang noch wichtig: Diese Art der Abfrage ist nicht Case-Sensitive - das bedeutet, dass hierbei nicht zwischen Groß- und Kleinschreibung unterschieden wird und beide Aufrufe sowohl Prozesse finden, die als "running" gekennzeichnet sind, als auch solche, die beispielsweise als "Running" ausgegeben werden.

Metazeichen, Suchmuster und was sie bewirken

Aber dazu ist es zunächst einmal wichtig, kurz zu erläutern, was sich hinter dem Begriff reguläre Ausdrücke eigentlich verbirgt. Grundsätzlich handelt es sich dabei um ein Muster (eine Zeichenfolge), die Daten beschreibt. So repräsentiert dann ein solcher Ausdruck immer eine bestimmte Art von Daten im Suchmuster.

Dazu werden auch sogenannte Metazeichen eingesetzt. Die wichtigsten Zeichen - die auch von der PowerShell verwendet werden - sind die folgenden:

., ^, $, [], { }, *, ?, \

wobei es sich hierbei keinesfalls um eine vollständige Aufzählung der bei den regulären Ausdrücken zum Einsatz kommenden Metazeichen handelt.

Wenn es sich also bei einem regulären Ausdruck lediglich um ein Muster handelt, was macht die PowerShell dann mit diesem Muster? Sie benutzt es dazu, es mit den ihr übergebenen Daten zu vergleichen. Hier ein einfaches Beispiel:

PS C: \> $Eingabe=‘TecChannel‘

Bei dem Objekt, das wir hier der Variablen "Eingabe" zugewiesen haben, handelt es sich eindeutig um eine Zeichenkette (String). Die regulären Ausdrücke in der PowerShell arbeiten mit Zeichenklassen, wie sie auch im Microsoft-.NET-Framework 3.5 zur Verfügung stehen. Um mithilfe des match-Operators festzustellen, ob es sich bei einem Objekt beispielsweise um ein "Wortzeichen" handelt, kann der folgende Aufruf eingesetzt werden:

PS C:\> $Eingabe -match "\w"True

Als "Wortzeichen" wird hierbei die Menge der Zeichen von a-z sowie A-Z und 0-9 angesehen. Wichtig hierbei: Soll dahingehend verglichen werden, ob es sich um ein solches Wortzeichen handelt, dann muss hinter dem Escape-Zeichen "\" ein kleines "w" folgen - an dieser Stelle wird sehr wohl zwischen Groß- und Kleinschreibung unterschieden. Kommt ein großes "W" zum Einsatz, so wird auf "Nicht-Wortzeichen" verglichen. Ein Beispiel dafür wäre ein Leerzeichen im String. So wird dann der folgende Aufruf:

PS C:\> $Eingabe -match "\W"False

logischerweise als unrichtig (False) angezeigt. Die PowerShell vergleicht bei diesem Aufruf, wie wir ihn hier angegeben haben, das zu untersuchende Muster so lange, bis die Bedingung zutrifft. Dies lässt sich schön durch das automatisch angelegte und bei einem Aufruf von -match auch automatisch gefüllte Objekt "$matches" zeigen. Das sieht dann bei unserem ersten Aufruf folgendermaßen aus:

PS C:\> $Eingabe=‘TecChannel‘

PS C:\> $Eingabe -match "\w"

True

PS C:\ $matches

Name Value

0 T

Das mag grundsätzlich ganz praktisch sein, aber viel häufiger wird es wohl sinnvoll sein, genauer auf Übereinstimmung mit dem Suchmuster zu testen. Hier kommen die schon zuvor erwähnten Metazeichen ins Spiel. Sie modifizieren den Vergleich folgendermaßen:

Beispiele für Vergleiche und Treffer

Das Vorhergehende mag nun ein wenig verwirrend erscheinen, deshalb ist es am besten, diese "Treffer" einmal selbst anhand der folgenden Beispiele auszuprobieren. So kann es durchaus nicht im Sinne des Anwenders sein, dass der Vergleich sofort nach dem ersten Treffer stoppt. Dieses Verhalten kann folgendermaßen geändert werden:

PS C:\> $Eingabe=‘Tec789Channel‘

PS C:\> $Eingabe -match "\w+"

True

PS C:\ $matches

Name Value

0 Tec789Channel

Geht es darum, auf Zahlen zu vergleichen, so hilft folgender Aufruf:

PS C:\> $Eingabe -match "\d"

True

PS C:\ $matches

Name Value

0 7

Auch hier stoppt der Vergleich nach der ersten Zahl und kann entsprechend erweitert werden:

PS C:\> $Eingabe -match "\d+"

True

PS C:\ $matches

Name Value

0 789

Mithilfe der geschweiften Klammern kann hier auch eine Anzahl von Zeichen festgelegt werden, die in der Zeichenkette zu finden sein soll. Dabei gilt grundsätzlich, dass ein solcher Aufruf in der Form {Anzahl der minimal vorhandenen Zeichen, Anzahl der maximal vorhandenen Zeichen} erfolgt. Befindet sich nur eine Zahl zwischen den geschweiften Klammern, so prüft die PowerShell, ob mindestens die Anzahl dieser Zeichen vorhanden ist. Der folgende Aufruf zeigt dies:

PS C:\> $Eingabe -match "\d{2}"

True

PS C:\ $matches

Name Value

0 78

während dieser Aufruf:

PS C:\> $Eingabe -match "\d{2,3}"

True

PS C:\ $matches

Name Value

0 789

als "wahr" angezeigt wird, wenn mindestens zwei und höchstens drei Ziffern in der Zeichenfolge zu finden sind. Zusammen mit den Zeichen, die einen String am Anfang (^) und am Ende ($) vergleichen, kann hier auch gleich ein praxisnäheres Beispiel gezeigt werden, nämlich die Abfrage eines Eingabe-Strings:

PS C:\> $Eingabe=Read-Host "Bitte drei Ziffern gefolgt von mindestens vier, aber nicht mehr als acht Buchstaben eingeben!"

Wenn nun eine Eingabe in diese Variable erfolgt ist, kann sie dann beispielsweise mit folgendem regulären Ausdruck auf ihre Richtigkeit überprüft werden:

PS C:\ > $Eingabe -match "^\d{3}\w{4,8}$"

Wenn Ihnen das immer noch ein wenig kryptisch erscheint, dann probieren Sie es einfach aus. Diese Art der Abfrage ist wohl nicht für ein sicheres Passwort geeignet, kann aber gut zum Verhindern von falschen Eingaben in Shell-Skripten zum Einsatz kommen.

Es geht noch mehr: Bereiche untersuchen, Groß- und Kleinschreibung …

Während sich die geschweiften Klammern, wie gerade gezeigt, zum Abprüfen einer bestimmten Anzahl von Übereinstimmungen einsetzen lassen, können die eckigen Klammer "[ ]" dazu verwendet werden, einen bestimmten Bereich von Zeichen zu vergleichen. Werden dabei zwischen den Klammer mehrere Zeichen angeben, so ist die Bedingung dann zutreffend, wenn mindestens eines dieser Zeichen im zu untersuchenden Objekt zu finden ist:

PS c:\ > $Eingabe=‘TecChannel Rulez‘

PS c:\> $Eingabe -match "[cz]"

True

PS c:\> $matches

Name Value

0 c

Wie bereits bekannt, stoppt die Shell den Vergleich, sobald eine erste Übereinstimmung gefunden wurde, was in diesem Fall dem ersten Auftauchen des Buchstaben "c" entspricht. Es ist dabei ebenfalls möglich, einen Bereich anzugeben, aus dem beispielsweise die Buchstaben stammen sollen:

PS c:\ > $Eingabe=‘TecChannel Rulez‘

PS c:\> $Eingabe -match "[b-m]"

True

PS c:\> $matches

Name Value

0 e

Hier wird das erste Zeichen gefunden, das aus dem Bereich von "b" bis "m" (einschließlich!) stammt, somit ist das "e" der erste Treffer. In vielen anderen Script-Sprachen wird an dieser Stelle von den regulären Ausdrücken auch eine Case-sensitive Unterscheidung unterstützt. Und so findet man leider auch in vielen Beschreibungen zur PowerShell immer wieder die falsche Behauptung, unter der PowerShell würde diese Vorgehensweise ebenso funktionieren. Testen Sie das einfach, indem Sie mit unserem Teststring (oder natürlich auch einer anderen Zeichenkette) nach dem ersten Vorkommen eines Großbuchstabens suchen. Der folgende Ansatz:

PS c:\ > $Eingabe=‘TecChannel Rulez‘

PS c:\> $Eingabe -match "[A-D]"

True

PS c:\> $matches

Name Value

0 c

sollte dann ja eigentlich erst beim zweiten "c" stoppen, was aber leider weder unter der Version 2.0 noch unter der aktuellen Version 3.0 bei Windows 8 und Windows Server 2012 nicht funktioniert. Hier muss unter der PowerShell eine Variante des -match-Operators zum Einsatz kommen. Wollen Sie reguläre Zeichen Case-sensitiv untersuchen, so müssen Sie dazu -cmatch verwenden, und Sie bekommen das gewünschte Ergebnis:

PS c:\ > $Eingabe=‘TecChannel Rulez‘

PS c:\> $Eingabe -cmatch "[A-D]"

True

PS c:\> $matches

Name Value

0 C

Metazeichen und ihre unterschiedliche Bedeutung

Wie bereits eingangs erwähnt, schrecken viele Anwender und auch System-Profis vor dem Einsatz der regulären Ausdrücke zurück, da sie deren Syntax als zu kryptisch und unübersichtlich ansehen.

Kann durchaus verwirrend sein: Der "Accent Circumflex" hat unterschiedliche Auswirkungen, je nachdem, wo er eingesetzt wird. In diesem Fall negiert er das Suchmuster.

Ein Punkt, der sicherlich entscheidend zu dieser weit verbreiteten Einschätzung beigetragen hat, ist die Tatsache, dass einige der Metazeichen durchaus unterschiedliche Bedeutung haben können, je nachdem, wo sie zum Einsatz kommen.

So haben wir in diesem Beitrag bereits das Metazeichen "^" (accent circumflex) vorgestellt, das es erlaubt, die Übereinstimmungen am Anfang einer Zeichenfolge zu finden. Kommt es allerdings innerhalb der eckigen Klammern zum Einsatz, so negiert es das darin formulierte Suchmuster. So findet der folgende Aufruf:

PS c:\ > $Eingabe=‘TecChannel678 Rulez‘

PS c:\> $Eingabe -match "[^a-z]"

True

PS c:\> $matches

Name Value

0 6

die Zeichen, die keine (!) Buchstaben sind - der Vergleich stoppt dementsprechend bei der Ziffer "6". Sollen alle zusammenhängenden Ziffern in dieser Zeichenkette gefunden werden, so würde das durch den folgenden Aufruf erledigt:

PS c:\> $Eingabe -match "[^a-z]+"

True

PS c:\> $matches

Name Value

0 678

Wird ein solcher Aufruf mit der Case-sensitiven Variante des -match-Operators in der folgenden Form gestartet:

PS c:\> $Eingabe -cmatch "[^a-z]"

True

PS c:\> $matches

Name Value

0 T

so stoppt der Vergleich schon beim ersten groß geschriebenen "T", da es nicht in den Bereich "a-z" hineinfällt und diese Bedingung somit zutrifft.

Sonder- und Escape-Zeichen und natürlich die Hochkommas

Neben der Problematik der Metazeichen, die in verschiedenen Zusammenhängen unterschiedliche Effekte hervorrufen, kommt es gerade beim Vergleich und bei der Untersuchung von Zeichenketten immer wieder zu einem anderen Problem: Die Metazeichen, die von den regulären Ausdrücken verwendet werden, tauchen häufig auch als Sonderzeichen in Zeichenketten auf und wollen dann entsprechend behandelt werden.

Grundsätzlich gilt dabei: Sollen diese Meta- oder Sonderzeichen nicht mit ihrer Funktion aufgerufen werden, so müssen sie maskiert werden. Das gelingt mit dem sogenannten "Escape"-Zeichen, das den regulären Zeichen dann mitteilt, dass sie das nächste Zeichen hinter diesem Escape-Zeichen genau so "betrachten" sollen, wie es da steht:

PS c:\> ‘Der $hell Fisch‘ -match "\$\w+"

True

Name Value

0 $hell

durch die Shell - so konnten wir hier erreichen, dass das Dollarzeichen auch als solches gesehen wird und die Shell nicht versucht, hier den Inhalt der Variablen "$hell" einzusetzen. Sie können den Unterschied leicht erkennen, wenn Sie diese Form der Eingabe ausprobieren:

PS c:\> "Der $hell Fisch" -match "\$\w+"False

Haben Sie zuvor einen anderen Aufruf mit dem -match-Operator ausgeführt, so kann es Ihnen allerdings jetzt passieren, dass Sie den vorherigen Wert in $matches finden. Besetzen Sie also sicherheitshalber diese Variable mit einem Leerstring in der folgenden Form, bevor Sie dieses Experiment ausführen:

$matches=""

Die Möglichkeiten, die Ihnen mit der PowerShell und unter Einsatz von regulären Zeichen zur Verfügung stehen, sind enorm - also haben Sie keine Scheu und probieren Sie diese mithilfe unseres Workshops einfach aus. Es gibt noch viel mehr Einzelheiten, Sonderzeichen und Tricks zu zeigen, aber das würde den Rahmen dieses Artikels deutlich sprengen.

Bildergalerie:
Mit regulären Ausdrücken arbeiten
Einige Beispiele aus der Praxis, die zeigen, dass der Administrator unter Einsatz der regulären Ausdrücke sehr viel gezieltere und genauere Ausgaben erhält.
Mit regulären Ausdrücken arbeiten
Auch hier können die regulären Ausdrücke verwendet werden: Ein bestimmter Zweig der Registry („uninstall“ bei der Microsoft Software) wird direkt durchsucht und das entsprechend gefilterte Ergebnis ausgegeben.

Zum Abschluss haben wir hier noch vier praxisnahe Beispiele herausgesucht. Überlegen Sie zunächst, was diese Aufrufe wohl anzeigen werden, und probieren Sie diese aus. In unserer Bilderstrecke können Sie dann auch Aufruf und Ausführung dieser Aufrufe sehen, wie sie auf unseren Testsystemen unter Windows 7 und Windows 8 abgelaufen sind:

dir c:\windows | where {$_.name -match "\s"}

(\s vergleicht auf "Whitespaces - also Leerzeichen und so weiter)

get-process [bw]*

get-service | where {$_.name -match "\d{1}"}

HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\kb[0-9]*

In unserer Bilderstrecke können Sie dann auch Aufruf und Ausführung dieser Aufrufe sehen, wie sie auf unseren Testsystemen unter Windows 7 und Windows 8 abgelaufen sind. (mje)