PowerShell im Vergleich mit anderen Sprachen

A PowerShell im Vergleich mit anderen Sprachen Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, ...
Author: Irmela Albrecht
2 downloads 2 Views 756KB Size
A

PowerShell im Vergleich mit anderen Sprachen

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Anhang

A

PowerShell im Vergleich mit anderen Sprachen Die meisten Leute, die zu PowerShell kommen, haben bereits Erfahrungen mit anderen Sprachen oder Shells gesammelt. In diesem Anhang werden wir deshalb PowerShell mit einigen der üblichen Shells und Sprachen vergleichen, die Sie möglicherweise schon kennen. Die meiste Zeit werden wir für cmd.exe (die traditionelle Windows Shell) und die UNIX-Shells verwenden. Wir werden ebenfalls auf einige Probleme eingehen, mit denen Perl-, VBScript- und C#-Programmierer zu kämpfen haben. Ganz nebenbei werden wir auch eine Anzahl nützlicher Techniken demonstrieren, die den ganz normalen PowerShell-User interessieren dürften. HINWEIS: In den folgenden Abschnitten finden Sie keine systematische Gegenüberstellung der

einzelnen Features. Stattdessen sind zahlreiche Hinweise und Tipps enthalten, die ich über Jahre hinweg gesammelt habe und die auf Fragen basieren, die mir die Leute gestellt haben. Ich gehe auf die häufigsten Stolpersteine und Probleme ein, mit denen neue PowerShell-User zu kämpfen haben. Natürlich ist es unmöglich, hier die Antworten auf alle auftretenden Fragen zu geben. Die Community mit ihren Blogs und Newsgroups ist insbesondere für den Anfänger eine schier unerschöpfliche Ressource, die dabei hilft, mit PowerShell schnell vertraut zu werden.

A.1 PowerShell und CMD.EXE Die heutzutage noch am häufigsten verwendete Windows Shell ist cmd.exe. Wir wollen deshalb hier auf einige Dinge hinweisen, die ein cmd.exe-User wissen sollte um erfolgreich nach PowerShell umzusteigen.

A.1.1 Grundlegendes Navigieren und Dateioperationen PowerShell stellt eine Reihe von Standard-Aliasen für die Namen der Basisbefehle zur Verfügung, wie sie ein cmd.exe-User bereits kennt. Wir können also sofort Basisoperationen wie dir, copy und sort ausführen, und diese werden mehr oder weniger so funktionieren wie wir das erwarten.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

528

A PowerShell im Vergleich mit anderen Sprachen

Etwas schwieriger wird es erst dann, wenn wir Optionen für diese Befehle festlegen wollen, denn PowerShell verwendet für Optionen eine andere Syntax. Befehle werden in PowerShell auch anders gehandhabt, insbesondere was die Verteilung der Funktionalität zwischen den verschiedenen Befehlen betrifft. Cmd.exe hat ziemlich wenig Befehle, diese aber verfügen über eine Menge an Funktionalität. Leider können diese Befehle nur schwer miteinander kombiniert werden. Demgegenüber hat PowerShell eine größere Anzahl von Befehlen mit weniger Optionen, die miteinander kombiniert werden können. So hat zum Beispiel das PowerShell-Äquivalent von dir keine sort-Option, stattdessen verwendet man den sort-Befehl. In den folgenden Tabellen zeigen wir einige wichtige Befehlsmuster, die den cmd.exe-User interessieren dürften. Tabelle A.1 enthält grundlegende Navigationsbefehle in cmd.exe sowie deren PowerShell-Äquivalente. Wir haben bereits erwähnt, dass Befehle in PowerShell in Wirklichkeit Aliase sind. In der Tabelle finden Sie manchmal auch ein zweites, kursiv gedrucktes Beispiel, dieses bezieht sich auf die ausführliche Notation des Befehls (kein Alias). So ist zum Beispiel "dir" ein Alias für "Get-ChildItem". Operationsbeschreibung

cmd.exe Syntax PowerShell

Liefert eine Liste des aktuellen Verzeichnisses

dir

dir Get-ChildItem

Liefert eine Liste aller Dateien die mit dir *.txt einem bestimmten Muster übereinstimmen

dir *.text Get-ChildItem *.txt

Liefert eine Liste aller Dateien in allen Unterverzeichnissen des aktuellen Verzeichnisses

dir /s

dir –rec Get-ChildItem –rec

Listet alle Textdateien in allen Unterverzeichnissen auf

dir /s *.txt

dir –rec –filter *.txt Get-ChildItem –rec –filter *.txt

Sortiert Dateien entsprechend des letzten Schreibzugriffs

dir /o:-d

dir | sort -desc LastWriteTime

Setzt das aktuelle Arbeitsverzeichnis auf eine bestimmte Stelle

cd c:\windows

cd c:\windows Set-Location c:\windows

Tabelle A.1 Vergleich einiger Basisbefehle zum Navigieren in cmd.exe und in PowerShell

Kopieren, Verschieben und Löschen von Dateien gehören ebenfalls zu den Grundoperationen. Tabelle A.2 vergleicht einige übliche Befehlsszenarien aus cmd.exe mit deren PowerShell-Äquivalenten. Operationsbeschreibung

cmd.exe Syntax

PowerShell

Eine Datei auf den Bildschirm kopieren

type file.txt

type file.txt Get-Content file.txt

Eine Datei kopieren

copy f1.txt f1.txt

copy f1.txt f2.txt Copy-Item f1.txt f2.txt

Mehrere Dateien kopieren

copy f1.txt,f2.txt,f3.txt c:\

copy f1.txt,f2.txt,f3.txt c:\

Mehrere Dateien verketten

copy f1.txt+f2.txt+f3.txt f4.txt type f1,txt,t2,txt,f3.txt > f4.txt

529

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

A.1 PowerShell und CMD.EXE

Operationsbeschreibung

cmd.exe Syntax

PowerShell

Eine Datei löschen

del file.txt

del file.txt Remove-Item file.txt

Alle Textdateien im aktuellen Verzeichnis löschen

del *.txt

del *.txt Remove-Item *.txt

Alle Textdateien in allen Unterverzeichnissen des aktuellen Verzeichnisses löschen

del /s *.txt

del –rec *.txt Remove-Item –rec *.txt

Tabelle A.2 Grundlegende Dateioperationen in cmd.exe und in PowerShell

Eine andere Möglichkeit zum Ausführen von Dateioperationen ergibt sich aus der Anwendung von Umleitungsoperatoren (redirection operators). Natürlich unterstützt PowerShell den Pipe-Operator (|) und auch dieselbe Menge von Umleitungsoperatoren (>, >>, 2>, 2>&1) wie in cmd.exe, allerdings gibt es keine Input-Umleitung. Stattdessen müssen wir den Get-Content-Befehl (oder dessen Alias) verwenden. Im folgenden Abschnitt vergleichen wir einige Syntax-Features beider Umgebungen, die beim Skripteschreiben von Bedeutung sind.

A.1.2 Variablen und Substitution In der cmd.exe Umgebung werden Variablen in Prozentzeichen (%) eingeschlossen und mit dem set Befehl gesetzt. BEISPIEL: Variablendefinition und -zuweisung in cmd.exe: C:\>set a=3 C:\>echo a is %a% a is 3

In PowerShell werden Variablen mittels Dollarsymbol ($) vor der Variablen gekennzeichnet. Um den Wert einer Variablen zu setzen, ist kein spezieller Befehl erforderlich – eine einfache Zuweisung genügt. BEISPIEL: Das Vorgängerbeispiel in PowerShell-Syntax: PS C:\> $a = 3 PS C:\> echo a is $a a is 3

Da ist aber noch etwas bei Variablen zu beachten: PowerShell unterstützt verschiedene Arten von Variablen, die Variablen in cmd.exe sind aber meistens Umgebungsvariablen. Das bedeutet, dass diese Variablen automatisch in den Child-Prozess exportiert werden, wenn cmd.exe einen Prozess erzeugt. Andererseits werden Umgebungsvariablen in PowerShell im separaten Namensraum ENV: abgelegt.

530

A PowerShell im Vergleich mit anderen Sprachen

BEISPIEL: Zuweisen einer Umgebungsvariablen in PowerShell: $env:envVariable = "Hello"

Als Nächstes wollen wir uns darüber unterhalten, wie Berechnungen auszuführen sind. Der setBefehl in cmd.exe wird auch für arithmetische Berechnungen verwendet.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

BEISPIEL: Eine Berechnung unter cmd.exe: C:\>set /a sum=33/9 3 C:\>echo sum is %sum% sum is 3

Auch hier benötigt PowerShell keine spezielle Syntax. Um eine Berechnung auszuführen braucht man dafür nur einen Ausdruck zu schreiben. BEISPIEL: Eine Berechnung unter PowerShell: PS C:\> $a = 2 + 4 PS C:\> $a 6 PS C:\> $b = $a /3 –[math]::sqrt(9) PS C:\> $b -1 PS C:\> [math]::sin( [math]::pi * 33 ) 4.88487288813344E-16 PS C:\>

Da PowerShell auf .NET aufsetzt, verfügt es auch über die vollen mathematischen Fähigkeiten solcher Sprachen wie C# und VB (Fließkomma-Operationen und Zugriff auf transzendente Funktionen inbegriffen). In cmd.exe gibt es eine Vielzahl von String-Operationen, die als Seiteneffekt beim Expandieren einer Variablen ausgeführt werden können. In PowerShell werden diese Arten von Operationen mit Ausdrücken und Operatoren realisiert. BEISPIEL: Eine Variable enthält den Dateinamen "myscript.txt", und wir wollen ihn unter Verwendung des

-replace-Operators in "myscript.ps1" ändern: PS C:\> $file = "myscript.txt" PS C:\> $file -replace '.txt$','.ps1' myscript.ps1

Der geänderte String wurde angezeigt. Nun wollen wir die Variable aktualisieren: PS C:\> $file = $file -replace '.txt$','.ps1'

Wir überprüfen, ob sie sich geändert hat: PS C:\> $file myscript.ps1

A.1 PowerShell und CMD.EXE

531

Das Verwenden von Operatoren zum Aktualisieren der Werte von Variablen ist nicht so übersichtlich wie die Notation bei der Variablenexpansion von cmd.exe, aber es steht im Einklang mit den restlichen Features von PowerShell.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

A.1.3 Befehle ausführen Nun wollen wir uns mit den Unterschieden bei der Ausführung von Befehlen in beiden Umgebungen auseinandersetzen. In PowerShell brauchen wir keinen Befehl um irgendetwas auf dem Bildschirm anzuzeigen. BEISPIEL: Ein String in der Kommandozeile wird direkt ausgegeben: PS C:\> "a is $a" a is 3

Andererseits müssen wir auch in der Lage sein, Befehle auszuführen, in deren Namen Zwischenräume enthalten sind. Wir benutzen dazu den PowerShell Call-Operator "&". BEISPIEL: Aufruf eines Befehls der Zwischenräume in seinem Namen hat: & "command with space in name.exe"

Ein weiterer Unterschied zwischen beiden Umgebungen bezieht sich auf die Art wie Skripte ausgeführt werden. Wenn Sie unter cmd.exe ein Skript ausführen, wirken sich alle Änderungen, die das Skript verursacht, auf die aktuelle Sitzung aus. Das hat zur allgemeinen Praxis geführt, dass BatchDateien zum Einstellen der Umgebung verwendet werden. Ein gutes Beispiel dafür ist die Datei "vcvars.bat", die zu Visual Studio gehört. Wenn wir diese Datei abspielen, aktualisiert diese den Pfad und setzt alle Variablen, die für die Kommandozeilen-Tools von Visual Studio erforderlich sind. (In Abschnitt A.1.7 werden wir zeigen, wie man diesen Typ einer Batchdatei verwendet.) Das standardmäßige Verhalten von PowerShell ist hingegen ein anderes. Wenn ein Skript ausgeführt wird, dann läuft es in seinem eigenen Bereich, sodass alle nichtglobalen Variablen, die es erzeugt hat, beim Verlassen des Skripts entsorgt werden. Um ein PowerShell-Skript zum Modifizieren unserer Umgebung zu verwenden, müssen wir einen Punkt (dot) voranstellen. Mit anderen Worten, wir setzen einen Punkt und einen Zwischenraum vor das auszuführende Skript. Wenn wir in cmd.exe einen lokalen Gültigkeitsbereich für Variablen schaffen wollen, benutzen wir die Schlüsselwörter setlocal/endlocal. PowerShell hat dieselbe Fähigkeit, wobei wiederum die Ampersand-Notation verwendet wird. BEISPIEL: Gültigkeitsbereich von Variablen in PowerShell: PS PS 3 PS 22 PS 3

C:\> $a = 3 C:\> $a C:\> & { $a = 22; $a } C:\> $a

532

A PowerShell im Vergleich mit anderen Sprachen

In diesem Beispiel haben wir zunächst im äußeren Gültigkeitsbereich den Wert von $a auf 3 gesetzt und angezeigt. Dann haben wir den &-Operator und geschweifte Klammern verwendet, um einen eingebetteten Gültigkeitsbereich zu erzeugen. In diesem eingebetteten Bereich haben wir $a den neuen Wert 22 zugewiesen und diesen angezeigt. Nach Verlassen des lokalen Gültigkeitsbereichs haben wir wieder den Wert von $a angezeigt, er entspricht dem Originalwert 3.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

A.1.4 Syntaktische Unterschiede Die PowerShell Syntax unterscheidet sich meistens deutlich von cmd.exe, außer in Bezug auf die grundlegenden Syntax gibt es auch einige signifikante Unterschiede in der Art und Weise wie die Befehle verarbeitet werden. Eine Sache mit der die von cmd.exe kommenden Umsteiger so ihre Schwierigkeiten haben ist die, dass man in cmd.exe keine Leerzeichen zwischen den eingebauten Befehlen und deren Argumenten einfügen muss. BEISPIEL: Erlaubte Befehlseingaben in cmd.exe: C:\>cd\windows C:\WINDOWS>cd.. C:\>dir\files\a.txt Volume in Laufwerk C: hat keine Bezeichnung. Volumeseriennummer: D8DE-A814 Verzeichnis von C:\files 11.06.2007 13:38 0 a.txt 1 Datei(en) 0 Bytes 0 Verzeichnis(se), 87.061.401.600 Bytes frei

In PowerShell hingegen endet das mit einer Fehlermeldung: PS C:\> cd\windows Die Benennung "cd\windows" wurde nicht als Commandlet, Funktion, ausführbares Programm oder S kriptdatei erkannt. Überprüfen Sie die Benennung, und versuchen Sie es erneut. Bei Zeile:1 Zeichen:10 + cd\windows
cd windows PS C:\> cd..

Damit sind einige der angesprochenen Probleme behoben, allerdings nicht alle. Wir müssen immer noch ein Leerzeichen zwischen "cd" und "windows" einfügen. Trotzdem empfinden manche Leute diese Vorgehensweise als sehr nützlich. Wenn Sie wollen, dass Ihnen diese Funktionen jederzeit zur Verfügung stehen wenn Sie PowerShell starten, dann können Sie diese in Ihr persönliches Profil einfügen, welches durch die Variable $PROFILE benannt ist. Führen Sie folgenden Befehl aus: notepad $profile

... und fügen Sie die Definitionen hinzu, die Ihnen immer zur Verfügung stehen sollen, und speichern Sie die Datei. Wenn Sie PowerShell das nächste Mal starten, stehen Ihnen alle in diesem Profil definierten Funktionen sofort zur Verfügung.

A.1.5 Textsuche: findstr und Select-String Ein allgemeiner Befehl zur Dateisuche in cmd.exe ist findstr.exe. (Beachten Sie, dass das ein externer Befehl ist und demzufolge auch von PowerShell aus funktioniert.) PowerShell hat einen ähnlichen Befehl: Select-String. Warum aber brauchen wir ein neues Commandlet, wenn die alte Exe auch funktioniert? Es gibt dafür eine Reihe von Gründen: Das Select-String-Commandlet liefert Objekte, die den übereinstimmenden Text, die Zeilennummer und den Dateinamen als separate Felder enthalten. Das vereinfacht das Verarbeiten des Outputs. Weiterhin benutzt das Commandlet die .NET-Bibliothek regulärer Ausdrücke, die weitaus leistungsfähiger ist als die Muster die findstr verarbeiten kann. Wenn wir uns die Hilfe für findstr anschauen, so sehen wir, dass es eine Menge von Optionen gibt die in Select-String nicht vorhanden sind. Das liegt daran, dass PowerShell ein so genanntes Kompositions-Modell benutzt. Anstatt eine umfangreiche Menge von Operationen in einem Befehl zusammenzufassen, gibt es mehrere kleinere Befehle die miteinander kombiniert werden können. BEISPIEL: Mit findstr alle C#-Dateien in allen Unterverzeichnissen suchen: findstr /s Main *.cs

Mit Select-String würden wir den Output von dir in den Befehl leiten: dir –rec –filter *.cs | select-string main

A.1.6 Äquivalente für die For-Schleife Iterationen (d.h. das Verarbeiten von verschiedensten Auflistungen) werden in cmd.exe mit dem for-Statement realisiert. Dies ist ein leistungsfähiger aber auch ziemlich komplexer Befehl zur Flusskontrolle. PowerShell verfügt hingegen über einfachere Mechanismen um dasselbe zu tun und

534

A PowerShell im Vergleich mit anderen Sprachen

zwar mittels Pipelines. Tabelle A.3 zeigt einige einfache Beispiele, die eine cmd.exe Anweisung mit dem äquivalenten PowerShell Konstrukt vergleichen.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Beschreibung

cmd.exe

PowerShell

Iterieren über Dateien

for %f in (*) do echo %f

dir | ? {! $_.PSIsContainer} | % {$_ }

Iterieren über Verzeichnisse

for /d %f in (*) do echo %f

dir | ? { $_.PSIsContainer} | % {$_ }

Iterieren über die Zahlen von 1 to 9 in 2er Schritten

for /l %i in (1,2,10) do ( @echo %i )

for ($i=1; $i -lt 10; $i+=2) { $i }

Tabelle A.3 Beispiele für Iterationen in cmd.exe und inPowerShell

Nun wollen wir einige etwas komplexere Beispiele betrachten. Ebenso wie zum Iterieren über Dateien kann man das for-Statement von cmd.exe auch zum Parsen von Dateien verwenden. Listing A.1 zeigt einen for-Befehl, der die ersten drei Token einer Datei extrahiert und ausgibt. Listing A.1: Tokenizer mit dem for-Statement von cmd.exe for /f "tokens=1-3" %a in (c:\temp\data.txt) do ( @echo a is %a b is %b c is %c)

Den korrespondierenden PowerShell-Befehl zeigt das Listing A.2. Listing A.2: Tokenizer mit PowerShell type c:\temp\data.txt |%{ $a,$b,$c,$d = [regex]::split($_,' +'); "a is $a b is $b c is $c" }

Das for-Statement ist monolitisch – es gibt keine Möglichkeit um die Tokenizer-Fähigkeiten des for-Statement separat einzusetzen. In PowerShell werden all diese Operationen (Datei lesen, tokenisieren usw.) mit verschiedenen Komponenten ausgeführt. Die [regex]::Split()-Methode kann überall eingesetzt werden, da sie nicht zu einem bestimmten Statement gehört.

A.1.7 Batchdateien und Subroutinen In cmd.exe ruft man Subroutinen mittels goto-Statement auf und verwendet ein goto um zum Aufrufer zurückzukehren. Eine cmd.exe-Prozedur wird mittels call-Statement aufgerufen. PowerShell hingegen hat erstklassige Funktionen, inbegriffen sind benannte Parameter, optionale typisierte Parameter und Rekursionen. PowerShell-Skripte können auch als Befehle aufgerufen werden, auch sind wiederum Rekursionen und benannte Parameters erlaubt. PowerShell besitzt kein goto-Statement, innerhalb des loop-Statements können allerdings Sprungmarken (Label) benutzt werden. Achten Sie auch darauf, dass es in PowerShell keinen Unterschied im Verhalten beim Eintippen von Code an der Befehlszeile und beim Ausführen von Code außerhalb einer Funktion oder eines Skripts gibt. Syntax und Semantik sind immer gleich.

535

A.1 PowerShell und CMD.EXE

Eine der gebräuchlichsten Anwendungen für cmd.exe-Batchdateien ist das Setzen von Umgebungsvariablen. Wie bereits erwähnt, gibt es (wenn Sie Visual Studio installiert haben) eine Batchdatei "vcvarsall.bat", die zum Einstellen der Umgebungsvariablen in cmd.exe dient. Es ist ebenfalls möglich, diese Batchdatei von PowerShell aus aufzurufen, die Änderungen an der Umgebung vorzunehmen und dann diese Änderungen zurück in die PowerShell-Umgebung zu importieren. Das klingt zwar kompliziert, ist aber in Wahrheit ziemlich einfach. Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

BEISPIEL: Zwecks Setzen von Umgebungsvariablen definieren wir zuerst einen Stapelbefehl, der innerhalb

der Variablen $cmd ausgeführt werden soll: PS C:\> $cmd = >> '"C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"' + >> ' & set' >>

Als Nächstes rufen wir den Befehl auf, indem wir den Output in den %-Befehl leiten: PS C:\> cmd /c $cmd |%{ >> $p,$v = $_.split('='); set-item -path env:$p -value $v } >>

Im Körper des Blocks wird der übergebene Befehl in Namen ($n) und Wert ($v) aufgesplittet. Diese Teile werden dann an Set-Item weitergereicht, um den Wert der korrespondierenden Umgebungsvariablen zuzuweisen. Nun wollen wir das Ergebnis unserer Bemühungen betrachten: PS C:\> ls env:v* Name ---VS80COMNTOOLS VSINSTALLDIR VCINSTALLDIR

Value ----C:\Program Files\Microsoft Visual... C:\Program Files\Microsoft Visual... C:\Program Files\Microsoft Visual...

Wie Sie sehen, wurden die Variablen richtig zugewiesen. Wir wollen das jetzt zu einer Funktion verallgemeinern, die mit jeder Batchdatei arbeiten kann. Listing A.3 zeigt den Source-Code der Get-BatchFile-Funktion. Listing A.3: Beispiel: Get-BatchFile-Funktion function Get-BatchFile ($file) { $cmd = "`"$file`" & set" cmd /c $cmd | Foreach-Object { $p,$v = $_.split('=') Set-Item -path env:$p -value $v } }

Diese Funktion macht dasselbe wie der Befehl den wir eingegeben haben. Der einzige Unterschied besteht darin, dass wir den vollständigen Namen der Commandlets verwenden, anstatt den %Alias für Foreach-Object, und dass die auszuführende Batchdatei als Argument übergeben wird.

536

A PowerShell im Vergleich mit anderen Sprachen

(Nebenbei bemerkt ist es hier besser, wenn Sie den vollständigen Namen des Befehls und nicht den Alias verwenden. Die Person, die später einmal Ihre Skripte lesen soll, wird Ihnen dafür dankbar sein.)

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

A.1.8 Den Prompt einstellen Eine der häufigsten Fragen von Leuten, die zu PowerShell wechseln, bezieht sich auf das Anpassen der Eingabeaufforderung (Prompt). In cmd.exe wird dies durch Setzen der PROMPT Variablen realisiert. BEISPIEL: Das typische Zuweisen von PROMPT in cmd.exe: C:\files>set prompt PROMPT=$P$G

In PowerShell wird der Prompt durch die prompt-Funktion kontrolliert. Diese Funktion sollte einen einzelnen String zurückgeben. BEISPIEL: Das Äquivalent von "$P$G" in PowerShell: PS C:\> function prompt {"$PWD> "} C:\files>

Dass die Eingabeaufforderung in PowerShell eine Funktion ist hat den Vorteil, dass so ziemlich alles damit gemacht werden kann. BEISPIEL: Sie wollen als Prompt den Wochentag anzeigen: C:\files> function prompt { "$((get-date).DayOfWeek)> " } Monday>

Wir haben die Funktion neu definiert und sehen nun was für ein Tag heute ist. Und noch etwas können wir tun: Das Anzeigen des Pfads im Prompt ist ein Problem, da dieser ziemlich lang werden kann. Manche Leute zeigen ihn deshalb lieber im Fenstertitel an. Man kann sich diesen Wunsch mit einer Funktion wie in Listing A.4 erfüllen: Listing A.4: Beispiel: Prompt-Funktion function prompt { $host.ui.rawui.WindowTitle = "PS $pwd" "PS > " }

Das Ergebnis der Neudefinition der Eingabeaufforderung zeigt die Abbildung A.1. Der String "PS > " wird immer noch als aktueller Prompt angezeigt, aber die Funktion setzt außerdem noch den Fenstertitel.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

A.1 PowerShell und CMD.EXE

537

Abbildung A.1 Zuweisen der Eingabeaufforderung in in PowerShell

Weil der Prompt eine Funktion ist, kann er alles Mögliche tun, also Befehle protokollieren, Sound abspielen, Bemerkungen ausgeben usw.

A.1.9 Verwenden von doskey in PowerShell Das doskey-Tool erlaubt uns das Definieren von Tastatur-Makros für das Konsolenfenster. Was bedeutet das? Doskey-Makros werden vom Konsolen-Subsystem verarbeitet, das ist der Teil des Windows-Betriebssystems der sich um die Wiedergabe des Konsolenfensters und das Auslesen der Tastatur kümmert. Wenn ein Konsolenprogramm Readline() aufruft, überprüft das Konsolen-Subsystem, ob irgendwelche Makros für dieses Programm verfügbar sind. Falls ja, dann wird die Makro-Substitution mit dem String vorgenommen bevor die Rückkehr zum User erfolgt. Warum kümmert uns das? Weil es bedeutet, dass wir ebenfalls Doskey-Makros in PowerShell verwenden können. Das folgende Beispiel demonstriert die Verwendung des doskey-Tools in PowerShell. BEISPIEL: Zunächst wird überprüft, ob irgendwelche Makros für PowerShell definiert wurden: PS C:\> doskey /macros:powershell.exe

Da nichts zurückgegeben wurde, nehmen wir an, dass momentan keine Doskey-Makros für PowerShell vorhanden sind. Beachten Sie, dass wir immer den vollständigen Namen für die ExeDatei angeben müssen. Standardmäßig ist dies cmd.exe, sodass wir den Namen in powershell.exe ändern mussten. Nun wollen wir ein Makro definieren: PS C:\> doskey /exename=powershell.exe ` >> ddir = dir `$* `| ? `{ '$_.PSIsContainer' `} >>

Das erfordert ein bisschen Aufwand weil man sich absichern muss, dass die Argumente ordnungsgemäß zu doskey durchgereicht werden. Wenn Sie eine Anzahl Makros definieren wollen, dann ist das wahrscheinlich am einfachsten mit der doskey/file-Option. Nun wollen wir uns davon überzeugen, dass das Makro richtig definiert wurde. Achten Sie darauf, dass der Text in der Befehlszeile so ersetzt wird, dass die resultierende Befehlszeile syntaktisch korrekt ist. PS C:\> doskey /macros:powershell.exe ddir=dir $* | ? { $_.PSIsContainer }

538

A PowerShell im Vergleich mit anderen Sprachen

Das sieht gut aus. Beachten Sie die Verwendung von $* in den Makros. Wird die doskey-Makrosubstitution durchgeführt, dann wird $* durch irgendein Argument ersetzt, das man dem Makro übergibt. Das wollen wir nun ausprobieren: PS C:\> ddir

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Verzeichnis: Microsoft.PowerShell.Core\FileSystem::C:\files Mode ---d---d---d----

LastWriteTime ------------19.06.2006 12:35 19.06.2006 12:35 19.06.2006 12:35

Length Name ------ ---d1 d2 d3

Es werden nur die Verzeichnisse im aktuellen Verzeichnis angezeigt. Wir probieren es nochmals mit der Option -rec und sehen was passiert: PS C:\> ddir -rec Verzeichnis: Microsoft.PowerShell.Core\FileSystem::C:\files Mode ---d---d---d----

LastWriteTime ------------19.06.2006 12:35 19.06.2006 12:35 19.06.2006 12:35

Length Name ------ ---d1 d2 d3

Verzeichnis: Microsoft.PowerShell.Core\FileSystem::C:\files\d2 Mode ---d---d----

LastWriteTime ------------19.06.2006 12:35 19.06.2006 12:35

Length Name ------ ---dd1 dd2

Dieses Mal haben wir alle Verzeichnisse, inklusive der Unterverzeichnisse, erhalten. Doskey erlaubt Ihnen auch einen Blick auf den Befehlsverlauf der Konsole. Auch davon wollen wir uns jetzt überzeugen. Wieder müssen wir den vollen Namen der Exe-Datei angeben:. PS C:\> doskey /exename=powershell.exe /h cd c:\files doskey /macros:powershell.exe doskey /exename=powershell.exe ` ddir = dir `$* `| ? `{ '$_.PSIsContainer' `} doskey /macros:powershell.exe ddir ddir -rec doskey /exename=powershell.exe /h

Alle Befehle, die wir bisher eingetippt haben, werden angezeigt. PowerShell verwaltet auch den Verlauf aller von ihm ausgeführten Befehle. Da diese Befehle nach den doskey-Substitutionen aufgezeichnet werden, sehen Sie anstelle Ihrer Eingaben jetzt die expandierten Befehle:

A.1 PowerShell und CMD.EXE

539

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

PS C:\> get-history Id CommandLine -- ----------1 cd c:\files 2 doskey /macros:powershell.exe 3 doskey /exename=powershell.exe `... 4 doskey /macros:powershell.exe 5 dir | ? { $_.PSIsContainer } 6 dir -rec | ? { $_.PSIsContainer } 7 doskey /exename=powershell.exe /h

Beachten Sie die Befehle mit den IDs 5 und 6. Das sind die expandierten Befehle, die zu den Eingaben "ddir" und "ddir –rec" gehören. Auf diese Weise lässt sich beobachten, was die MakroExpansion tatsächlich bewirkt hat. Doskey ist ein Tool welches Ihnen dabei helfen kann, auf einfache Weise Befehle von cmd.exe nach PowerShell zu übertragen. Sie können damit parametrisierte Makros definieren, die einfache Strings in komplexere PowerShell-Ausdrücke expandieren.

A.1.10 Verwenden von cmd.exe in PowerShell Das letzte Thema bezieht sich darauf, wie wir cmd.exe von PowerShell aus benutzen können. Konkret bedeutet das: Können wir unsere vorhandenen Skripte weiter verwenden? Die Antwort lautet, dass Sie diese Skripte größtenteils weiter benutzen können. Wenn PowerShell eine Datei mit der .cmd Extension erkennt, wird es diese einfach ausführen. Wenn das nicht funktioniert, dann hängt das mit all den Konfigurationsskripten zusammen, die einige Leute verwenden. Diese Skripte setzen eine Anzahl von Variablen und werden dann beendet. Von PowerShell aus werden sie nicht funktionieren, weil der cmd.exe-Prozess, der erzeugt wurde um die Skripte auszuführen, beendet wird wenn die Batchdatei fertig abgearbeitet ist und damit alle Änderungen verworfen werden. Wir können mittels "cmd /c" irgendeinen der eingebauten cmd-Befehle von PowerShell aus ausführen. BEISPIEL: Aufruf eines cmd.exe- Befehls von PowerShell aus: PS C:\> cmd /c 'for %f in (*) do @echo %f' a.txt b.txt c.txt d.txt

BEISPIEL: Wir benutzen cmd.exe für einen Befehl, mit dem wir einige Dateien generieren, die dann mit dem

foreach-Statement von PowerShell verarbeitet werden: PS C:\> foreach ($f in cmd /c 'for %f in (*) do @echo %f') >> { $f.ToUpper() } >> A.TXT B.TXT

540

A PowerShell im Vergleich mit anderen Sprachen

C.TXT D.TXT

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Sie sehen, dass Sie beim Übergang zu PowerShell Ihr über Jahre mit cmd.exe hart erworbenes Wissen nicht über Bord zu werfen brauchen, sondern Sie können es mit PowerShell mischen bzw. daran anpassen.

A.2 PowerShell und UNIX-Shells In diesem Abschnitt wollen wir uns Beispiele anschauen, in denen wir PowerShell mit UNIX Shells vergleichen, speziell meinen wir die Bourne Shell-Familie (sh, ksh, bash usw.). Obwohl PowerShell stark von diesen Shells inspiriert wurde, gibt es doch große Unterschiede. Der offensichtlich größte Unterschied ist, dass PowerShell für die Interaktion mit dem User Objekte anstatt Strings benutzt. Zweitens ist die Liste der "eingebauten" Befehle größer und kann vom User erweitert werden. Es gibt keinen Unterschied zwischen den eingebauten Befehlen und den vom User erzeugten zusätzlichen Commandlets. Dieses Modell ist eine notwendige Konsequenz aus der Entscheidung zugunsten der Verwendung von Objekten. Das Out-of-Process-Erweiterungsmodell, wie es von traditionellen Shells benutzt wird, ist für eine objektbasierte Shell einfach nicht praktikabel. Auch die Verwendung von XML als Zwischenformat ist wegen des großen Aufwands für Serialisierung und Deserialisierung jedes Objekts nicht möglich. Anstatt die einzelnen Features von PowerShell mit denen der Unix-Shells zu vergleichen, werden wir in diesem Abschnitt eine Reihe von aussagekräftigen Beispielen erörtern.

A.2.1 Beispiel: Alle Prozesse anhalten Um auf einem Unix System alle Prozesse anzuhalten die mit dem Buchstaben "p" beginnen, würden Sie an der Kommandozeile Folgendes eingeben: $ ps -e | grep " p" | awk '{ print $1 }' | xargs kill

Der ps-Befehl liefert eine Liste der Prozesse und sendet den auszugebenden Text an grep. Der grep-Befehl durchsucht den String nach Prozessen, deren Namen mit "p" anfangen. Der Output von grep wird zum awk Befehl geschickt, welcher die erste Spalte im Eingabetext selektiert (in der Prozess- ID) und übergibt diese an den xargs-Befehl. Der xargs Befehl führt dann den kill-Befehl für jeden Prozess aus, der als Input empfangen wird. Wegen seiner Komplexität und der Anzahl der auszuführenden Schritte ist dieser Befehl ziemlich labil. Das Problem besteht darin, dass sich der ps-Befehl auf unterschiedlichen Systemen (oder sogar bei verschiedenen Versionen) unterschiedlich verhält. So kann zum Beispiel der an der Kommandozeile eingegebene Befehl fehlschlagen, weil das -e-Flag bei ps fehlt oder der auszuführende Befehl sich nicht in der ersten Spalte des Outputs befindet. Nun wollen wir uns den äquivalenten PowerShell-Befehl ansehen, er ist sowohl einfacher als auch verständlicher: PS C:\> get-process p* | stop-process

A.2 PowerShell und UNIX-Shells

541

Diese Befehlszeile besagt "liefere mir die Prozesse deren Namen mit "p" beginnen und halte sie an". Das Get-Process-Commandlet nimmt ein Argument, welches mit dem Namen des Prozesses übereinstimmt. Die von Get-Process zurückgegebenen Objekte werden direkt an das Stop-ProcessCommandlet weitergeleitet, welches diese Objekte stoppt. Nun kommen wir zu einem etwas komplizierteren Beispiel.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

A.2.2 Beispiel: Stoppen einer gefilterten Prozessliste Diese Aufgabe dürfte schon etwas schwieriger sein: "Finde die Prozesse, die mehr als 10 MB Speicherplatz belegen und lösche sie!". Zunächst der entsprechende Unix-Befehl: $ ps -el | awk '{ if ( $6 > (1024*10)) { print $3 } }' | grep -v PID | xargs kill

Der Erfolg dieser Befehlszeile hängt davon ab, ob der User weiß, dass der ps -el-Befehl die Prozessgröße in Kilobytes (KB) in Spalte 6 und die PID des Prozesses in Spalte 3 liefert. Weiterhin ist es erforderlich, dass die erste Ausgabezeile von ps entfernt wird. Jetzt kommen wir zum korrespondierenden PowerShell-Befehl, der auch dieses Mal deutlich kürzer und einfacher ausfällt: PS C:\> get-process | where { $_.VS -gt 10M } | stop-process

Wir erkennen, dass der Befehl mit Objekten anstatt mit Texten arbeitet. Es gibt keinerlei Probleme beim Bestimmen der Spalten, die die Prozessgröße bzw. die ProcessID enthalten. Die Speicherplatzgröße kann logisch über ihren Namen angesprochen werden. Das Where-Commandlet kann die hereinkommenden Objekte direkt begutachten und sich auf deren Eigenschaften beziehen. Das Vergleichen des Werts dieser Eigenschaft geschieht direkt und ist leicht verständlich.

A.2.3 Beispiel: Berechnen der Größe eines Verzeichnisses In diesem Beispiel wollen wir die Größen aller Dateien in einem Verzeichnis summieren. Wir iterieren über die Dateien, ermitteln deren Länge, addieren diese zu einer Variablen und geben diese Variable aus. Zunächst betrachten wir uns den Code für die Unix Shell: $ tot=0; for file in $( ls ) > do > set -- $( ls -log $file ) > echo $3 > (( tot = $tot + $3 )) > done; echo $tot

Dieses Beispiel verwendet den set-Befehl, welcher nummerierte Variablen für jedes durch einen Whitespace getrennte Element einer Zeile erzeugt (statt des awk Befehls im vorhergehenden Beispiel). Hätten wir den awk-Befehl benutzt, dann wäre folgende Reduzierung der durchzuführenden Schritte möglich gewesen: $ ls –l | awk ‘{ tot += $5; print tot; }’ | tail -1

542

A PowerShell im Vergleich mit anderen Sprachen

Das verringert zwar die Komplexität dessen was wir eingeben müssen, erfordert aber, dass wir sowohl die Shell-Sprache als auch den awk-Befehl kennen (dieser hat seine eigene Skriptsprache). Die PowerShell-Schleife ist ähnlich, jede Datei im Verzeichnis wird benötigt, aber der Code ist deutlich einfacher, da wir auf die Datei-Informationen über das entsprechende Objekt zugreifen können:

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

PS C:\> get-childitem | measure-object -Property length

Das Measure-Object-Commandlet agiert mit Objekten, und wenn es mit einer Property dieses Objekts versorgt wird, dann summiert es die Werte dieser Eigenschaft. Da die Property length die Länge der Datei repräsentiert, ist das Measure-Object-Commandlet in der Lage, direkt mit dem Objekt zu arbeiten, indem es sich auf den Namen der Eigenschaft bezieht ohne "wissen" zu müssen, dass die Dateilänge in Spalte 3 bzw. in Spalte 5 enthalten ist.

A.2.4 Beispiel: Arbeiten mit dynamischen Werten Viele Objekte, die das System zur Verfügung stellt, sind nicht statisch sondern dynamisch. Das bedeutet, dass ein vorhandenes Objekt nicht nochmals zugewiesen werden muss wenn man es später wieder benötigt, weil die Daten des Objekts kontinuierlich aktualisiert werden, wenn Änderungen im System auftreten. Umgekehrt wirken sich alle Änderungen des Objekts sofort auf das System aus. Wir nennen diese Objekte deshalb "aktive Objekte" (live objects). Nehmen wir zum Beispiel an, dass jemand die Prozessorzeit ermitteln will, die ein Prozess im Verlauf einer bestimmte Zeitspanne beansprucht. Im traditionellen Unix-Modell müsste man dazu den ps-Befehl wiederholt aufrufen, die entsprechende Spalte im Output müsste gefunden und dann die Subtraktion ausgeführt werden. Mit einer Shell, die mit "lebenden" Objekten arbeiten kann, müssen wir nur auf das Prozessobjekt zugreifen und – da es kontinuierlich vom System aktualisiert wird – periodisch dieselbe Eigenschaft auslesen. Das folgende Beispiels demonstriert, wie der Speicherplatzbedarf einer Applikation im 10-Sekunden-Intervall geprüft wird und die Differenzen ausgegeben werden. Zunächst das entsprechende Unix Skript: $ while [ true ] do msize1=$(ps -el|grep application|grep -v grep|awk '{ print $6}') sleep 10 msize2=$(ps -el|grep application|grep -v grep|awk '{print $6}') expr $msize2 - $msize1 msize1=$msize2 done

Nun dasselbe Beispiel in PowerShell: PS> $app = get-process application PS> while ( $true ) { >> $msize1 = $app.VS >> start-sleep 10 >> $app.VS - $msize1 >> }

543

A.2 PowerShell und UNIX-Shells

Wieder stellt sich heraus, dass das PowerShell Skript einfacher ist und man es leichter verstehen kann.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

A.2.5 Beispiel: Die Lebenszeit eines Prozesses überwachen Zu bestimmen, ob ein Prozess nicht mehr läuft, ist nicht ganz so einfach wie es scheinen mag. In so einem Fall muss der Unix-User eine Liste der Prozesse aufstellen und diese mit einer anderen Liste vergleichen: $ $ > > > > > > > > > >

processToWatch=$( ps -e | grep application | awk '{ print $1 }' while [ true ] do sleep 10 processToCheck=$(ps -e |grep application |awk '{print $1}' ) if [ -z "$processToCheck" -or \ "$processToWatch" != "$processToCheck" ] then echo "Process application is not running" return fi done

In PowerShell sieht das so aus: PS C:\> $processToWatch = get-process application PS C:\> $processToWatch.WaitForExit()

Wie an diesem Beispiel zu erkennen ist, muss der PowerShell-User nur das Objekt abholen und dann auf die Benachrichtigung warten, dass das Objekt nicht mehr existiert.

A.2.6 Beispiel: Prüfen auf Pre-Release-Binärcode Nehmen wir mal an dass Sie feststellen wollen, welche Prozesse als Pre-Release Code kompiliert wurden. Diese Informationen sind in einer standardmäßigen Unix-Exe nicht enthalten, sodass Sie einige spezielle Tools benötigen um diese Informationen zum Binärcode hinzuzufügen und um auf diese Informationen zuzugreifen. Da diese Tools nicht existieren ist es nicht möglich, diese Aufgabe zu erfüllen. Allerdings sind diese Informationen Bestandteil des standardmäßigen WindowsDateiformats. Die folgende Lösung zeigt wie PowerShell herausfindet, welche der auf dem System laufenden Prozesse als Pre-Release-Binärdateien markiert sind: PS C:\> get-process | where { >> $_.mainmodule.FileVersioninfo.isPreRelease} >> Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) ------- -------------- ----- -----643 88 1024 1544 15 14.06 453 15 25280 7268 199 91.70

Id -1700 3952

ProcessName ----------AdtAgent devenv

544

A PowerShell im Vergleich mit anderen Sprachen

In diesem Beispiel schachteln wir die Properties. Die entsprechende Property des Prozessobjekts (MainModule) wird untersucht, die Property FileVersionInfo wird referenziert (eine Eigenschaft von MainModule) und dann wird der Wert der Property IsPreRelease benutzt um die Ergebnisse zu filtern. Falls IsPreRelease den Wert True hat werden die Objekte durch das Get-ProcessCommandlet ausgegeben.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

A.2.7 Beispiel: Einen String in Großbuchstaben verwandeln Die Verfügbarkeit der Objektmethoden eröffnet eine Vielfalt von Möglichkeiten. Wenn wir zum Beispiel die Schreibweise eines Strings so ändern wollen, dass dieser nur Großbuchstaben enthält, würden wir bei einer UNIX Shell wie folgt verfahren: $ echo "this is a string" | tr [:lower:] [:upper:]

oder $ echo "this is a string" | tr '[a-z]' '[A-Z]'

Nun wollen wir dasselbe in PowerShell realisieren: PS C:\> "this is a string".ToUpper()

Hier können wir die ToUpper()-Methode eines String-Objekts verwenden, statt einen externen Befehl wie tr benutzen zu müssen.

A.2.8 Beispiel: Text in einen String einfügen Nun wollen wir uns ein anderes Beispiel anschauen in welchem wir Methoden benutzen. Nehmen wir mal an, wir wollen den String "ABC" nach dem ersten Zeichen des Worts "String" einfügen, sodass als Ergebnis der String "sABCtring" entsteht. In einer Unix Shell wäre dazu der sed-Befehl erforderlich: $ echo "string" | sed "s|\(.\)\(.*)|\1ABC\2|"

Dieselbe Vorgehensweise – reguläre Ausdrücke – wäre auch in PowerShell möglich: PS C:\> "string" -replace '(.)(.*)','$1ABC$2' sABCtring

Wir könnten aber auch die insert-Methode des Stringobjekts verwenden, um die gleiche Aufgabe zu erfüllen (diesmal allerdings viel direkter): PS C:\> "string".Insert(1,"ABC") sABCtring

Während die ersten beiden Lösungen spezielles Wissen über reguläre Ausdrücke erfordern, ist die Verwendung der Insert()-Methode wesentlich intuitiver.

A.3 PowerShell und Pearl

545

A.3 PowerShell und Perl Wenn Sie mit Perl klarkommen dann dürfte auch PowerShell für Sie kein Problem sein. Es gibt aber einige Dinge, auf die Perl-Programmierer besonders achten müssen, die ersten beiden davon treffen ebenso auf die meisten anderen Programmiersprachen zu: ■ Funktionen werden in PowerShell so wie Befehle aufgerufen. Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

■ Das Ergebnis einer Anweisung ist standardmäßig nicht leer. Mehr dazu erfahren Sie im folgenden Abschnitt über C# und in Kapitel 7 (Funktionen und Skripte). Einige Sachen sind natürlich sehr Perl-spezifisch. Dort wo Perl verschiedene Kürzel für verschiedene Variablentypen verwendet ($ für skalar, @ für Array und % für Hashtabellen), benutzt PowerShell für alle Datentypen nur das Dollarsymbol. Weil PowerShell auf .NET basiert, muss es mit sehr viel mehr Datentypen als Perl zurechtkommen, sodass es nicht möglich ist, für jeden Typ ein eigenes Kürzel zu verwenden. Ein anderer bedeutender Unterschied bezieht sich auf Arrays, diese werden an Funktionen automatisch per Referenz übergeben. Wenn Sie eine Variable haben die drei Objekte enthält und übergeben diese an eine Funktion, wird sie als einzelnes Argument übergeben, welches die Referenz auf das Array enthält. Ein Beispiel soll das demonstrieren. BEISPIEL: Wir definieren eine Funktion die drei Argumente entgegennimmt: PS C:\> function foo ($a,$b,$c) { "a=$a`nb=$b`nc=$c" }

Nun rufen wir die Funktion mit den Argumenten 1, 2 und 3 auf: PS C:\> foo 1 2 3 a=1 b=2 c=3

Jedes Argument wird wie erwartet ausgegeben. Jetzt definieren wir ein Array, welches die Zahlen 1,2,3 enthält und übergeben es der Funktion: PS C:\> $a = 1,2,3 PS C:\> foo $a a=1 2 3 b= c=

Dieses Mal landen die drei Werte alle in $a, weil das Array als Einzelargument per Referenz übergeben wird, anstatt die einzelnen Werte als einzelne Argumente zu übergeben. Schließlich noch eine allgemeine Frage, wie sie häufig von Perl-Usern gestellt wird: Gibt es in PowerShell ein Äquivalent für die map-Operation? Die Antwort lautet "im Prinzip ja". Das Foreach- Object-Commandlet (oder dessen Alias %) ist im Wesentlichen das Äquivalent zu Perls map. Die map-Operation von Perl sieht folgendermaßen aus: map

546

A PowerShell im Vergleich mit anderen Sprachen

Das Äquivalent in PowerShell: | foreach

In der Praxis ist das Foreach-Object-Commandlet leistungsfähiger als map, weil es zusätzlich das Initialisieren und Komplettieren von Blöcken erlaubt:

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

$list | foreach {begin code…} {process code…} {end code…}

Da es sich um eine eine Pipeline-Operation handelt, kann es einfacher kombiniert werden als der map-Operator. BEISPIEL: Es werden die Commandlets ermittelt die über keinen Alias verfügen: gal | %{$ac = @{}} {$ac[$_.definition] = $true} { gcm | ?{! $ac[$_.name]}}

In der begin-Klausel wird eine Hashtable in $ac initialisiert, dann werden für jeden Alias, der durch gal zurückgegeben wird, die Definition als Schlüssel der Hashtable verwendet und ihr Wert auf True gesetzt. Schließlich wird in der end-Klausel das where-object-Commandlet (dessen Alias ist ?) verwendet um den Output von gcm so zu filtern, dass nur die Befehle, die über keine Einträge in der Hashtable verfügen, ausgegeben werden.

A.4 PowerShell und C# PowerShell ist syntaktisch ziemlich ähnlich zu C#. So sind zum Beispiel die Anweisungen zur Flusskontrolle in PowerShell meistens dieselben wie in C# (außer dass in PowerShell die Groß-/ Kleinschreibung keine Rolle spielt). Jedoch gibt es eine Reihe allgemeiner Probleme, die C#-User in Betracht ziehen müssen wenn sie mit PowerShell beginnen. Diese Probleme kommen daher, dass PowerShell eine Shell-ähnliche Semantik hat. Ausführlich wurde darüber im Kapitel 11 berichtet, wir aber wollen das hier nochmals in konzentrierter Form wiederholen.

A.4.1 Aufruf von Funktionen und Befehlen PowerShell-Funktionen sind Befehle und werden demzufolge auch wie Befehle und nicht wie Methoden aufgerufen. BEISPIEL: Eine Funktion my-command mit drei Argumenten wird so aufgerufen: my-command 1 2 3

und nicht so: my-command(1,2,3)

Die letzte Befehlszeile ruft den Befehl mit einem einzelnen Argument auf (ein Array mit drei Werten) und nicht mit drei separaten Argumenten.

A.4 PowerShell und C#

547

A.4.2 Methodenaufrufe Methoden werden in PowerShell so wie in C# aufgerufen, allerdings sind keine Zwischenräume zwischen dem Namen der Methode und den öffnenden Klammern für die Argumente erlaubt. BEISPIEL: Der PowerShell-Ausdruck

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

$data.method($a1, $a2)

ist gültig, aber der folgende Ausdruck $data.method ($a1, $a2)

endet mit einem Syntaxfehler. Auch Leerzeichen um den Punkt (.) zwischen Ausdruck und Methodenname sind nicht erlaubt. Diese Restriktionen ergeben sich aus den Besonderheiten beim Parsen von Ausdrücken und Befehlsparametern in PowerShell. Weil Befehlsparameter durch Leerzeichen voneinander getrennt sind, würden Leerzeichen bei Methodenaufrufen Konflikte verursachen (siehe Kapitel 2).

A.4.3 Rückgabe von Werten PowerShell unterstützt mehrfache implizite Rückgabewerte einer Funktion. Unter implizit verstehen wir, dass Werte direkt von einer Funktion ausgegeben werden können, ohne dafür das returnStatement verwenden zu müssen. BEISPIEL: Die Funktion function foo { 13 }

gibt die Zahl 13 zurück. Die Funktion function bar ( 10; 11; 12 }

gibt hingegen drei Werte zurück: 10, 11 und 12. In einer Programmiersprache erscheint ein solches Verhalten merkwürdig, in einer Shell macht es aber durchaus einen Sinn (der Name "PowerShell" hat seinen Grund!). Wir können nämlich unseren Code stark vereinfachen wenn eine Funktion eine Auflistung zurückgeben soll, denn wir brauchen dann keine einzelnen Werte zwischenzuspeichern, denn das System kümmert sich darum. Eine Folge davon ist, dass der standardmäßige Rückgabewert einer Anweisung nicht leer ist. Das bedeutet, dass wir einen nicht benötigten Rückgabewert einer Funktion explizit verwerfen müssen, entweder durch Umwandlung nach [void] oder Outputumleitung nach $null. Das Addieren eines Wertes zu einer ArrayList liefert beispielsweise eine Zahl zurück die der Anzahl der Elemente der Auflistung entspricht. Ausführlich wird das Verhalten von PowerShell-Funktionen im Kapitel 7 beschrieben.

548

A PowerShell im Vergleich mit anderen Sprachen

A.4.4 Sichtbarkeit von Variablen

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Im Unterschied zu den meisten anderen Programmiersprachen verfügt PowerShell über dynamisches Scoping. Das bedeutet, dass die Variablen in der aufrufenden Funktion auch in der aufgerufenen Funktion sichtbar sind. Variablen werden bei ihrem ersten Aufruf erzeugt und verschwinden wieder wenn sie den Gültigkeitsbereich verlassen. Mit Scope-Modifizierern können Sie Variablen in anderen Gültigkeitsbereichen explizit ändern, falls dies erforderlich sein sollte. Obwohl PowerShell das Typisieren von Variablen nicht verlangt ist es möglich, Typbeschränkungen hinzuzufügen. Die dafür erforderliche Semantik ist allerdings nicht dieselbe wie in C#. In PowerShell akzeptiert eine typbeschränkte Variable jeden Wert der in ihren Typ konvertiert werden kann. In C# hingegen müssen Typ bzw. Untertyp auf beiden Seiten exakt übereinstimmen.

A.5 PowerShell und VBScript Während cmd.exe die traditionelle Windows-Shell ist, wurde aus VBScript das Standard-SkriptingTool für Windows. Lassen Sie uns deshalb einige Aspekte beleuchten, die ein VBScript-User wissen sollte, wenn er mit PowerShell arbeitet. Die Syntax von PowerShell hat mit VBScript nur wenig gemeinsam, was vor allem an der Wortfülle von VBScript liegt. Weil PowerShell hauptsächlich als interaktive Shell verwendet wird, haben sich die Entwickler für eine knappe, C-ähnliche Syntax entschieden. (Die Tatsache, dass beide Sprachen so unterschiedlich sind, ist für den VBScript-User hilfreich, kommt er doch so kaum in die Versuchung beide Sprachen miteinander zu vermischen.) HINWEIS: Die meisten der in Abschnitt A.4 diskutierten Probleme treffen auch auf VBScript zu

(und auch auf die meisten anderen Programmiersprachen). Der vorliegende Abschnitt enthält Material welches besonders auf VBScript zutrifft. Da sich in VBScript das Schreiben von Verwaltungs-Skripten hauptsächlich auf COM und WMI Objekte bezieht, ist es für den VBScript-User wichtig zu wissen, was es für Äquivalente zum Erzeugen von COM-Objekten mittels CreateObject() und für den Zugriff auf Instanzen von WMIObjekten mittels GetObject() gibt. In PowerShell erzeugen Sie ein COM-Objekt mit dem NewObject Befehl: $ie = New-Object –com InternetExplorer.Application

Ein WMI Objekt erhalten Sie mit dem Get-WmiObject-Commandlet: $tz = Get-WMIObject win32_timezone

Kapitel 12 behandelt dieses Thema im Detail. Dieses Kapitel enthält auch einen konkreten Vergleich zwischen einem in VBScript und einem in PowerShell geschriebenen Skript. Obwohl wir damit bereits die wichtigsten Umstiegsprobleme eines VBScript-Users besprochen haben, gibt es noch eine ganze Reihe weiterer Einzelheiten die man wissen sollte: ■ Variablen beginnen immer mit einem "$" wie z.B. $a.

A.5 PowerShell und VBScript

549

■ Methodenaufrufe müssen immer die Klammern an den Methodennamen anfügen, denn ein Objekt kann zum Beispiel sowohl eine Eigenschaft SomeName und eine Methode SomeName() haben. ■ Der Versuch, nicht vorhandene Objekteigenschaften zu lesen, verursacht keinen Fehler.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

■ Das "Set"-Schlüsselwort für das Zuweisen von Objekteigenschaften gibt es nicht. ■ Strings können in PowerShell entweder mit einfachen oder mit doppelten Anführungszeichen begrenzt werden. Innerhalb doppelter Anführungszeichen werden Steuersequenzen und Variablenreferenzen expandiert (siehe Kapitel 3 für ausführliche Informationen). ■ PowerShell verwendet völlig andere Vergleichsoperatoren: -lt anstatt "" für "größer als" usw. (siehe Kapitel 4 für mehr Informationen). Vergleiche in PowerShell sind standardmäßig unabhängig von der Groß-/Kleinschreibung). ■ Arrays werden unter Verwendung eckiger statt runder Klammern indiziert. Das Zuweisen eines Array-Elements sieht so aus: $a[2] = "Hello"

■ Der Plus (+)-Operator wird für das Zusammenfügen von Strings und Arrays benutzt. Der Typ des linken Arguments bestimmt den Konvertierungstyp (siehe Kapitel 7 für mehr Details). ■ Die PowerShell-Syntax ist sehr ähnlich zu der von C. Anweisungsblöcke werden mit geschweiften Klammern anstatt mit Schlüsselwörtern begrenzt "{" und "}". In PowerShell würden wir zum Beispiel schreiben if ($false -neq $true) { "false is not true "}

anstatt in VBScript If (False True) Then MsgBox "false is not true" End If

■ Mehrfachanweisungen innerhalb einer Zeile werden in PowerShell mittels Semikolon ";" anstatt in VBScript durch Doppelpunkt ":" voneinander getrennt. ■ Wie auch in VBScript ist bei syntaktisch korrekter Anweisung am Ende der Zeile kein Abschluss erforderlich. Wenn jedoch ein PowerShell-Statement nicht komplett ist, kann es sich über mehrere Zeilen ausbreiten ohne explizit fortgesetzt zu werden. Falls eine Fortsetzung erforderlich ist, kann dies durch einen einzelnen Backtick "`" am Zeilenende erreicht werden. Beachten Sie, dass ein Backtick (`) nicht dasselbe ist wie ein einfaches Anführungszeichen bzw. Apostroph ('). ■ Obwohl PowerShell über kein exaktes Äquivalent zu Option Explicit (eine Variable muss vor ihrer Verwendung deklariert werden) verfügt, gibt es ein Feature welches das Initialisieren von Variablen vor ihrer Benutzung verlangt. Dieses Features wird mit folgendem Befehl eingeschaltet: set-psdebug –strict

550

A PowerShell im Vergleich mit anderen Sprachen

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

■ Jeder Ausdruck, der in einer Funktion einen Wert zurückgibt, wird zum Bestandteil des Rückgabewerts. Ein Zuweisen zum Namen der Funktion ist nicht notwendig (allerdings gibt es in PowerShell auch ein return-Statement, es ist nur dann erforderlich, wenn Sie die Reihenfolge der Ausführung der Anweisungen innerhalb einer Funktion ändern wollen, um die Funktion früher zu verlassen.) In VBScript können wir zum Beispiel schreiben: Function GetHello GetHello = "Hello" End Function

■ Das PowerShell Äquivalent ist einfacher: function Get-Hello { "Hello" }

■ Das nächstliegende Äquivalent zum on error-Konstrukt in VB ist das trap-Statement in PowerShell (siehe Kapitel 9). Trotz all dieser Unterschiede ist es mitunter erstaunlich, wie leicht sich ein Skript aus VBScript nach PowerShell übersetzen lässt. Das liegt vor allem daran, dass wir in vielen Fällen mit denselben WMI- oder COM-Objekten arbeiten. Natürlich werden einige Dinge völlig anders gelöst – zum Beispiel die Stringverarbeitung. Schauen Sie sich dazu die Beispiele in Abschnitt 12.2.4 an, dort wird auch demonstriert, wie einfach man ein kleines Skript von VBScript nach PowerShell übersetzen kann. Trotzdem, auch wenn die Übersetzung einfach ist, kann man dabei nur selten die Vorteile nutzen, die PowerShell bezüglich des Schreibens kurzer und knapper Skripte bietet. Schließlich sei noch darauf hingewiesen, dass man unter Verwendung des ScriptControl COM Objekts komplette VBScript-Fragmente in ein PowerShell Skript einbetten kann.

B

Beispiele zum Administrieren

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Anhang

B

Beispiele zum Administrieren Obwohl dieses Buch kein Kochbuch ist, kann es nicht schaden, wenn wir noch ein paar konkrete Anwendungen als Zugabe präsentieren. Dieser Abschnitt enthält deshalb eine Anzahl kurzer Beispiele die zeigen, wie man einfache administrative Aufgaben mit PowerShell bewältigen kann.

B.1 Active Directory-Infos abrufen Das folgende Skript zeigt für eine Liste von Computern die Active Directory-Informationen an. Falls keine Computernamen zur Verfügung stehen, werden die Domänen-Infos für den aktuellen Computer ausgegeben. Optional können Sie eine Reihe von Eigenschaften festlegen, die zurückgegeben werden sollen. Den Code dieses Skripts zeigt Listing B.1. BEISPIEL: Um die Domäneninformation für den aktuellen Host zu erhalten verwenden Sie: Get-DomainInfo

oder Get-DomainInfo

BEISPIEL: Um die Domäneninfo für mehrere Computer zu erhalten: Get-DomainInfo machine1, machine2, machine3

BEISPIEL: Für eine Liste von Computern, die in einer Textdatei gespeichert sind: Get-Content machines.txt | Get-DomainInfo

BEISPIEL: Um nur den Domänennamen und den Domänen-Controler des aktuellen Computers zu erhalten: Get-DomainInfo –Properties DomainName, DomainControllerName

Listing B.1: Get-DomainInfo-Skript param( [string[]] $ComputerNames = @(), [string[]] $Properties = @() )

552

B Beispiele zum Administrieren

$ComputerNames += @($input)

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

if (! $ComputerNames) { $ComputerNames = "." } if ($Properties.Length -eq 0) { Get-WmiObject -Class Win32_NTDomain ` -ComputerName $ComputerNames } else { Get-WmiObject -Class Win32_NTDomain ` -ComputerName $ComputerNames | select-object $properties }

Ùq Informationen abrufen

Ùw Eigenschaften auslesen

Das Skript benutzt dasGet-WmiObject-Commandlet q um die Informationen einer Liste von Computern zu lesen und zurückzugeben. Wenn die Optionsliste der Eigenschaften spezifiziert ist, dann wird das Select-Object-Commandlet w verwendet, um die Properties aus der Ergebnismenge zu extrahieren.

B.2 Installierte Software anzeigen Dieses Skript zeigt eine Liste aller Software-Features an, die auf einer Reihe von Computern installiert sind. Optional können Sie eine Liste mit Eigenschaften festlegen, die zurückgegeben werden sollen (standardmäßig werden alle Eigenschaften zurückgegeben). Der Code des Skripts wird in Listing B.2 dargestellt. BEISPIEL: Um alle Eigenschaften des aktuellen Computers zu erhalten genügt einfach: Get-SoftwareFeatures

BEISPIEL: Um die Software-Features einer Liste von Computern zu gewinnen, können Sie einfach Folgendes

an der Befehlszeile eingeben: Get-SoftwareFeatures machine1, machine2, machine2

Oder Sie geben es von der Pipeline ein: get-content machines.txt | Get-SoftwareFeatures

Sie können ebenfalls eine Untermenge von Eigenschaften festlegen, die angezeigt werden sollen. BEISPIEL: Nur die Felder Vendor und Caption werden angezeigt: Get-SoftwareFeatures –properties Vendor, Caption

553

B.3 Terminal Server-Einstellungen bestimmen

Listing B.2: Skript Get-SoftwareFeatures.ps1 param( [string[]] $ComputerNames = @(), [string[]] $Properties = @() )

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

$ComputerNames += @($input) if (! $ComputerNames) { $ComputerNames = "." } if ($Properties.Length -eq 0) { Get-WmiObject -Class Win32_SoftwareFeature ` -ComputerName $ComputerNames } else { Get-WmiObject -Class Win32_SoftwareFeature ` -ComputerName $ComputerNames | select-object $properties }

Ùq Informationen abrufen

Ùw Eigenschaften auslesen

Wie auch im vorhergehenden Beispiel wird Get-WmiObject verwendet, um die gewünschten Informationen abzurufen q und zu filtern w.

B.3 Terminal Server-Einstellungen bestimmen Die Einstellungen des Terminal Servers können mit einer einfachen WMI-Abfrage ermittelt werden. BEISPIEL: Um alle Eigenschaften des Terminal Server-Dienstes des aktuellen Computers aufzulisten, verwen-

den Sie folgende Anweisung: get-wmiobject -class Win32_TerminalService –computername .

BEISPIEL: Um die Terminal Dienste-Konten aufzulisten, verwenden Sie das Win32_TSAccount-Objekt wie

folgt: get-wmiobject -class Win32_TSAccount –computername . | select AccountName, PermisionsAllowed

BEISPIEL: Um die Remote Control-Einstellung der Terminal Dienste eines Computers zu erhalten: get-wmiobject Win32_TSRemoteControlSetting | select-object TerminalName, LevelOfControl

554

B Beispiele zum Administrieren

In diesem Beispiel haben wir vom positionellen Charakter des Class-Parameters Gebrauch gemacht, sodass wir -class nicht spezifizieren mussten. Wir haben den Default-Namen für ComputerName mit "." bezeichnet – das ist der aktuelle Computer. Um eine Liste aller WMI Klassen zum Verwalten von Terminaldiensten anzuzeigen, verwenden Sie folgende Anweisung:

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

PS C:\> get-wmiobject -list | >> where {$_.name -like "win32_ts*"} | select name >> Name ---Win32_TSNetworkAdapterSettingError Win32_TSRemoteControlSettingError Win32_TSEnvironmentSettingError Win32_TSSessionDirectoryError Win32_TSLogonSettingError Win32_TSPermissionsSettingError Win32_TSClientSettingError Win32_TSGeneralSettingError Win32_TSSessionSettingError Win32_TSSessionDirectory Win32_TSRemoteControlSetting Win32_TSNetworkAdapterSetting Win32_TSAccount Win32_TSGeneralSetting Win32_TSPermissionsSetting Win32_TSClientSetting Win32_TSEnvironmentSetting Win32_TSNetworkAdapterListSetting Win32_TSLogonSetting Win32_TSSessionSetting Win32_TSSessionDirectorySetting

Dieser Befehl durchsucht alle WMI Klassen nach solchen deren Namen mit "Win32_TS" beginnt.

B.4 Auflisten aller Hotfixes des aktuellen Computers Das folgende Skript listet alle Hotfixes auf, die auf einer Liste von Computern installiert sind. Stehen keine Computernamen zur Verfügung, werden die Hotfix Informationen für den aktuellen Computer ermittelt. Optional können wir die Properties spezifizieren, die zurückgegeben werden sollen. Den Code für dieses Skript zeigt Listing B.3. BEISPIEL: Die Eigenschaften aller Hotfixes, die auf dem aktuellen Computer installiert sind, werden ange-

zeigt: Get-HotFixes

B.5 Computer mit fehlenden Hotfixes suchen

555

BEISPIEL: Sie wollen nur bestimmte Properties sehen: Get-HotFixes -prop ServicePackInEffect,Description

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Listing B.3: Skript Get-HotFixes.ps1 param( [string[]] $ComputerNames = @(), [string[]] $Properties = @() ) $ComputerNames += @($input) if (! $ComputerNames) { $ComputerNames = "." } if ($Properties.Length -eq 0) { Get-WmiObject -Class Win32_QuickFixEngineering ` -ComputerName $ComputerNames } else { Get-WmiObject -Class Win32_QuickFixEngineering ` -ComputerName $ComputerNames | select-object $properties }

Spätestens an dieser Stelle sehen wir, dass es für alle Beispiele gute konsistente Lösungen gibt. Kennen wir einmal die WMI-Klasse für ein bestimmtes Feature, so ist die Vorgehensweise zur Informationsgewinnung grundsätzlich immer dieselbe. PowerShell erleichtert die Benutzung der WMI an der Befehlszeile, um Informationen über das System zu erhalten sobald Sie den Namen der Klasse wissen.

B.5 Computer mit fehlenden Hotfixes suchen Wir wollen das Skript des Vorgängerbeispiels weiter ausbauen um eine speziellere Aufgabe auszuführen. Das neue Skript (siehe Listing B.4) soll alle Computer ermitteln bei denen Hotfixes fehlen. Der Output soll folgendermaßen aussehen: PS C:\> ./Get-MachinesMissingHotfix.ps1 –computer . ` >> -hotfix KB902841,KB902842,KB902843,KB902844 >> Name Value -------name . missing {KB902842, KB902843, KB902844}

556

B Beispiele zum Administrieren

Das Ergebnis des Befehls zeigt, dass drei von vier Hotfixes noch nicht auf dem aktuellen Computer installiert sind. HINWEIS: Einige dieser Hotfix IDs sind fiktiv, sodass wir damit ein paar Fehler simulieren kön-

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

nen. Machen Sie sich also keine Sorgen, wenn Sie diese in der Knowledge Base nicht finden. Beachten Sie die Struktur des Outputs. Statt Strings werden Hashtabellen ausgegeben, weil diese in späteren Prozessen einfacher verwendet werden können, z.B. für Aktualisierungspakete. Da wir auch gleichzeitig mehrere Computer überprüfen wollen, kann das Skript diese Liste entweder an der Befehlszeile entgegennehmen oder sie vom Inputstream lesen (siehe nächstes Beispiel) BEISPIEL: Die Datei "machines.txt" enthält eine Liste von zu überprüfenden Computern ("machine1" ...

"machine5"). PS C:\> Get-Content machines.txt|./Get-MachinesMissingHotfix.ps1 ` >> -hotfix KB902841,KB902842,KB902843,KB902844 >> Name ---name missing name missing name missing

Value ----machine1 {KB902842, KB902843, KB902844} machine4 {KB902842, KB902843, KB902844} machine5 {KB902841,KB902842, KB902843, KB902844}

Am Output erkennen wir, dass die Computer 2 und 3 auf dem neuesten Stand sind – sie erscheinen deshalb nicht im Output. Bei den Computern 1 und 4 fehlen drei Hotfixes und bei Computer 5 fehlen alle vier. Listing B.4: Skript Get-MachinesMissingHotfix.ps1 param( [string[]] $ComputerName = @(), [string[]] $HotFix = $(throw "you must specify a hotfix id") ) $ComputerName += @($input) if (! $ComputerName) { $ComputerName = "." }

Ùq Entgegennahme der Computerliste

$myDir = split-path $MyInvocation.MyCommand.Definition Ùw Pfad zu Get-HotFixes-Script suchen $gh = join-path $myDir Get-HotFixes.ps1

557

B.5 Computer mit fehlenden Hotfixes suchen

foreach ($name in $ComputerName) { $sps = & $gh $name | foreach { $_.ServicePackInEffect}

Ùe Hot Fix-Liste für Computer abrufen

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

$result = @{name = $name; missing = @() } foreach ($hf in $HotFix) { if ($sps -notcontains $hf) { $result.missing += $hf } } if ($result.missing.length -gt 0) { $result }

Ùr Ergebnistabelle initialisieren

Ùt Fehlendes Hot Fix hinzufügen

Ùy Ergebnis zurückgeben

}

Dass Skript nimmt zwei Parameter entgegen – die Namensliste der zu überprüfenden Computer und die Liste der Hotfixes nach denen gesucht werden soll. Werden keine Computernamen angegeben, so wird der aktuelle Computer durchsucht. Wir können Computernamen sowohl an der Befehlszeile als auch im Inputstream eingeben. Beide Listen werden miteinander verkettet q. Wir erwarten, dass sich das Get-HotFixes-Skript im gleichen Verzeichnis befindet wie das aktuelle Skript. Wenn das der Fall ist, dann können wir den Pfad w zum Get-HotFixes-Skript herausfinden, indem wir den in $MyInvocation enthaltenen Pfad nehmen. (Das ist ganz allgemein eine sehr nützliche Technik, die Sie sich auch für andere Skripte merken sollten.) Haben wir den Pfad zum Get-HotFixes-Befehl so benutzen wir ihn, um die Liste der Hotfixes zu ermitteln e. Da wir aber nur am ServicePackInEffect-Feld interessiert sind, verwenden wir das foreach-Commandlet um diese Property zu extrahieren. Wir initialisieren die Variable $result als Hashtable-Objekt mit dem Namen des aktuellen Computers und setzen die Liste der fehlenden Hotfixes auf ein leeres Array r. Wenn kein Hotfix fehlt, wird dieses Objekt nicht zurückgegeben! Wir überprüfen deshalb ob die Länge der fehlenden Member in der Hashtabelle 0 ist. Nun iterieren wir durch die Liste der Hotfixe und prüfen, ob jeder davon in der auf der Zielmaschine installierten Liste enthalten ist. Wenn die Liste der installierten Hotfixe die aktuelle Hotfix-ID nicht enthält, wird die ID dem Array t in der resultierenden Hashtabelle hinzugefügt. Nachdem schließlich alle Hotfixe geprüft sind und das Array in der Hashtabelle immer noch die Länge null hat, dann sind alle Hotfixe auf dem Computer installiert. Ist das Array ungleich null, dann wird das $result-Objekt ausgegeben y.

558

B Beispiele zum Administrieren

B.6 Ereignisprotokoll verwenden Eine sehr ergiebige Informationsquelle für den Administrator ist das Ereignisprotokoll. PowerShell hat ein Commandlet, welches sich ausschließlich damit beschäftigt: Get-EventLog. Abbildung B.1 zeigt die Syntax.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

das abzurufende Ereignisprotokoll die Anzahl der zurückzugebenden letzten Ereignisse

Name des Commandlets

Get-EventLog [-LogName] [-Newest get-eventlog -list Max(K) Retain OverflowAction ------ ------ -------------512 7 OverwriteOlder 512 7 OverwriteOlder 512 7 OverwriteOlder 15,360 0 OverwriteAsNeeded 512 7 OverwriteOlder 512 7 OverwriteOlder

Entries ------48 2,895 0 80 1 2,105

Name ---ACEEventLog Application Internet E... PowerShell Security System

Am Output dieses Beispiels erkennen Sie, dass in diesem System mehrere Protokolle (Logs) verfügbar sind.

559

B.6 Ereignisprotokoll verwenden

B.6.1 Ein spezifisches EventLog-Objekt ermitteln Wir wollen das Log-Objekt für das Ereignisprotokoll von PowerShell ermitteln (siehe Kapitel 9 für mehr Informationen über Fehler und Ereignisse in PowerShell).

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

PS C:\> $log = get-eventlog -list | >> ? { $_.logdisplayname -like "Win*Pow*" } >>

Wir prüfen, ob wir das richtige Protokoll erhalten haben: PS C:\> $log.LogDisplayName Windows PowerShell

Nun wollen wir die fünf neuesten Ereignisse im Log betrachten: PS C:\> get-eventlog $log.LogDisplayName -newest 5 Index ----208 207 206 205 204

Time ---Jun 12 Jun 12 Jun 12 Jun 12 Jun 12

11:00 11:00 11:00 11:00 11:00

Type ---Info Info Info Info Info

Source -----PowerShell PowerShell PowerShell PowerShell PowerShell

EventID ------400 600 600 600 600

Message ------Der Modulzustand wird von "None... Der Anbieter "Certificate" ist ... Der Anbieter "Variable" ist Sta... Der Anbieter "Registry" ist Sta... Der Anbieter "Function" ist Sta...

Aber was ist mit dem Protokoll selbst? BEISPIEL: Wir ermitteln die maximale Größe des Protokolls: PS C:\> $log.MaximumKilobytes 64

Das Protokoll auf diesem Computer ist auf 64K gesetzt. Lassen Sie uns die Größe verdoppeln: PS C:\> $log.MaximumKilobytes *= 2 PS C:\> $log.MaximumKilobytes 128

Wie wir sehen können, ist diese Art von Manipulation ziemlich einfach.

B.6.2 Das Ereignisprotokoll als Live-Objekt Das EventLog-Objekt ist ein Live-Objekt. Das bedeutet, wenn wir das Objekt einmal haben dann können wir es ständig auf Aktualisierungen prüfen und feststellen, was sich geändert hat. BEISPIEL: Wir betrachten das PowerShell-Protokoll in $log. PS C:\> $log Max(K) Retain OverflowAction ------ ------ -------------15.360 0 OverwriteAsNeeded

Entries Name ------- ---208 Windows PowerShell

560

B Beispiele zum Administrieren

Aktuell werden 208 Einträge angezeigt. Nun wollen wir einige zusätzliche PowerShell-Instanzen starten, die weitere Einträge im Protokoll erzeugen. Wir übergeben dabei den exit-Befehl, sodass jede neue Instanz sofort wieder verschwindet. PS C:\> powershell exit PS C:\> powershell exit PS C:\> powershell exit Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Nun prüfen wir das Protokoll erneut: PS C:\> $log Max(K) Retain OverflowAction ------ ------ -------------15.360 0 OverwriteAsNeeded

Entries Name ------- ---256 Windows PowerShell

Wir sehen, dass das Protokoll mit den neuen Einträgen aktualisiert wurde. Nun wollen wir das Protokoll löschen. Wir tun dies mit einer separaten Instanz von PowerShell, damit wir weiterhin die "Live"-Natur des EventLog Objekts demonstrieren können. Hier der entsprechende Befehl: PS >> >> >> >>

C:\> powershell { (get-eventlog -list | ?{$_.LogDisplayName -like "Win*Pow*"}).Clear() }

Dieser Befehl übergibt einen Skriptblock an einen neuen PowerShell Prozess. Dieser Skriptblock enthält Code für den Zugriff auf das PowerShell EventLog Objekt und ruft dessen Clear()Methode auf. Wenn der Child-Prozess mit der Befehlsausführung fertig ist, prüfen wir wieder das aktuelle Protokoll: PS C:\> $log Max(K) Retain OverflowAction ------ ------ -------------15.360 0 OverwriteAsNeeded

Entries Name ------- ---8 Windows PowerShell

Wir sehen, dass der Inhalt des Protokolls gelöscht wurde.

B.6.3 Remote-Zugriff auf Ereignisprotokolle Ein Feature, das man beim Get-EventLog-Commandlet deutlich vermisst, ist der Zugriff auf die Ereignisprotokolle anderer Computer. Glücklicherweise lässt sich hier leicht Abhilfe schaffen, indem man das EventLog-Objekt direkt erzeugt. BEISPIEL: Zugriff auf das Event-Log des Computers "test1": PS C:\> $pslog = new-object System.Diagnostics.EventLog ( >> "Windows PowerShell", "test1") >>

561

B.6 Ereignisprotokoll verwenden

Da wir nun eine Instanz des EventLog Objekts haben, können wir auf die Einträge im Protokoll so zugreifen, als würde es sich um ein lokales Protokoll handeln. BEISPIEL: Anzeige der ersten sechs Einträge im obigen Protokoll:

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

PS C:\> $pslog.Entries[0..5] Index ----1 2 3 4 5 6

Time ---Jun 12 Jun 12 Jun 12 Jun 12 Jun 12 Jun 12

11:06 11:06 11:06 11:06 11:06 11:06

Type ---Info Info Info Info Info Info

Source -----PowerShell PowerShell PowerShell PowerShell PowerShell PowerShell

EventID ------601 601 601 601 601 601

Message ------Der Anbieter Der Anbieter Der Anbieter Der Anbieter Der Anbieter Der Anbieter

"Alias" ist Stoppe... "Environment" ist ... "FileSystem" ist S... "Function" ist Sto... "Registry" ist Sto... "Variable" ist Sto...

BEISPIEL: Wir wollen die letzten sechs Einträge mit dem select-Befehl ermitteln. Das sind die häufigsten Ein-

träge im Protokoll: PS C:\> $pslog.Entries | select -last 6 Index ----3 4 5 6 7 8

Time ---Jun 12 Jun 12 Jun 12 Jun 12 Jun 12 Jun 12

11:06 11:06 11:06 11:06 11:06 11:06

Type ---Info Info Info Info Info Info

Source -----PowerShell PowerShell PowerShell PowerShell PowerShell PowerShell

EventID ------601 601 601 601 601 403

Message ------Der Anbieter "FileSystem" ist S... Der Anbieter "Function" ist Sto... Der Anbieter "Registry" ist Sto... Der Anbieter "Variable" ist Sto... Der Anbieter "Certificate" ist ... Der Modulzustand wird von "Avai...

Diese Beispiele zeigen uns, dass die Benutzung der .NET-Klassen oft nicht schwieriger sein muss als das Verwenden von Commandlets.

B.6.4 Speichern von Ereignisprotokollen Wir können das Export-CliXML-Commandlet verwenden um ein Ereignisprotokoll in einer Form zu speichern, die eine zukünftige Weiterverarbeitung erlaubt. BEISPIEL: Ereignisprotokoll speichern: PS C:\> $pslog.Entries | export-clixml c:\temp\pslog.clixml

Der Befehl zum Zurücklesen der Daten ist einfach: PS C:\> $data = import-clixml C:\temp\pslog.clixml

Wir wollen nun die Originaldaten mit den wiederhergestellten Daten vergleichen. Hier die Einträge im Log: PS C:\> $pslog.Entries[0..3] | >> ft -auto Index,Time,EventID,Message

562

B Beispiele zum Administrieren

>>

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Index Time EventID Message ----- ---- ------- ------1 601 The description for Event 2 601 The description for Event 3 601 The description for Event 4 601 The description for Event

ID ID ID ID

'601' '601' '601' '601'

in... in... in... in...

ID ID ID ID

'601' '601' '601' '601'

in... in... in... in...

Und hier die wiederhergestellten Daten: PS C:\> $data[0..3] | >> ft -auto Index,Time,EventID,Message >> Index Time EventID Message ----- ---- ------- ------1 601 The description for Event 2 601 The description for Event 3 601 The description for Event 4 601 The description for Event

Die Inhalte sind mehr oder weniger identisch. Natürlich haben die wiederhergestellten Daten eine wesentliche Besonderheit, sie kommen nicht mehr von einem Live-Objekt. Es gibt deshalb keine Methoden und das Ändern einer Eigenschaft hat keinerlei Auswirkungen auf das System.

B.6.5 Ereignisse schreiben Eine andere wichtige Sache, die wir beim Ereignisprotokoll-Support von PowerShell vermissen, ist die Fähigkeit zum Schreiben von Ereignissen. Aber auch diesmal können wir auf die Unterstützung der .NET-Klassen vertrauen. BEISPIEL: Wir fügen einige Ereignisse zum Ereignisprotokoll von PowerShell hinzu. Zunächst erzeugen wir

eine Ereignisquelle: PS C:\> [System.Diagnostics.EventLog]::CreateEventSource( >> "me", "PowerShell") >>

Danach greifen wir auf das PowerShell-Ereignisprotokoll des aktuellen Computers zu: PS C:\> $pslog = new-object System.Diagnostics.EventLog ( >> "PowerShell", ".") >>

Und setzen die Ereignisquelle dieses Objekts auf die des gerade erzeugten Objekts: PS C:\> $pslog.Source="me"

Nun verwenden wir dieses Objekt, um einen Eintrag in das Protokoll mittels WriteEntry()-Methode vorzunehmen:

563

B.7 Arbeiten mit vorhandenen Dienstprogrammen

PS C:\> $pslog.WriteEntry("Hi")

Schließlich wollen wir überprüfen, ob das Ereignis wirklich in das Protokoll geschrieben wurde: PS C:\> $pslog.Entries | select -last 8

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Index Time ----2 3 4 5 6 7 8 9

---Sep 16 Sep 16 Sep 16 Sep 16 Sep 16 Sep 16 Sep 16 Sep 16

Type Source

17:18 17:18 17:18 17:18 17:18 17:18 17:18 17:30

---Info Info Info Info Info Info Info Info

-----PowerShell PowerShell PowerShell PowerShell PowerShell PowerShell PowerShell me

EventID Mess age ------- ---601 T... 601 T... 601 T... 601 T... 601 T... 601 T... 403 T... 0 Hi

Sie können sehen, dass unser Ereignis zum Protokoll hinzugefügt wurde.

B.7 Arbeiten mit vorhandenen Dienstprogrammen Die Textausgabe eines vorhandenen Dienstprogramms lässt sich in ein Format konvertieren, welches von PowerShell besser verarbeitet werden kann. Im folgenden Beispiel wollen wir das anhand des Aufgabenplaners (schtasks.exe) demonstrieren. BEISPIEL: Zunächst betrachten wir uns die Ausgabe von schtaks.exe: PS C:\> schtasks Taskname ==================================== AppleSoftwareUpdate ClientZeit

Nächste Ausführungszeit ======================== 20:09:00, 18.06.2007 09:30:00, 13.06.2007

Dieser Output ist ein Textstream, den wir in Objekte umwandeln wollen, damit wir diese zum Beispiel sortieren können. Wir wünschen uns, dass der konvertierte Output folgendermaßen aussieht: PS C:\> get-sched TaskName -------AppleSoftwareUpd... ClientZeit

Nächste Ausführungszeit Status ----------------------- -----20:09:00, 18.06.2007:... 09:30:00, 13.06.2007...

Ich will zugeben, dass dieses Beispiel durch die beschränkten Formatierungsmöglichkeiten nicht sehr attraktiv aussieht. Viel wichtiger ist es aber, dass wir jetzt einfach nach NextRunTime sortieren können:

564

B Beispiele zum Administrieren

PS C:\> get-sched | sort NextRunTime

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

TaskName -------ClientZeit AppleSoftwareUpd...

Nächste Ausführungszeit Status ----------------------- -----09:30:00, 13.06.2007... 20:09:00, 18.06.2007:...

Listing B.5 zeigt den Quellcode. Das Skript demonstriert auf anschauliche Weise, wie man die "alte" Welt der stringbasierten Dienstprogramme in die "neue" Welt der PowerShell-Objekte überführen kann. Listing B.5: Das get-sched-Skript $null,$header,$lines,$data = schtasks /query

Ùq Daten abrufen

function Split-String ($s,[int[]] $indexes) { if (! $s ) { return } $indexes | foreach {$last=0} { [string] $s.substring($last, $_-$last) $last = $_+1 } $s.substring($last) }

Ùw Hilfsfunktion

$first,$second,$third = $lines.split(" ") | foreach { $_.length } $second+=$first $h1,$h2,$h3 = split-string $header $first, $second | foreach { $_ -replace " " }

Ùe Offset berechnen

Ùr Property-Namen abrufen

$data | foreach { $v1, [datetime] $v2, $v3 = split-string $_ $first, $second new-object psobject | add-member -pass -mem NoteProperty $h1 $v1 | add-member -pass -mem NoteProperty $h2 $v2 | add-member -pass -mem NoteProperty $h3 $v3

Ùt Daten aufsplitten

Ùy Objekte erzeugen

}

Zunächst holen wir die Daten aus dem Befehl q, sie haben folgendes Format: Leerzeile, gefolgt von Kopfzeile, Trennungslinie und Daten. Wir verwenden eine Mehrfachzuweisung um jedem dieser Abschnitte seine eigene Variable zuzuordnen (Zuweisen von null verwirft die Daten). Die Liste von Datensätzen wird $data zugewiesen. Als Nächstes definieren wir eine Hilfsfunktion w, die Strings an bestimmten Offsets in Stücke aufteilt, wir benutzen die Funktion zum Aufsplitten der Datensätze.

B.8 Arbeiten mit Active Directory und ADSI

565

Nun wollen wir herausfinden, wie breit die Felder sein müssen und zerlegen dazu die Unterstreichungslinie e. Wir zerteilen diesen String an seinen Leerzeichen, bestimmen die Länge jedes einzelnen Teilstrings und benutzen diese Längen als Offset, um die Daten für die einzelnen Felder zu gewinnen.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Dann wollen wir die Kopfzeile neu formatieren r, sodass wir als Beschriftung die Namen der Eigenschaften der zu erstellenden Objekte verwenden können. Dazu zerteilen wir die Kopfzeile und entfernen dann die Leerzeichen aus den Namen. Schließlich verwandeln wir die Datenzeilen in Objekte mit Eigenschaften. Wir zerteilen jede Datenzeile in drei Stücke und verwenden dazu die berechneten Offsets t. Dann konstruieren wir ein synthetisches Objekt und fügen unter Verwendung obiger Beschriftungen Kommentareigenschaften hinzu y. Da wir wissen, dass das zweite Feld ein DateTime Objekt ist, konvertieren wir es in ein streng typisiertes Objekt, statt nur den String zu nehmen. Das ermöglicht uns ein intelligenteres Sortieren.

B.8 Arbeiten mit Active Directory und ADSI Active Directory (AD) wurde mit Windows 2000 eingeführt und ist ein Eckpfeiler des Windows Enterprise Managements. Es handelt sich hierbei um eine hierarchische Datenbank für die Verwaltung aller Arten von Unternehmensdaten. In diesem Beispiel wollen wir uns mit dem Skripteschreiben für AD beschäftigen. HINWEIS: Alle Beispiele dieses Abschnitts haben wir unter Verwendung von ADAM (Active

Directory Application Mode) entwickelt. ADAM kann frei von Microsoft.com heruntergeladen werden und ist eine alleinstehende Active Directory Implementierung, die ohne Windows Server auskommt und auf einem Computer unter Windows XP läuft. ADAM ist ein großartiges Tool, um sich in Active Directory einzuarbeiten. Wie auch bei WMI ist der Schlüssel für PowerShells AD Support der ADSI (Active Directory Service Interface)-Objektadapter und der [ADSI]-Typ. Für unsere Beispiele haben wir eine Active Directory Installation für eine fiktive Firma "Fabrikam.com" eingerichtet. HINWEIS: Dass die erste Version von PowerShell keine Features enthält, die das Arbeiten mit

ADSI in anderen Umgebungen erleichtern, ist kein idealer Zustand. Die beste Lösung wäre ein AD-Provider, der uns das Navigieren in Active Directory auf dieselbe Weise wie im Dateisystem oder in der Registry ermöglichen würde. Also warten wir auf die nächste Version von PowerShell!

B.8.1 Zugriff auf den Active Directory-Service Auf unseren "Fabrikam" AD- Service können wir folgendermaßen zugreifen: Wir nehmen die URL des LDAP (Lightweight Directory Access Protocol) für diesen Dienst und konvertieren diese in ein ADSI Objekt:

566

B Beispiele zum Administrieren

PS C:\> $domain = [ADSI] ` >> "LDAP://localhost:389/dc=NA,dc=fabrikam,dc=com" >>

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Da wir nun mit dem Active Directory-Service verbunden sind, wollen wir eine neue organisatorische Einheit für die Personalabteilung erzeugen. Wir verwenden dazu die Create()-Methode des $domain Objekts: PS C:\> $newOU = $domain.Create("OrganizationalUnit", "ou=HR") PS C:\> $newOU.SetInfo()

Haben wir das Objekt erzeugt, müssen wir SetInfo() aufrufen um den Server zu aktualisieren.

B.8.2 Benutzer hinzufügen Um auf das Objekt zuzugreifen, welches die organisatorische Einheit repräsentiert die wir gerade erzeugt haben, verwenden wir wieder eine [ADSI]-Konvertierung, dieses Mal aber schließen wir das Element "ou=HR" mit in die URL ein. PS C:\> $ou = [ADSI] ` >> "LDAP://localhost:389/ou=HR,dc=NA,dc=fabrikam,dc=com" >>

Nun wollen wir in dieser Abteilung ein User-Objekt erzeugen und verwenden die Create()Methode von $ou, um einen neuen "User" mit dem CN (common name) "Dogbert" zu erhalten. PS C:\> $newUser = $ou.Create("user", "cn=Dogbert")

Wir wollen diesem User auch einige Eigenschaften zuweisen und verwenden dazu die Put()Methode des user-Objekts. (Die Menge von Eigenschaften, die wir setzen können, ist durch das AD-Schema des user-Objekts festgelegt.) PS PS PS PS

C:\> C:\> C:\> C:\>

$newUser.Put("title", "HR Consultant") $newUser.Put("employeeID", 1) $newUser.Put("description", "Dog") $newUser.SetInfo()

Wir setzen für diesen User die Eigenschaften title, employeeID und description und rufen anschließend SetInfo() auf, um den Server zu aktualisieren. Um wieder auf das user-Objekt zuzugreifen, verwenden wir eine URL mit dem Pfadelement "cn=Dogbert": PS C:\> $user = [ADSI] ("LDAP://localhost:389/" + >> "cn=Dogbert,ou=HR,dc=NA,dc=fabrikam,dc=com") >>

Um zu überprüfen ob die Eigenschaften tatsächlich gesetzt wurden, sollten wir sie anzeigen: PS C:\> $user.title HR Consultant PS C:\> $user.Description Dog

B.8 Arbeiten mit Active Directory und ADSI

567

B.8.3 Benutzergruppe hinzufügen

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Nun wollen wir ein paar User hinzufügen und definieren dafür einige Datenobjekte, die eine nameProperty (der Name des Arbeitnehmers) und weitere Eigenschaften enthalten. In unserem Fall wollen wir diese Daten als Hashtable-Array definieren: PS >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>

C:\> $data = @{ Name="Catbert" Title="HR Boss" EmployeeID=2 Description = "Cat" }, @{ Name="Birdbert" Title="HR Flunky 1" EmployeeID=3 Description = "Bird" }, @{ Name="Mousebert" Title="HR Flunky 2" EmployeeID=4 Description = "Mouse" }, @{ Name="Fishbert" Title="HR Flunky 3" EmployeeID=5 Description = "Fish" }

Wir schreiben nun eine Funktion New-Employee , um diese Daten zu verarbeiten und den User zur Active Directory hinzuzufügen. Die Funktion übernimmt zwei Argumente – die Liste der zu erzeugenden Employee-Objekte und optional die organisatorische Einheit (OU), in welcher sie generiert werden sollen. Standardmäßig ist es die von uns erzeugte OU: PS C:\> function New-Employee ( >> $employees = >> $(throw "You must specify at least one employee to add"), >> [ADSI] $ou = >> "LDAP://localhost:389/ou=HR,dc=NA,dc=fabrikam,dc=com" >> ) >> { >> foreach ($record in $employees) >> { >> $newUser = $ou.Create("user", "cn=$($record.Name)") >> $newUser.Put("title", $record.Title) >> $newUser.Put("employeeID", $record.employeeID)

568

B Beispiele zum Administrieren

>> >> >> >> } >>

$newUser.Put("description", $record.Description) $newUser.SetInfo() }

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Diese Funktion iteriert durch die Liste der Arbeitnehmer, erzeugt jeden einzelnen, setzt seine Eigenschaften und schreibt das Objekt zurück in den Server. Die Funktion kümmert sich nicht darum, welche Objekttypen in $employees enthalten sind (oder ob es sogar eine Collection ist). Wichtig ist nur, dass die Objekte die richtigen Eigenschaften haben. Das bedeutet, dass man anstatt einer Hashtable auch ein XML-Objekt oder das Ergebnis des Import-Csv-Commandlets nehmen könnte. HINWEIS: Die Verwendung von Import-Csv ist besonders interessant, weil Sie ein Tabellen-

kalkulationsprogramm zur Eingabe der Daten für Ihre User nehmen können. Danach exportieren Sie die Tabelle in eine CSV-Datei und verwenden den einfachen Befehl New-Employee (Import-Csv usersToCreate.csv)

um alle User aus der Tabelle nach AD zu importieren. Wir schreiben noch eine weitere Funktion Get-Employee, um Arbeitnehmer von einer OU abzurufen. Diese Funktion erlaubt optional Wildcards im Namen des Arbeitnehmers, ansonsten werden alle Arbeitnehmer zurückgegeben. Für die standardmäßige OU gilt wiederum "ou=HR". PS >> >> >> >> >> >> >> >> >>

C:\> function Get-Employee ( [string] $name='*', [adsi] $ou = "LDAP://localhost:389/ou=HR,dc=NA,dc=fabrikam,dc=com" ) { [void] $ou.psbase $ou.psbase.Children | where { $_.name -like $name} }

Nun lasst uns diese Funktionen testen. Zunächst verwenden wir New-Employee um die OU mit User Objekten zu füllen: PS C:\> New-Employee $data

Anschließend benutzen wir Get-Employee um die zuvor eingegebenen User abzurufen. Wir zeigen die Eigenschaften für Namen, Titel und Privattelefon an: PS C:\> Get-Employee | Format-Table name,title,homePhone name ---{Birdbert} {Catbert}

title ----{HR Flunky 1} {HR Boss}

homePhone --------{} {}

569

B.8 Arbeiten mit Active Directory und ADSI

{Dogbert} {Fishbert} {Mousebert}

{HR Consultant} {HR Flunky 3} {HR Flunky 2}

{} {} {}

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Alle User und deren Titel sind zu sehen. Da wir die Telefonnummer beim Erzeugen der User nicht mit eingegeben haben, bleiben diese Felder leer. Damit entsteht die Frage, wie wir die Eigenschaften eines Users aktualisieren können, nachdem wir den User erzeugt haben.

B.8.4 User-Eigenschaften aktualisieren Wir wollen eine weitere Funktion entwickeln, die wir Set-EmployeeProperty nennen. Diese Funktion übernimmt eine Liste mit Arbeitnehmern (employees) und eine Hashtable mit einer Menge von Eigenschaften, die für jeden Arbeitnehmer zutreffen. Wie gewöhnlich ist auch hier "HR" unsere standardmäßige OU. PS >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>

C:\> function Set-EmployeeProperty ( $employees = $(throw "You must specify at least one employee"), [hashtable] $properties = $(throw "You muset specify some properties"), [ADSI] $ou = "LDAP://localhost:389/ou=HR,dc=NA,dc=fabrikam,dc=com" ) { foreach ($employee in $employees) { if ($employee -isnot [ADSI]) { $employee = get-employee $employee $ou } foreach ($property in $properties.Keys) { $employee.Put($property, $properties[$property]) } $employee.SetInfo() } }

Im Unterschied zur New-Employee-Funktion verlangen wir diesmal, dass das Properties-Objekt eine Hashtable ist, da wir die Keys-Property benutzen wollen um eine Liste der Eigenschaften zu erhalten die wir dem User-Objekt zuweisen. (Das ähnelt der Form-Funktion in Kapitel 11.) Wir verwenden ebenfalls die Get-Employee-Funktion, um das zu editierende User-Objekt abzurufen. Nun wollen wir diese Funktion verwenden, um Titel und Telefonnummer von zwei Usern einzutragen: PS C:\> Set-EmployeeProperty dogbert,fishbert @{ >> title="Supreme Commander"

570

B Beispiele zum Administrieren

>> homePhone = "5551212" >> } >>

Die Änderungen überprüfen wir mit der Get-Employee-Funktion:

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

PS C:\> Get-Employee | ft name,title,homePhone name ---{Birdbert} {Catbert} {Dogbert} {Fishbert} {Mousebert}

title ----{HR Flunky 1} {HR Boss} {Supreme Commander} {Supreme Commander} {HR Flunky 2}

homePhone --------{} {} {5551212} {5551212} {}

Wie wir sehen, wurden die Titel der spezifizierten Objekte aktualisiert und auch die Telefonnummern der beiden User wurden zugewiesen.

B.8.5 User entfernen Schließlich gilt es noch herauszufinden, wie man einen User wieder entfernt. Wir schreiben dazu eine Funktion, die wir Remove-Employee nennen: PS >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>

C:\> function Remove-Employee ( $employees = $(throw "You must specify at least one employee"), [ADSI] $ou = "LDAP://localhost:389/ou=HR,dc=NA,dc=fabrikam,dc=com" ) { foreach ($employee in $employees) { if ($employee -isnot [ADSI]) { $employee = get-employee $employee $ou } [void] $employee.psbase $employee.psbase.DeleteTree() } }

Nun wollen wir mit dieser Funktion einige User löschen: PS C:\> remove-employee fishbert,mousebert

Wir vergewissern uns ob sie tatsächlich entfernt wurden: PS C:\> get-employee

B.9 Zusammenführen von zwei Datenmengen

571

distinguishedName ----------------{CN=Birdbert,OU=HR,DC=NA,DC=fabrikam,DC=com} {CN=Catbert,OU=HR,DC=NA,DC=fabrikam,DC=com} {CN=Dogbert,OU=HR,DC=NA,DC=fabrikam,DC=com}

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Wie Sie sehen, ist es unter PowerShell mit geringem Aufwand möglich, Aufgabenstellungen für Active Directory zu automatisieren.

B.9 Zusammenführen von zwei Datenmengen PowerShell-Commandlets geben Datenlisten zurück. In vielen Fällen ähneln diese Listen "Datentabellen". Manchmal wollen wir Felder aus zwei Listen miteinander kombinieren um ein neues Objekt zu erzeugen, welches Eigenschaften der Objekte beider Listen enthält. Im Endeffekt wollen wir also einen "Join" über zwei Datenmengen ausführen. Ein reales Szenario, wo dies auftreten könnte, wäre ein Kunde, der eine Liste von Mailbox-Usern von einem Exchange Server in eine CSV-Datei exportieren möchte, wobei gleichzeitig einige zusätzliche User-Daten aus einer anderen CSV-Datei eingearbeitet werden müssten. Obwohl die Version 1 von PowerShell noch über keine eingebauten Tools zur Erfüllung derartiger Aufgaben verfügt, lässt sich das leicht unter Verwendung von Hashtables realisieren. Wir zeigen hier die Basis-Lösung: Zuerst schafft man die erste Datenmenge in eine Hashtable und indiziert sie mittels "Primary Key"-Property. Dann durchläuft man die zweite Menge und fügt die zusätzlichen Eigenschaften hinzu, die aus der Hashtable extrahiert werden. (Oder man erzeugt neue Objekte und fügt die Properties beider Mengen hinzu.) Unser Beispiel demonstriert diese Vorgehensweise: Die Properties der Listen von Process- und ServiceController-Objekten werden in einem einzigen Objekt zusammengefasst. Das Ergebnis wird in eine CSV-Datei exportiert. Listing B.6: Skript Get-ProcessServiceData.ps1 get-process | foreach {$processes = @{}} { Ùq Prozessdaten abrufen $processes[$_.processname] = $_} Ùw Service Daten abrufen get-service | where {$_.Status -match "running" –and $_.ServiceType -eq "Win32OwnProcess" } | foreach { Ùe Neues Objekt erstellen new-object psobject | add-member -pass NoteProperty Name $_.Name | Ùr Member hinzufügen add-member -pass NoteProperty PID $processes[$_.Name].Id | add-member -pass NoteProperty WS $processes[$_.Name].WS | add-member -pass NoteProperty Description $_.DisplayName | add-member -pass NoteProperty FileName ` $processes[$_.Name].MainModule.FileName } | Ùt Als CSV-Datei exportieren export-csv -notype ./service_data.csv

572

B Beispiele zum Administrieren

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Zunächst erfolgt das Einlesen aller Prozessdaten q in eine Hashtabelle, der Index ist der Prozessname. Dann werden die ServiceController-Objekte für alle Dienste w, die in ihrem eigenen Prozess laufen, abgerufen. Ein neues Objekt wird erzeugt e, die Felder der Service-Objekte werden extrahiert und (unter Verwendung des Servicenamens zum Indizieren der Prozessdaten-Hashtabelle) den Prozessobjekten hinzugefügt r. Dann werden diese Informationen in eine CSV-Datei exportiert t. Beachten Sie, dass der -notype Parameter zusammen mit dem Export-Csv-Befehl verwendet wird – das synthetische Objekt hat nämlich keinen Typ. Wie Sie gesehen haben, handelt es sich hier um ein ziemlich simples Beispiel. Durch einfaches Austauschen der Datenquellen (Commandlets) und der Schlüssel (Namen der Properties) kann diese Technik für einen beliebigen Join zwischen zwei Datenlisten verwendet werden.

C

Die PowerShell-Grammatik

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Anhang

C

Die PowerShell-Grammatik Einer der Wege zum Erlernen einer neuen Sprache führt über deren Grammatik. Dieser Abschnitt präsentiert Ihnen deshalb eine knappe Zusammenfassung der PowerShell-Grammatik gemeinsam mit Erklärungen und einigen Beispielen. PowerShell benutzt einen erweiterten rekursiven Parser. Diese Erweiterung war notwendig, um mit einigen komplexeren Strukturen beim Tokenizing der PowerShell Sprache fertigzuwerden (Dieses Thema wird detailliert in Kapitel 2 behandelt). Der komplette Parser besteht aus einer Vielzahl von Parsing- und Tokenizer-Regeln. Diese Regeln können in fünf Schichten aufgeteilt werden: 1. Statement Liste: die Regeln für das Parsen einer Statement Liste und eines Statement Blocks. 2. Statements: verschiedene Arten von Anweisungen in der Sprache. 3. Ausdrücke 4. Werte 5. Tokenizer Regeln

In den folgenden Abschnitten werden wir auf jedes dieser Themen näher eingehen.

C.1 Statement-Liste = '{' '}' = [ ]*

574

C Die PowerShell-Grammatik

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

C.2 Statement = | | | | | | | | | |

C.2.1 Pipeline = | [ '|' ]* = = [? |? ]* = * = * = | = [ '&' | '.' | ] [ | ] [ | | | ]* =

BEISPIEL: Hier einige Beispiele wie Pipelines aussehen können: get-childitem -recurse -filter *.ps1 | sort name (2+3),3,4 | sort

C.2 Statement

575

& "c:\a path\with spaces.ps1" | % { $_.length } get-childitem | sort-object > c:/tmp/junk.txt

Diese Regel ermöglicht es, dass auch zugewiesene Ausdrücke wie $a = dir | sort length

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

ordnungsgemäß geparst werden.

C.2.2 Das if Statement = 'if' '(' ')' [ 'elseif' '(' ')' ]* [ 'else' ]{0|1}

Das if Statement ist die grundlegende Vergleichsbedingung in PowerShell. BEISPIEL: Ein Beispiel für das if Statement: if ($x -gt 100) { "x is greater than 100" } elseif ($x -gt 50) { "x is greater than 50" } else { "x is less than 50" }

In einem PowerShell if-Statement muss der Körper der Anweisung auch dann in geschweifte Klammern eingeschlossen werden, wenn er nur aus einer einzelnen Zeile besteht. Das elseif-Token ist ein zusammenhängendes Wort ohne Leerzeichen dazwischen. Ein if-Statement kann einen oder mehrere Werte zurückgeben, wenn es in einem Unterausdruck eingesetzt wird. BEISPIEL: Das folgende if-Statement begrenzt den Wert von $x, der $a zugewiesen wird, auf 100: $a = $( if ( $x –gt 100 ) { 100 } else { $x } )

576

C Die PowerShell-Grammatik

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

C.2.3 Das switch-Statement = 'switch' ['-regex' | '-wildcard' | '-exact' ]{0 |1} ['-casesensitive']{0|1} ['-file' | '(' ')' ] '{' [ ['default' | | | ] ]+ '}'

Das switch-Statement erlaubt Ihnen die Auswahl von Alternativen auf der Grundlage einer bestimmten Menge von Klauseln. Es kombiniert sowohl Features von Bedingungs- als auch von Schleifenkonstruktionen. BEISPIEL: So kann ein switch-Statement aussehen: switch -regex -casesensitive (get-childitem | sort length) { "^5" {"length for $_ started with 5" ; continue} { $_.length > 20000 } {"length of $_ is greater than 20000"} default {"Didn't match anything else..."} }

In einem switch-Statement darf es nur eine einzige Default-Klausel geben.

C.2.4 Das foreach-Statement = {0 |1} 'foreach' '(' 'in' ')'

HINWEIS: Das foreach-Statement iteriert über eine enumerierbare Collection. BEISPIEL: Eine Anwendung des foreach Statements: foreach ($i in get-childitem | sort-object length) { $i $sum += $i.length }

Beachten Sie auch, dass es da noch das Foreach-Object-Commandlet gibt, mit dem man Objekte nacheinander verarbeiten kann.

C.2 Statement

C.2.5 Die for- und while-Statements

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

= {0 |1} 'while' '(' ')' | {0 |1} 'for' '(' {0 |1} ';' {0 |1} ';' {0 |1} ')'

BEISPIEL: Eine Anwendung des while-Statements: while ($i -lt 100) { echo i is $i $i += 1 }

BEISPIEL: So sieht ein for-Statement aus: for ($i=0; $i -lt 10; $i += 1) { echo i is $i }

C.2.6 Die do/while- und do/until-Statements = {0 |1} 'do' ['while' | 'until'] '(' ')'

BEISPIEL: Anwendung des do/while-Statements: do { write-host $i $i += 1 } while ($i -lt 100)

BEISPIEL: Anwendung des do/until-Statements: do { write-host $i $i += 1 } until ($i -ge 100)

577

578

C Die PowerShell-Grammatik

C.2.7 Das trap-Statement = 'trap' {0 |1}

BEISPIEL: Ein trap-Statement sieht folgendermaßen aus:

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

trap { ... }

oder trap [system.nullreferenceexception] { ... }

Der Gültigkeitsbereich eines trap-Statements ist auf die Anweisungsliste begrenzt, die es enthält (siehe Kapitel 9).

C.2.8 Das finally-Statement = 'finally'

BEISPIEL: Ein finally-Statement sieht folgendermaßen aus: finally { ... }

HINWEIS: Dieses Statement ist in Version 1 von PowerShell nicht implementiert und führt zu

einem "nicht-implementiert"-Laufzeit-Fehler.

C.2.9 Anweisungen zur Flusskontrolle = ['break' | 'continue'] [ | ]{0 |1} | 'return'

Statements zur Fluss-/Ablaufkontrolle ändern die normale Ausführungsfolge von Anweisungen in PowerShell. BEISPIEL: So sehen Anweisungen zur Ablaufkontrolle aus: break break label break $labelArray[2].name return return 13 return get-content | sort | pick-object -head 10

C.2 Statement

579

C.2.10 Funktionsdeklarationen

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

= [ '(' ')' ] = '{' [ '(' ')' ] ( [ 'begin' | 'process' | 'end' ]* | '}'

Funktionsdeklarationen in PowerShell gibt es in vielgestaltiger Form, angefangen bei einer simplen Funktion mit einer impliziten Argumenteliste bis hin zu einer vollständigen Commandlet-Spezifikation. BEISPIEL: Ein Funktionsdeklaration in einfachster Form: function foo { ... }

Oder: function foo ($a1, $a2) { ... }

BEISPIEL: Eine Funktion, die wie ein vollständiges Commandlet agiert: function foo ($a1, $a2) { begin { … } process { … } end { … } }

BEISPIEL: Parameter können alternativ mittels param-Statement festgelegt werden: function foo ($a1, $a2) { begin { … } process { … } end { … } }

BEISPIEL: Eine Filterspezifikation: filter foo ( $a1, $a2 ) { … }

Das ist äquivalent zu: function ( $a1, $a2) { process { … } }

In all diesen Fällen ist die Spezifikation von Parametern optional.

C.2.11 Parameterdeklarationen = '(' ')'

580

C Die PowerShell-Grammatik

= [ ]*

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

= [ '=' ]

Diese Regeln umfassen die Notation von Parameterdeklarationen. Diese erlauben als Option Typqualifizierer und Initialisierer für jeden Parameter. Mehrfache Typqualifizierer ermöglichen komplexere Transformationen von Argumenten. Die Initialisierer von Argumenten können Unterausdrücke enthalten, die ein beliebiges Initialisieren (auch von Pipelines) gestatten. BEISPIEL: Einige Parameterdeklarationen: param ($x, $y) param ([int] $a, $b = 13) param ([int][char] $a = “x”, [System.IO.FileInfo[]] $files = $(dir *.ps1 | sort length))

C.3 Ausdruck = = [ ]* = [ comparisonExpressionRule>]* = [ ]* = [ ]* = [ ] = [ ]*

581

C.4 Wert

= [ ]*

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

= [ ]* = | = * = '[' ']' ] | '.' [ {0|1} | valueRule> ] = '(' ')'

C.4 Wert = '(' ')' | '$(' ')' | '@(' ')' | | '@{' '}' | | | | | | | | = '=' [ ]*

Die valueRule wird zum Verarbeiten einfacher Werte benutzt, die zum Beispiel Hash Literale oder Skriptblöcke enthalten können. Auch Unterausdrücke werden nach dieser Regel verarbeitet.

582

C Die PowerShell-Grammatik

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

C.5 Tokenizer-Regeln = "-eq" | "-ne" | "-ge" | "-gt" | "-lt" | "-le" | "-ieq" | "-ine" | "-ige" | "-igt" | "-ilt" | "-ile" | "-ceq" | "-cne" | "-cge" | "-cgt" | "-clt" | "-cle" | "-like" | "-notlike" | "-match" | "-notmatch" | "-ilike" | "-inotlike" | "-imatch" | "-inotmatch" | "-clike" | "-cnotlike" | "-cmatch" | "-cnotmatch" | "-contains" | "-notcontains" | "-icontains" | "-inotcontains" | "-ccontains" | "-cnotcontains" | "-isnot" | "-is" | "-as" | "-replace" | "-ireplace" | "-creplace" = "=" | "+=" | "-=" | "*=" | "/=" | "%=" = "-and" | "-or" = "-band" | "-bor" = "2>&1" | ">>" | ">" | ">" | "1>>" = "function" | "filter"

Ein expandierbarer String führt eine Variablenexpansion innerhalb durch: = ".*"

Ein konstanter String führt keine Expansion aus, auch Steuersequenzen werden nicht verarbeitet: = '.*'

Variablen sehen wie $a123 oder ${abcd} aus – Steuerzeichen in einem Variablennamen sind in { } einzuschließen: = \$[:alnum:]+ | \${.+}

Die ParameterToken-Regel betrifft Commandlet-Parameter wie -foo oder - boolProp: . Da diese Regel auch auf –foobar zutrifft, muss sie vor der --token-Regel geprüft werden: = -[:letter:]+[:]{0 |1} = ' |' = ' |'

C.5 Tokenizer-Regeln

583

= '--' = '..'

Das Tokenizing von Zahlen hängt davon ab, welche Zeichen bezüglich Parsing-Modus nachfolgen:

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

= C# number pattern... = "." | "::" | "["

Die folgende Token-Regel wird zum Parsen der Token von Befehlsargumenten verwendet, sie ist nur nach dem Lesen des Befehlsnamens aktiv. Der Zweck ist jedes Zeichen in einem Befehlsargument zu erlauben, außer Anweisungsbegrenzern (Zeilenumbruch, Semikolon oder schließende Klammer), Ausdrucksbegrenzern (schließende Klammer, Pipe Symbol) oder Whitespaces. = [^-($0-9].*[^ \t] = "!" | "-not" | "+" | "-" | "-bnot" | = '-f' = "param" = '++' | = '*' | '/' | '%' = '+' | '-' | emDash | enDash | horizontalBar

Die Attribute-Spezifikation sieht wie [int] oder [system.int32] aus und erlaubt eventuell auch den vollen Bereich der PowerShell-Metadaten. = \[..*\]

Die folgenden Token beziehen sich auf die Klasse der Zeilenabschluss-Token. Die Token && und || werden nicht geparst, führen aber in der Version 1 von PowerShell zu einem Fehler (nicht implementiert). = ';' | '&&' | '||' |

Der Namen eines Commandlets kann aus irgendeiner Zeichenfolge bestehen, die durch einen Whitespace begrenzt wird der nicht mit einem der nachfolgend aufgeführten Zeichen übereinstimmt. Das trifft grundsätzlich auf ein Commandlet zu, welches ein natives Commandlet oder der Name einer Exe (foo/bar, foo/bar.exe, foo\bar.exe, foo.bar.exe, c:\foo\bar usw.) sein kann. = [^$0-9(@"'][^ \t]*

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Index

Index 2> 174 2>&1 174 2>> 174 ` 67 __new_instance 280 - 121, 152 -- 57, 152 -= 128 -and 146 -append 177 -as 150 -as operator 151 -band 146 -bnot 146 -bor 146 -bxor 146 -ccontains 133 -ceq 133 -cge 133 -cgt 133 -cle 133 -clike 141 -clt 133 -cmatch 142 -cne 133 -cnotcontains 133 -cnotlin 141 -cnotmath 142 -ComputerName 473 -contains 133 -creplace 142 -Debugger 327 -Delimiter 361 -depth 387

-desc 528 -encoding 177 -eq 133 -ErrorAction 304 -ErrorVariable 298, 299 -ev 301 -f 172 -FilePath 327 -ge 133 -gt 133 -icontains 133 -ieq 133 -ige 133 -igt 133 -ile 133 -ilike 141 -ilt 133 -imatch 142 -ine 133 -inotcontains 133 -inotlike 141 -inotmatch 142 -InputObject 55, 66 -ireplace 142 -is 149 -is operator 151 -isnot 149 -isnot operator 151 -le 133 -like 141 -LiteralPath 356 -lt 133 -match 142 -ne 133

-noclobber 177 -not 146 -notcontains 133 -notlike 141 -notmatch 142 -or 146 -prompt 517 -PSHost 327 -quiet 365 -replace 119, 142, 449, 530 -step 317, 320 -strict 440 -trace 314 -width 177 -xor 146 , 152, 158 ; 71 :: 109, 171 . 169 .. 161 ./ 61 .\ 61 .NET 35 Enumeratoren 398 Grundlagen 389 Instanzen erzeugen 395 Typen 393 Typsystem 390 .NET-Adapter 89 .NET-Konverter 115 .NET-Reflection 469 [ ] 162 [] 152 [array] 108

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

586

Index [bool] 108 [byte] 108 [char] 108 [decimal] 108 [double] 108 [float] 108 [hashtable] 108 [int] 107 [long] 107 [psobject] 108 [regex] 108, 347 [scriptblock] 108 [single] 108 [string] 108 [switch] 108 [type] 108 [WMI] 479 [WMICLASS] 479 [WMISEARCHER] 479 [xml] 108, 367 @ 54, 97 @( … ) 154 * 121 *= 128 / 121 /= 128 & 54, 531 % 121 %= 128 + 121, 152 ++ 152 += 128 < 175 387 = 128 > 174 >> 174 | 73 $_ 54, 241 $? 301 $( … ) 154 $args 216, 437 $error 298 $error[0] 298 $ErrorActionPreference 304 $false 177

Indizieren 102, 162 Reverse 166 Array-Operatoren 158 Array-Unterausdruck 153, 156 Assembly 390 Assembly erkunden 391 Assembly laden 391 Auflistung 191 Auflistungen 138 Ausdrücke 44, 119 Ausdrucksmodus 69, 91 Ausführungs-Richtlinie 499, 500 Ausführungsrichtlinie 245 Ausgabe 77 Ausnahme 307 A Auswerten 44 Abbrechen 320 Authentifizierung 496 Ablaufsteuerung 183, 206 Automatisieren 442 Active Directory 565 Autorisierung 496 Benutzer hinzufügen 566 AutoSizeMode 432 Benutzergruppe hinzufügen 567 awk 540 User entfernen 570 User-Eigenschaften 569 B Active Directory-Infos 551 Backquote 67 Active Directory-Service 565 Backtick 67 ActiveDocument 460 bash 540 AD 565 Basistypen 90 ADAM 565 Batchdateien 534 Add-Member 264 Bedrohungen 492 Additions-Operator 121 Befehle 55 ADO-Adapter 89 Befehle aufrufen 255 ADSI 565 Befehle ausführen 531 ADSI Object Adapter 89 Befehlskonzept 54 Alias 62 Befehlsmodus 69 AliasProperty 264, 265 Befehlsparameter 55 AllSigned 500 Anführungszeichen 57, 66, 69, 91 Befehlspfad 499 Befehlstypen 58 Angriffsobjekte 494 Befehlsvervollständigung 43 Apostroph 66 Befehlszeile 32 AppActivate 453 begin 241, 259 Applet 450 Benutzername 520 Argumente 55 Benutzerschnittstelle 416 Arithmetische Operatoren 121 Bereichsmodifizierer 231, 247 Array Bereichsoperator 165 Bereichsoperator 161 Erstellen 102 Bildschirm 81

$foreach 193 $global:name 247 $host 312 $LASTEXITCODE 301 $matches 142, 201 $MaximumErrorCount 298 $MyInvocation 324 $null 177 $OFS 216 $PROFILE 533 $PSHOME 77 $switch 205 $true 177

587

Index Bindungsprozess 75 Bit-Operatoren 146 bp 324 break 195, 308 breakpoint 320, 322 built-in commands 58

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

C C# 398, 546 Call-JScript 466 Call-Operator 531 Call-VBScript 465 Carriage return 68 Cast-Operation 111 Certmgr.exe 512 CIM 471 class 281 ClientRectangle 436 Clippy 461 Cmd.exe 527, 539 Cmd.exe, Unterschiede 532 Code generieren 285 Code-Injection 498 Codecs 475 CodeMethod 264 CodeObject 477 CodeProperty 264 Collection 97, 138, 191 Color 436 COM Get-Member 443 Instanziieren 440 Multithreadding 467 New-Object 440 parametrisierte Eigenschaft 446 Probleme 467 COM-Collection 446 COM-Interop-Library 440 COM-Objektadapter 89 COM-Objekte kapseln 469 CommandInfo-Objekte 255 Commandlets 55 Common Information Model 471 Constructors 116 Containment 139 continue 195, 304, 325

ControlPanelItem 450 Controls 419 ConvertFrom-SecureString 518 ConvertTo-SecureString 518 copy 528 Copy-Item 528 Core Cmdlets Clear-Item 350 Copy-Item 350 Get-Content 350 Get-Location 350 Mkdir 350 Move-Item 350 New-Item 350 Remove-Item 350 Rename-Item 350 Set-Content 351 Set-Item 350 Set-Location 350 Credentials 518 CSV-Datei 571 CurrentDirectory 400 Custom Object Adapter 89 CustomClass 278

D Danom-Virus 491 Databinding 431 DataGrid 434 DataSource 432 Dateien 81 Lesen 357 Schreiben 362 Dateiverarbeitung 349 Datenbindung 431 Datengitter 431 Datenliste 431 Datenmengen 571 Datenquelle 431 DateTime 127 Debug-Statement 234 Debugging 312 del 529 Dialog 420 Dictionary 97, 404 Dienstprogramme 563

dir 49, 528 Dispose 436 Distributed Management Task Force 471 Division 126 DLL 58, 390 DMTF 471 do/while 188 Dock 418 Dokumente analysieren 344 Domäneninformation 551 doskey 537 Dotting 250 DPAPI 518 Drawing 421, 423 DrawLine 436

E edit.com 61 Editieren 42 Eigenschaft 37, 169 Eigenschaft hinzufügen 275 Eingabeprüfung 496 Eingebetteter Prompt 320 Elevation of Privilege 493 else 184 elseif 184 end 241, 259 Endlosschleife 464 endof-parameters 57 EnterNestedPrompt 322 eq 524 Ereignis 418 Ereignisbehandlung 414 Ereignisprotokoll 334, 558 error handling 294 Error Record Property CategoryInfo 296 ErrorDetails 296 Exception 296 FullyQualifiedErrorId 296 InvocationInfo 296 TargetObject 296 ErrorRecord 295, 296 ErrorStream 295 Escapesequenz 68 Eventhandler 417

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

588

Index EventLog 559 Exception 307 Exchange 336 Execution Policy 245, 499 ExecutionContext 286 exit 248 ExpandString 287 Expansion 68, 92 Explicit Cast Operator 116 Export-CliXML 384, 561 Export-Window 449 Extensible Markup Language 366

F Fehlerbehandlung 294 Fehlermeldung 174, 295 Fibonacci-Reihe 129, 155 FillRectangle 436 Filter 239 findstr 364 findstr.exe 533 flexible Syntax 62 Flusskontrolle 50, 183 for 189 for, cmd.exe 533 foreach 191 Foreach-Object 48, 207 Format-Commandlets 78 Format-Custom 78 Format-List 77, 78 Format-Operator 172 Format-Table 77, 78 Format-Wide 78 Formatierung 77 Formatter 78 Forms 418 Framework 390 FullName 392 function 216 Function Drive 242 function: 242, 289 Funktion als Commandlet 241 Anzahl von Argumenten 223 Argumente 227

Argumente-Array 216 Debugging 234 Flags 226 Grundlagen 216 in Pipeline 238 Initialisieren 224 Optionen 227 Output 234 Parameter 219, 224 return 236 Rückgabewerte 231 Schalter 227 switch-Parameter 226 Typbeschränkungen 221 Verwalten 242 $args 216

G G.I.S.S.-Prinzip 53 gcs 326 GDI 434 GDI+ 434 Generics 402 Get-Assemblies 393 Get-BatchFile 535 Get-ChildItem 62, 354, 528 Get-Command 255 Get-ComRSS 457 Get-Content 62, 357 Get-Credential 519 Get-DataBaseReader 399 Get-Date 175, 256 Get-Digg 458 Get-DomainInfo 551 Get-EventLog 334, 558 Get-ExecutionPolicy 501 Get-FilesInMsiPackage 470 Get-FromDatabase 399 Get-HexDump 359 Get-HotFixes 555 Get-MachinesMissingHotfix 556 Get-MagicNumber 360 Get-Member 108 Get-Process 49, 431, 541 Get-ProcessServiceData 571

Get-ProgID 441, 442 Get-RSS 408 Get-RSSMenu 408 Get-Sched 564 Get-SoftwareFeatures 552 Get-Spelling 460 Get-Types 394 get-wmiobject 50, 472, 553 Get-WordDefinition 454 Get-XPathNavigator 380 getElementById 454 GetLength 465 getproperties 273 gm 444 Grafikausgabe 434 Graviszeichen 67 grep 364, 540 Groß-/Kleinschreibung 133, 136 Großbuchstaben 544 Group-Object 347 Gruppieren 153 GUI 416 GUI-Shell 442 Gültigkeitsbereich 309

H Hash-Algorithmus 490 Hash-Literal 97 Hashing 502 Hashtabelle Allgemein 97 Arraynotation 98 Eigenschaftennotation 98 Manipulieren 99 Modifizieren 99 Values 98 Verwenden 345 Hauptformular 418 Here-String 93, 415, 477 Hexadezimale Literale 96 Host-API 312 Hotfixes 554 HTTP-Protokoll 414

589

Index

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

I I/O-Umleitung 81 IConvertable 116 Identität verschleiern 493 IDictionary 97 if 50, 184 Implicit Cast Operator 116 Import-Clixml 384 Import-Window 449 Information Disclosure 493 Installer 40 Installieren 40 Installierte Software 552 Integer-Operation 87 Integrität 511 Internet 406 Internet Explorer 441, 454 Interop Wrapper 467 Interpreter 55 interval 436 InvocationInfo 297, 325 Invoke-Display 462 Invoke-Expression 286, 415, 496, 521 Invoke-MSAgent 463 Invoke-WebServer 411 InvokeMember 470 InvokeScript 288 IsReadOnly 517 Item 446 ItemNotFound 297

J JavaScript 466 Join 344, 571 JScript-Code 466

K Klammerausdruck 72 Kleine Sprachen 277 Kodierung 90 Komfort-Alias 63 Konvertierung 111 Kryptographie 490 ksh 540

L Labeled Loops 195 Labels 195 Laufwerke 349 Layoutmanager 418 Leere Arrays 105 Leere Ausdrücke 156 Leerzeichen 66 Linke-Hand-Regel 121 List 403 Literale 90 Live-Objekt 559 Logische-Operatoren 146 loop 534 Low-Level-Überwachung 326

M MakeCert.exe 504 MakeGenericType 403 MakeReadOnly 517 Management Object Format 88 ManagementEventWatcher 484 ManagementObjectSearcher 479 Manipulieren von Daten 493 Match 348 Math 109 MD5 490 Measure-Object 542 Media-Player 441 Mehrfache Zuweisungen 129 Message 424 Messagebox 461 Metaprogrammierung 253 Method 280 Methode 37, 170 Methodenaufrufe 547 Microsoft Management Console 521 Microsoft Word 441, 458 mmc.exe 521 Modulo 126 MOF 88 MSH/Cibyz-Wurm 492 Multidimensionale Arrays 167 multiple assignments 129 Multiplikations-Operator 124 Multiplikator-Suffix 96

Multithreading 415 Musterabgleich 140 Mustervergleich 143

N Named Captures 144 Navigate2 454 Netzwerkzugriff 454 new 281 New-GenericDictionary 405 New-Item 289 New-Menu 424 New-MenuItem 424 New-Menustrip 424 New-Object 395 New-PSDrive 351 New-Separator 424 Newline 68 NewScriptblock 288 Nicht-terminierender Fehler 294 Nichtanerkennung 493 non-terminating error 294 NoteProperty 264, 266 Null 69 Numerische Literale 95

O ObjectNotFound 297 Objekte 37, 39 Erweitern 264 Erzeugen 261 Manipulieren 261 Mitglieder 261 public members 261 Sortieren 46 Synthetische Mitglieder 262 Objektorientiertes Programmieren 37 Öffentliche Schlüssel 391 Office-Applikationen 454 OOP 37 Operatoren 119, 149 Out-Default 80 Out-File 80, 176, 362 Out-Host 80 Out-Null 80 Out-Printer 81

590

Index

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Out-String 81, 83 Output-Commandlets 80 Output-Umleitung 41

PSNoteProperty 279 PSObject 265, 273 PSObject-Layer 88 PSScriptMethod 280 PSTypeConverter 115 Public Key 391 Public Key-Verschlüsselung 502 Put 484 pwd 400

S

Schleife 183, 187 Schleifenenumerator 205 Schlüsselwörter 183 P Schritt-Modus 320 Paint 434 Schrittweise Überwachung 317 param-Statement 219, 246, 258 schtasks.exe 563 Parameter 75, 116 Scope-Modifizierer 180 Parameterbinder 56 ScriptControl 465, 477 Parameterbindung 75 ScriptMethod 264 Q Parameterbindung überwachen 330 ScriptMethode 267 Quantifizierer 348 ParameterizedProperty 264 ScriptProperties 268 Query 381, 398, 473, 476, 479, 483, ScriptProperty 264 Parametertypen 221 484, 498 Parameterübergabe 219 SecureString 516 Quoting 66 Parse Method 116 sed 544 Parsing 64, 69, 144 Select-Members 394 Passwort 520 Select-Object 47, 270 R Paste 460 Select-String 364, 533 Random 462 PATH 499 Semikolon 71 Range Operator 161 PATHEXT 499 Send 457 RawUI 313 Pearl 545 SendHeader 414, 416 RCW 469 Pfad 353 SendKeys 453 readkey 313 Pfadnamen 400 SendResponse 414 readline 313 Pi 110 Sequenzen 102 Really Simple Syndication 407 Pipe-Operator 73 ServiceController 572 Rechner 426 Pipeline 73, 154 Set-Content 362 Rechtschreibprüfung 458 Pipeline Output 102 Set-ExecutionPolicy 245, 501 Referenztyp 101 Polling 415 Set-PSDebug 314 Reflection 391, 469 Popup 460 SetRequestHeader 457 Registry- Provider 441 PositionMessage 297 sh 540 PowerShell-Ereignisprotokoll 336 regulärer Ausdruck 141, 348 Shadowing 276 Remote-Zugriff 499, 560 Pre-Release 543 Shared Libraries 391 RemoteSigned 500 Process 241, 259, 521 Shell 32 Remove-Item 529 ProcessStartInfo 521 Shell.Application 442, 450 Repudiation 493 ProgID 441 ShellExecute 521 Resolve-Path 402 Prompt 41, 48 Show 419 Response 416 Prompt einstellen 536 Show-Members 395 Restricted 500 Properties 264 ShowDialog 419, 422 return-Statement 236 Property 264 Sichere Skripte 515 RightEdge 424 PropertySet 264 Sicherheit 490 Risiko-Minimierung 494 Protokolldatei 341 Sicherheitsempfinden 490 Rollen 496 Prozess überwachen 543 Sicherheitsmodellierung 492 RSS-Feed 407, 456 Prozessbetrachter 432 Signieren 502, 508 Rücktaste 69 Prozessliste 541 Signierende Autoritäten 503 runas.exe 520 PSDrive 351 Silently Continue 304

591

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

Index Singleton-Array 105 Skalare Vergleiche 134 Skript 65 Argumente 245 Beenden 248 Grundlagen 244 param-Statement 246 Sichtbarkeitsregeln 247 Skript-Ausführung 499 Skriptbefehle 55 Skriptblock 254, 419 Skriptblock Literal 258 Skriptsprache 32 slicing 166 sort 47, 528 Sort-Object 99 Split 341, 415 Spoofing 493 Stack 324 Start-Agent 461 Start-LocalUserManager 520 Starten 40 Statement 71 Statements 212 Statische Methoden 109, 171 statische Mitglieder 108 Stop 304 Stop-Process 541 Streamingverhalten 74 Strict-Modus 319 STRIDE 493 String 66, 90 String-Expansion 91, 415 Stringdarstellung 90 Stringexpansion 93 StringSplitOptions 343 Strong Name 391 Strong Private Key-Schutz 512 Style 424 Subroutinen 534 Substitution 120, 529 Subtraktion 126 switch break 203 Dateiverarbeitung 204 Groß-/Kleinschreibung 201 Grundlagen 197

Reguläre Ausdrücke 200 Schleifenenumerator 205 Werte-Array 202 Wildcard Pattern 199 Switch-Parameter 57 System.__ComObject 446 System.Collections.Hashtable 98 System.Drawing 434 Systemsteuerung 450

T

Typanpassungssystem 88 Typattribut 179 Typbeschleuniger 480 Typbibliothek 467 type 528 type accelerator 480 TypeConverter 116 Typenmanagement 85 Typerweiterung 283 Typkonvertierung verfolgen 328 Typliterale 107 Typnamen 107 Typqualifizier 130 Typsystem 85, 273 Typumwandlung 110, 113 Typumwandlungsfehler 179

Tabellen-Layoutmanager 426 Tabulator 68 Tampering 493 TargetObject 297 Taschenrechner 426 Tastatur-Makro 537 U Tastatureingaben 453 Überwachen 314 Tastatursequenz 453 UI 312 Tastenkombinationen 42 Umgebungsvariable 180, 530 Teilarrays 164, 166 Umleitung 174 Teilausdrücke 92 Terminal Server-Einstellungen 553 Umleitungsoperator 295 Umleitungsoperatoren 174 terminating error 294 undefinierte Variablen 319 Terminieren 71 Unicode 90 Terminierender Fehler 294 UNIX-Shells 540 Terminologie 54 Unrestricted 500 Test-Path 178 Unterausdruck 153, 155 Text 341 Unterbrechungsmodus 320 Textkodierung 82 Unterschrifts-Zertifikat 507 Textmanipulation 348 throw-Statement 310 Timer 434 V tlbimp.exe 469 Variablen 45, 177, 529, 548 Token 65, 349 Variablen Tokenizer 65, 348 Lebenszeit 228 ToString 362 Sichtbarkeits-Regeln 228 ToUpper 544 Variablensubstitution 91 Trace-Command 76, 312, 327 VBScript 548 Trace-Listener 327 VBScript-Code 465 Transparenz 437 Verb-Substantiv 58 Trap 325, 415 Vergleichsoperatoren 133, 138 trap-Statement 307 Vergleichsregeln 134 Typ-Adaption 88 Verlängern 73 Typ-System 88 Verzeichnisgröße 541 Typanpassungsschicht 88 Verzweigungen 183

592

Index

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

W

WMI 442, 471 WMI Query Language 479 WMI-Adapter 89 WMI-Events 483 WMI-Methoden 481 WMI-Objektadapter 473 WMI-Repository 473 WMI-Typen 479 WMIDateStringToDate 477, 478 Word 441, 458 Word-Rechtschreibprüfung 458 Wörter suchen 454 Wörter zählen 345 WQL-Strings 479 Write-Output 55 writeline 313 WScript.Shell 451

Wagenrücklauf 68 WaitForNextEvent 484 WebClient 406 Webserver 409 Webserver-Skript 411 Weiße Listen 495 Wertausdrücke 132 Where-Object 210 Wheres 521 while 50, 187 WhiteSpace 342 Wildcard Pattern 140 Wildcards 353 Win32_Process 473, 481 Win32_TerminalService 553 Windows Data Protection API 518 Windows Management InstrumentaX tion 471 Windows-Agent 461 xargs 540 Windows-Automatisierung 442 XML Windows-Installer 469 AppendChild 368 WinForms 417 CreateAttribute 369 WinForms-Bibliothek 423 CreateElement 368 WinHTTP 456 dump-doc 372 Wissenschaftliche Notation 87 Hinzufügen von Elementen 368

Laden 371 Objekte 367 Pipeline 378 Save 370 Select-Help 375 SetAttributeNode 369 Speichern 371 Verarbeitung 366, 378 XML-Dateien 371 XML-Konfigurationsdatei 283 XPath 379

Z Zahlen 95 Zeichenoperationen 434 Zeilenumbruch 68, 71 Zeilenwechsel 68 Zertifikat exportieren 512 Zertifikat-Autorität 505 Zertifikate 503 Zertifikate, selbst-signierte 504 Zufallszahlengenerator 464 Zuweisungsoperatoren 128 Zwischenablage 458

>PUKV^Z7V^LY:OLSSPT,PUZH[a>PUKV^ZOH[a^HYLPULLPUMHJOa\ILKPLULUKL 6ILYÉjJOLKHZ(\[VTH[PZPLYLU]VU:`Z[LTHISj\MLUPZ[KLUUVJOUPJO[NHUaLPUMHJO‹ LZZLPKLUUTHUZL[a[7V^LY:OLSSLPU4PJYVZVM[ZUL\L\UP]LYZLSSL:RYPW[ZWYHJOL +HZPLLPNLUZMmY>PUKV^ZLU[^PJRLS[^\YKLZPUKTP[POYU\U+PUNLTlNSPJOKPL ]VYOLYKLU,PUZH[a]VU=)=):JYPW[VKLY* LYMVYKLY[LU >PUKV^Z7V^LY:OLSSPT,PUZH[aPZ[LPU7YVNYHTTPLY[\[VYPHSMmY:`Z[LTHKTPUPZ[YH [VYLU\UK,U[^PJRSLYKHZKLU3LZLY\TMHZZLUKPUKPL:WYHJOL\UK:WYHJO\TNL I\UNLPUMmOY[+HZ)\JOaLPN[^PL:RYPW[L\UK/PSMZTP[[LSLU[^PJRLS[^LYKLU\T :`Z[LTWYVaLZZLa\H\[VTH[PZPLYLUVKLYTjJO[PNL:`Z[LTTHUHNLTLU[>LYRaL\ NL\TKPL[jNSPJOLU(\MNHILUKLY>PUKV^Z:`Z[LTHKTPUPZ[YH[PVUa\IL^jS[PNLU +HZ)\JOKLJR[H\tLYKLT;OLTLU^PL)H[JO:RYPW[PUN\UK:[YPUN=LYHYILP[\UN *64\UK>40ZV^PLKPL5,;\UK>PU-VYTZ7YVNYHTTPLY\UNHI 5PJO[a\SL[a[aLPN[)Y\JL7H`L[[L^PLZV7V^LY:OLSSZV\UKUPJO[HUKLYZLU[^P JRLS[^\YKL\UKLU[ZWYLJOLUKHYILP[L[+HZ>PZZLUKLZ/H\W[LU[^PJRSLYZKPLZLY :WYHJOL]LYTP[[LS[KLT3LZLYKHZ[PLMLYL=LYZ[jUKUPZKHZMmYKLUILZ[TlNSPJOLU ,PUZH[a]VU7V^LY:OLSSUl[PNPZ[

—(SSL:JOH[[PLY\UNLU]VU7V^LY:OLSSH\ZKLY-LKLYKLZ/H\W[ZWYHJOLU[^PJRSLYZ +LY0UOHS[PZ[OLY]VYYHNLUKH\MILYLP[L[\UK]LYZ[jUKSPJONLZJOYPLILU 2LP[O/PSS:VM[^HYLHYJOP[LR[ :JV[[/HUZLSTHU*VTW\[LYALUJVT —0JOSPLILKPLZLZ)\JO

IY\JL7(@,;;,PZ[.YmUK\UNZTP[NSPLKKLZ7V^LY:OLSS;LHTZILP4PJYVZVM[ ,YPZ[MmYKHZ+LZPNUKLY:WYHJOLTP[]LYHU[^VY[SPJO\UK/H\W[]LYMHZZLYKLY :WYHJOPTWSLTLU[H[PVU=VYZLPULYALP[ILP4PJYVZVM[LU[^PJRLS[LLYILP:VM[^H` :`Z[LTZ\UKILP42:LYRaL\NLMmY>PUKV^Z

^^^OHUZLYKLJVTW\[LY  0:)5  

>PUKV^Z:`Z[LTHKTPUPZ[YH[VYLU \UK5,;,U[^PJRSLY

:`Z[LT]VYH\ZZL[a\UNLUMmYL)VVRPUZPKL!0U[LYUL[=LYIPUK\UN(KVIL9LHKLY(JYVIH[]VKLYOlOLYMmY>PUKV^ZHI>05 :,VKLY4(*6:?(TILZ[LUNSLPJOVUSPULYLNPZ[YPLYLU

Windows PowerShell im Einsatz downloaded from www.hanser-elibrary.com by 46.3.194.58 on September 5, 2017 For personal use only.

3,95,5:0,76>,9:/,33APUKV^ZHU^LUK\UNLU  >LIWYjZLUaa\T)\JO\U[LY^^^THUUPUNJVTWH`L[[L

Suggest Documents