Windows PowerShellWindows PowerShell-Konstrukte

Don Jones

Im vergangenen Monat habe ich Ihnen einige Möglichkeiten vorgeführt, wie Sie Windows PowerShell unmittelbar für die Lösung von Verwaltungsaufgaben einsetzen können - ohne wirklich ein einziges Skript zu schreiben. Obwohl es sich bei Windows PowerShell um eine exzellente interaktive Shell handelt, können Sie die Fähigkeiten dieser Shell erst wirklich voll ausschöpfen und selbst hochkomplexe Aufgaben automatisieren, wenn Sie auch die leistungsstarke und dennoch einfach gehaltene Skriptsprache dieser Shell nutzen.

Zuerst werden Sie sich zwar fragen: Braucht Microsoft wirklich noch eine weitere Skriptsprache? Letzten Endes hat uns Microsoft KiXtart, ein Anmeldeskriptprozessor, und auch noch Visual Basic® Scripting Edition (VBScript) beschert. Wie dem auch sei. Die Antwort lautet: "Ja". Microsoft braucht wirklich noch eine weitere Skriptsprache. Ich werde erläutern warum.

Die Sprache von Windows PowerShell™ musste simpel und intuitiv gehalten werden, damit Administratoren die Sprache ohne umfangreichen Ausbildungsaufwand lernen können. Außerdem musste die Sprache recht flexibel gestaltet werden, damit in ihr all die leistungsstarken Funktionen ausgedrückt werden können, die uns von Windows PowerShell selbst geboten werden.

Da Windows PowerShell auf dem Microsoft® .NET Framework basiert, muss die Syntax der Skriptsprache .NET-geeignet sein. Beim Erstellen einer Skriptsprache für Windows PowerShell haben sich die Entwickler für eine Syntax entschieden, die im Wesentlichen ein stark vereinfachtes C# darstellt (sprich C-Sharp oder Cis, wie die Musiknote, eine der Sprachen, die im .NET Framework enthalten sind). Warum nicht bei einer Syntax wie bei VBScript bleiben? Die Skriptsprache von Windows PowerShell unterscheidet sich in Wirklichkeit nicht so sehr von VBScript. Mit einer stärkeren Anlehnung an die Syntax von C# bietet PowerShell jedoch eine Art erstes Sprungbrett für das Erlernen der Programmierung mit dem .NET Framework. Wenn Sie sich später einmal für einen Aufstieg zu Visual Studio® entscheiden und mit dem Schreiben von Anwendungen in C# beginnen, wird ein großer Teil der Skriptsyntax von Windows PowerShell Sie begleiten.

Zu den beeindruckendsten Dingen der Skriptsprache von Windows PowerShell - oder in der Tat jeder beliebigen Skriptsprache - gehören ihre Konstrukte. Bei Konstrukten handelt es sich um spezielle Sprachelemente, mit denen Windows PowerShell logische Vergleiche anstellen und anhand der Ergebnisse dieser Vergleichsoperationen unterschiedliche Aktionen oder einen oder mehrere Befehle immer wieder ausführen kann.

Logisches Denken

Kernstück vieler Skripting-Konstrukte sind logische Vergleiche, und Windows PowerShell stellt da keine Ausnahme dar. Eine Vergleichsoperation betrachtet im Wesentlichen zwei Werte oder Objekte und beurteilt, ob das Ergebnis des Vergleichs "True" (Wahr) oder "False" (Falsch) ist. So könnten Sie sich beispielsweise fragen: "Ist das Ablaufdatum des Kennworts dieses Benutzers gleich dem Datum des heutigen Tages?" Das Ergebnis wäre entweder "True", wenn die Daten identisch sind oder "False" wenn sie nicht übereinstimmen. Beachten Sie, dass ich "True" und "False" in Anführungszeichen gesetzt habe, da diese beiden Ausdrücke eine spezielle Bedeutung in Windows PowerShell haben.

Hier nun ein Beispiel für einen realen logischen Vergleich, wie Sie ihn in Windows PowerShell ausführen könnten:

PS C:\> $a = 1
PS C:\> $b = 2
PS C:\> $a -eq $b
False

Ich habe eine Variable mit dem Namen $a angelegt und ihr den Wert 1 zugewiesen. In Windows PowerShell beginnen Variablennamen immer mit einem Dollarzeichen und sind daher einfach zu erkennen. Das = wird technisch als Zuweisungsoperator bezeichnet, da es für das Zuweisen eines Wertes verwendet wird. Danach habe ich eine zweite Variable mit dem Namen $b angelegt und ihr den Wert 2 zugewiesen. Anschließend folgt der eigentliche logische Vergleich - Ich habe Windows PowerShell angewiesen, die Inhalte von $a und $b mit Hilfe des Operators -eq (equality, Gleichheit) zu vergleichen. PowerShell führt den Vergleich aus, ermittelt, dass die beiden Werte nicht gleich sind, und zeigt das Ergebnis an: False.

Wie Sie sicherlich bemerkt haben, unterscheiden sich die Operatoren von Windows PowerShell ein wenig von denen anderer Skriptsprachen, sogar von den Operatoren in C#. In den meisten Sprachen wird der Operator = verwendet, um auf Gleichheit zu prüfen, als auch um Werte zuzuweisen. Windows PowerShell vermeidet Verwechslungen, indem es für jede einzelne Funktion einen fest zugeordneten Operator gibt. Abbildung 1 zeigt die Vergleichsoperatoren von Windows PowerShell gemeinsam mit den entsprechenden Operatoren anderer Sprachen (wie VBScript), die Ihnen möglicherweise bereits vertraut sind.

Figure 1 Vergleichsoperatoren in PowerShell

Operator Name Beschreibung
-eq Equality (Gleichheit) Prüft, ob Werte identisch sind. In anderen Sprachen wird möglicherweise = oder == für das Prüfen auf Gleichheit verwendet.
-ne Not Equal (Ungleich) Prüft auf Ungleichheit. In anderen Sprachen wird möglicherweise <> oder != für das Prüfen auf Ungleichheit verwendet.
-gt Greater Than (Größer als) Prüft, ob ein Wert größer als der andere ist. In anderen Sprachen wird möglicherweise das Zeichen > verwendet.
-lt Less Than (Kleiner als) Prüft, ob ein Wert kleiner als der andere ist. In anderen Sprachen wird möglicherweise das Zeichen < verwendet.
-ge Greater Than or Equal To (Größer oder gleich) Prüft, ob ein Wert größer als oder gleich groß wie ein anderer ist. Wie >= in VBScript und anderen Sprachen.
-le Less Than or Equal To (Kleiner oder gleich) Prüft, ob ein Wert kleiner als oder gleich groß wie ein anderer ist. Wie <= in VBScript und anderen Sprachen.

Diese Vergleichsoperatoren verfügen über eine weitere interessante Eigenschaft. Werfen Sie einen Blick auf diesen Vergleich:

PS C:\> $a = "TechNet"
PS C:\> $b = "technet"
PS C:\> $a -eq $b
True

Standardmäßig unterscheiden die Vergleichsoperatoren nicht zwischen Groß- und Kleinschreibung, d. h. die Version "TechNet" mit Großbuchstaben ist gleich zu "technet". Das ist recht angenehm, da Sie sich bei den meisten Verwaltungsaufgaben nicht um Groß- oder Kleinschreibung zu kümmern brauchen. Gelegentlich wünschen Sie sich das doch, und Sie können Windows PowerShell anweisen, einen Vergleich mit Unterscheidung von Groß- und Kleinbuchstaben auszuführen, indem Sie dem Vergleichsoperator den Buchstaben c voranstellen:

PS C:\> $a -ceq $b
False

Auf ähnliche Weise können Sie, wenn Sie einmal besorgt sind oder nicht genau wissen, ob Windows PowerShell einen Vergleich ohne Unterscheidung von Groß- und Kleinbuchstaben ausführt oder mit, einen solchen Vergleich ohne Unterscheidung erzwingen, indem Sie den Buchstaben i voranstellen:

PS C:\> $a -ieq $b
True

Merken Sie sich einfach, dass logische Vergleiche immer einen von zwei Werten ergeben: True oder False.

Fällen von Entscheidungen

Da Sie nun wissen, wie logische Vergleiche geschrieben werden, können Sie diese Vergleiche in Konstrukten verwenden. Das erste Konstrukt, das ich zeigen werde, ermöglicht Windows PowerShell, anhand eines Vergleichs Entscheidungen zu treffen. Dieses Konstrukt wird "If"-Konstrukt (Wenn-Konstrukt) genannt. Von diesem Konstrukt gibt es einige Varianten. Hier die einfachste Variante:

PS C:\> if ($a -eq $b) {
>> Write-Host "They are equal"
>> }
>>
They are equal

Da gibt es einige bemerkenswerte Dinge. Erstens enthalten die Variablen $a und $b immer noch die Werte "TechNet" bzw. "technet". Das Konstrukt beginnt mit dem Schlüsselwort "If". Anschließend folgt, in Klammern, der logische Vergleich, der ausgeführt werden soll. Dann folgt eine geschweifte Klammer. Diese Klammer zeigt den Beginn dessen an, was ich als "bedingten Code" bezeichne, der Code, den Windows PowerShell ausführt, wenn die Vergleichsoperation den Wert "True" zurückgibt. Sie wissen noch aus dem ersten Beispiel, dass dieser Vergleich den Wert "True" zurückgibt. Ich gehe also davon aus, dass der bedingte Code ausgeführt wird. Ich gebe meinen bedingten Code ein, Write-Host "Die sind gleich", und drücke die Eingabetaste. Zum Schluss beende ich den Abschnitt für den bedingten Code, indem ich eine schließende geschweifte Klammer eingebe, und drücke zweimal die Eingabetaste. (Durch das zweite Drücken der Eingabetaste auf einer Leerzeile erkennt der Parser, dass ich nichts weiter eingeben möchte und der Code ausgeführt werden soll.)

Beachten Sie, dass dieses Konstrukt nicht als Skriptdatei ausgeführt wird. Ich habe das Konstrukt einfach nur in die Befehlszeile von Windows PowerShell eingegeben. Das ist es, was Windows PowerShell einzigartig in der Welt von Windows-Skripting macht: Skripts können sowohl interaktiv erstellt als auch dauerhaft in einer Datei gespeichert werden.

Sobald ich die öffnende geschweifte Klammer geschrieben und die Eingabetaste gedrückt habe, zeigt Windows PowerShell eine Eingabeaufforderung >> an. Damit sagt uns Windows PowerShell: "Ich habe erkannt, dass Du dich in einem Konstrukt befindest und ich bin bereit, damit Du schreiben kannst, was im Konstrukt erscheinen soll!". Nachdem ich die schließende geschweifte Klammer eingeben und zweimal die Eingabetaste gedrückt habe, wird das Konstrukt sofort von Windows PowerShell ausgeführt. Dabei erkennt Windows PowerShell, dass der logische Vergleich zum Ergebnis "True" führt und führt den bedingten Code aus. Sie erkennen dies daran, dass "Die sind gleich" angezeigt wurde, bevor PowerShell wieder die normale Eingabeaufforderung anzeigt. Durch die Verwendung von Windows PowerShell zum interaktiven Ausführen von Skripts können Sie kleine Codeabschnitte schnell testen, bevor Sie diese zu einem dauerhaften Skript zusammenstellen. Dadurch werden sowohl das Erlernen der Skriptsprache als auch das Debuggen vereinfacht.

Ich sollte betonen, dass Windows PowerShell nicht sonderlich pedantisch bezüglich solchen Dingen wie dem Drücken der Eingabetaste ist. So führt diese Eingabe beispielsweise zum gleichen Ergebnis wie das vorherige Beispiel:

PS C:\> if ($a -eq $b) { Write-Host "They are equal" }
They are equal

Da ich alles in eine einzige Zeile geschrieben habe, braucht Windows PowerShell nicht die spezielle Eingabeaufforderung >> anzuzeigen. PowerShell hat das Konstrukt einfach ausgeführt, als ich am Ende der Zeile die Eingabetaste gedrückt habe. Woher hat Windows PowerShell gewusst, dass das Konstrukt ausgeführt werden soll? Da es an dieser Stelle vollständig war - die schließende geschweifte Klammer wurde eingegeben.

Ich habe die anderen Varianten des "If"-Konstrukts bereits erwähnt. Hier sehen Sie ein umfassendes Beispiel, wie es eher in einer PS1-Skriptdatei enthalten sein könnte, als in der Shell:

if ($a -eq $b) {
  Write-Host "They are equal"
} elseif ($a -lt $b) {
  Write Host "One is less than the other"
} else {
  Write Host "One is greater than the other"
}

Das Konstrukt beginnt auf gleiche Weise, mit dem Schlüsselwort "If". Für den Fall, dass der Vergleich das Ergebnis "False" ergibt, habe ich jedoch mit dem Schlüsselwort "Elseif" einen weiteren Vergleich eingefügt. Wenn auch dieser zweite Vergleich den Wert "False" liefert, wird durch das letzte Schlüsselwort "Else" ein dritter Codeblock angegeben, der in diesem Fall ausgeführt wird.

Selbst wiederholende Konstrukte

Windows PowerShell enthält einige Konstrukte, durch die Code immer wieder ausgeführt wird, bis ein Vergleich entweder "True" oder "False" ist. Programmierer nennen das Schleifenkonstrukte. Noch besser: eines der nützlichsten Schleifenkonstrukte ist in der Lage, Objekte in einer Kollektion abzuzählen und eine oder mehrere Zeilen an Code für die einzelnen Objekte auszuführen. Treffenderweise wird dieses Konstrukt als Foreach-Konstrukt (FürJeden-Konstrukt) bezeichnet und hat die folgende Gestalt:

PS C:\> $names = get-content "c:\computers.txt"
PS C:\> foreach ($name in $names) {
>> Write-Host $name
>> }
>>
don-pc
testbed

Zu Anfang weise ich das Cmdlet "Get-Content" von Windows PowerShell an, den Inhalt der Datei c:\computers.txt abzurufen, eine Datei, die ich selbst angelegt habe und die einen einzigen Computernamen je Zeile enthält. Windows PowerShell behandelt jede einzelne Zeile als Objekt. Dadurch ist die Datei letztendlich eine Kollektion, die diese Objekte enthält. Die Kollektion wird in der Variablen $names "aufgespult". Mit dem Schlüsselwort "Foreach" weise ich Windows PowerShell an, die Kollektion $names durchzuzählen, wobei das aktuelle Objekt bei den einzelnen Durchläufen der Schleife in der Variablen $name repräsentiert wird. Der Code der Schleife wird in geschweifte Klammern eingeschlossen. So, nun werde ich jeden einzelnen Namen in der Datei auf der Befehlszeile anzeigen. Und wie Sie an der Ausgabe nach dem Konstrukt sehen können, ist dies genau das, was Windows PowerShell tut. Sie können erkennen, wie so ein offensichtlicher Nutzen für administrative Skripte erzielt werden kann: Sie können z. B. einfach eine Liste mit Servernamen konstruieren und Windows PowerShell anweisen, für jeden einzelnen Namen nacheinander Informationen abzurufen.

Konstrukte aus dem wahren Leben

Nehmen wir nun logische Vergleiche, das If-Konstrukt und das foreach-Konstrukt, und machen wir etwas Sinnvolles. Ich möchte schnell einmal den Status des Messenger-Service auf mehreren Servern überprüfen. Ich gehe davon aus, dass der Service auf den meisten Servern angehalten wurde, und ich möchte nicht, dass Windows PowerShell diejenigen Server auflistet, die sich sowieso im erwarteten Status befinden. Mein Wunsch ist, dass alle Server aufgelistet werden, auf denen der Messenger-Service wirklich gestartet wurde, da es sich genau um die Server handelt, die ich bearbeiten muss.

Mit ist bekannt, dass mir das Cmdlet "Get-Service" in Windows PowerShell beim Abrufen der benötigten Informationen für den lokalen Computer helfen kann. Unglücklicherweise kann ich jedoch nicht zu einem Remotecomputer gelangen, was ja mein eigentliches Ziel ist. Glücklicherweise kann ich auf diese Informationen jedoch über Windows Management Instrumentation (WMI) zugreifen. Dazu verwende ich das Cmdlet "Get-WMIObject", wodurch ich mit einem Remotecomputer arbeiten kann. So, hier ist das Skript:

$names = get-content c:\computers.txt
foreach ($name in $names) {
  $svc = get-wmiobject win32_service '
   -computer $name -filter "name='messenger'"
  if ($svc.started -eq $True ) {
    write-host "$name has Messenger running"
  }
}

Haben Sie das Zeichen ' in der dritten Zeile bemerkt? Durch dieses Zeichen weiß Windows PowerShell, dass diese Zeile auf der folgenden Zeile fortgesetzt wird. Das ist in Fällen wie diesem hilfreich, wenn die vollständige Zeile nur mit Zeilenumbruch dargestellt werden könnte. Beachten Sie außerdem, dass mein If-Konstrukt die Variable $svc.started mit $True vergleicht. Die Variable $True ist eine reservierte Variable in Windows PowerShell, die den Wert für das boolesche "True" darstellt. (Natürlich gibt es eine Variable $False, die den booleschen Wert "False" verkörpert.) In Wirklichkeit hätte ich hier etwas abkürzen können:

$names = get-content c:\computers.txt
foreach ($name in $names) {
  $svc = get-wmiobject win32_service '
   -computer $name -filter "name='messenger'"
  if ($svc.started) {
    write-host "$name has Messenger running"
  }
}

Denken Sie daran, dass der Vergleich im If-Konstrukt einfach nur "True" oder "False" ergeben muss. Normalerweise erhalten Sie "True" oder "False" durch den Vergleich zweier Werte, wie ich das in der ersten Version dieses Skripts getan habe. Da die Eigenschaft "Started" selbst entweder "True" oder "False" ist, muss dieser Wert eigentlich nicht mit "True" oder "False" verglichen werden.

Ein wirklich hilfreiches Tool

So, da haben wir es - ein einfaches, hilfreiches Tool für Verwaltungsaufgaben, das seine Arbeit mit Hilfe von Konstrukten erledigt. Ob Sie das Konstrukt nun interaktiv in Windows PowerShell eingeben oder zur einfachen Wiederverwendung in einer PS1-Datei speichern, es handelt sich um ein handliches Tool zum Überprüfen des Status eines Services auf mehreren Computern und um eine hervorragende Demonstration, wie Konstrukte die Automatisierung von Verwaltungsaufgaben erleichtern können.

Don Jones ist der Direktor für Projekte und Services bei SAPIEN Technologies und Mitverfasser von Windows PowerShell: TFM (SAPIEN Press, 2006). Besuchen Sie Don auf seiner Website unter ScriptingAnswers.com (in Englisch).

© 2008 Microsoft Corporation und CMP Media, LLC. Alle Rechte vorbehalten. Die nicht genehmigte teilweise oder vollständige Vervielfältigung ist nicht zulässig.