BLOG
Wissenstransfer von IT-Spezialisten
| |

PowerShell: Aufrufen, Argumente übergeben und Variablen – Part 4

3.3    PowerShell aufrufen und Argumente übergeben

Die PowerShell kann aus einer Hostanwendung, z.B. der CMD heraus aufgerufen werden. In diesem Fall kann sie bestimmte Parameter empfangen und verarbeiten. Alle verfügbaren Parameter können in einem CMD Fenster mittels powershell /? angezeigt werden. Der wichtigste Parameter ist wohl der „-File“ Parameter. Mit Hilfe des File-Parameters kann ein PowerShell Skript übergeben werden. Dies ist extrem nützlich für unsere Arbeit mit z.B. Softwareverteilungssystemen wie NetInstall oder SCCM. Es können so komplexe Aufgaben in einem in der Regel unbeaufsichtigten Modus erledigt werden. Wichtig bei einer derartigen Ausführung ist noch der Parameter „-ExecutionPolicy“, welcher die Ausführungsrestriktionen für die PowerShell Instanz festlegt, die das Skript ausführt. Hier wird die Policy „bypass“ besonders wichtig, da nur sie die Garantie gibt, dass das Skript ohne Nachfrage ausgeführt wird. Folgendes Beispiel soll die Vorgehensweise veranschaulichen:

1
1.    Powershell.exe –ExecutionPolicy bypass –File .\SetNicTeamingParameter.ps1 –IPAddress 10.1.1.28 –SM 255.255.255.0

Soll das auszuführende Skript irgendwelche Argumente aufnehmen und verarbeiten, muss der Parameter „-File“ der letzte in der Kommandozeile sein, da alles was hinter dem Skriptnamen aufgeführt wird, als Skriptargumente interpretiert wird.

3.4    Variablen

Variablen sind wohl eine der wertvollsten Erfindungen einer Programmiersprache. Deshalb werden sie mit einem „$“-Zeichen gekennzeichnet (natürlich Blödsinn). Anders als in der altbewährten Pro-grammiersprache Basic, wird das Dollarzeichen nicht an den Variablennamen angehangen, sondern ihm vorangestellt (das ist wohl aber nicht der einzige Unterschied zwischen Basic und PowerShell). Die Variablennamen können fast beliebige Zeichen enthalten. Soll ein Variablenname ein unzulässiges Zei-chen enthalten, z.B. „ { [ \ muss ein sog. Escape-Zeichen dem problematischen Zeichen vorangestellt werden und der gesamte Variablenname muss in geschweiften Klammern umschlossen sein. In der PowerShell wird das umgekehrte, einfache Anführungszeichen als Escape-Zeichen verwendet ( ` kann auf der Tastatur über die Tastenkombination Shift + Taste links neben Backspace gefolgt von einem Leer-zeichen eingegeben werden, siehe Kapitel 3.11). Mit folgendem Ausdruck:

1
1.    ${this`{value`}is} = 1

wird die Variable mit dem Namen „this{value}is“ auf den Wert 1 gesetzt.

Die PowerShell unterscheidet drei Typen von Variablen:

User-created    Wie der Name sagt, werden Variablen von diesem Typ vom Benutzer erzeugt und gepflegt
Automatic    Automatische Variablen speichern meistens den Status der PowerShell, werden von der PowerShell erzeugt und gepflegt und können nicht vom Benutzer verändert werden (Beispiel: $PsHome)
Preference    Preference Variablen werden von der PowerShell erzeugt und mit Standard Wer-ten versehen. Sie speichern Benutzereinstellungen im Bezug auf die Shell selbst (z.B. $MaximumErrorCount oder $MaximumVariableCount), können aber vom Benutzer verändert werden.

Zu den automatisch erzeugten Variablen gehört auch „$_“. Es ist sozusagen eine besondere „Laufvariable“ bei solchen Sprachkonstrukten wie Foreach-Object (siehe Kapitel 4.4.8). Aber auch andere Spra-chelemente erzeugen automatische Variablen: $Switch im Switch-Anweisung und $Foreach im Foreach-Anweisung (siehe Kapitel 4.4.3 und 4.4.9). Immer speichert diese Art von Variablen einen bestimmten Zustand eines Objektes während der Ausführung der Anweisung selbst.

Variablen werden in der PowerShell nicht explizit deklariert, sondern bei der ersten Zuweisung erzeugt. Wird bei der Erzeugung der Variablen kein expliziter Typ angegeben, kann diese Variable jeden Datentyp speichern:

1
2
3
4
5
6
1.    $var = 5
2.    $var
3.    5
4.    $var = „abc“
5.    $var
6.    abc

Ist hingegen bei der Zuweisung ein bestimmter Datentyp vorgegeben, kann die Variable ausschließlich Daten des gleichen Datentyps speichern:

1
2
3
4
5
6
7
8
9
1.    [int32]$var = 5
2.    $var
3.    5
4.    $var = „abc“
Cannot convert value "abc" to type "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:5
+ $var <<<< ="abc"
+ CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMeta-dataException
+ FullyQualifiedErrorId : RuntimeException

Wenn jedoch die zugewiesenen Daten entsprechend konvertiert werden können, übernimmt das die PowerShell im Hintergrund:

1
2
3
1.    $var = „0123“
2.    $var
3.    123

Die PowerShell verwaltet in Bezug auf Variablen (aber auch Funktionen, Aliase und Drives) unterschiedliche Geltungsbereiche (sog. Scopes). Der allgemeine Bereich (global scope) entsteht, wenn die PowerShell startet. Weitere Bereiche entstehen, wenn z.B. ein Skript (script scope) oder eine Funktion (function scope) aufgerufen wird. Sie werden dann child scopes genannt. Der übergeordnete Bereich wird entsprechend parent scope genannt. Zur Veranschaulichung soll folgendes Beispiel betrachtet werden:

1.    Die PowerShell wird gestartet
2.    Ein Skript wird ausgeführt
3.    Innerhalb des Skriptes wird eine dort definierte Funktion aufgerufen
4.    Diese Funktion ruft eine weitere Funktion auf, welche im gleichen Skript definiert ist

Schritt eins erzeugt den global scope (parent). Schritt zwei erzeugt den script scope (child). Schritt drei erzeugt den function scope (child zum script), damit wird der script scope zum parent scope des function scope. Im Schritt vier wird wiederum ein weiterer function scope erzeugt. Diese Kette kann beliebig fort-gesetzt werden. Wichtig in diesem Zusammenhang ist die Sichtbarkeit der Variablen (und ggfls. weiteren Elementen, wie Aliase, Drives, Funktionen, etc.). Es gibt dabei zwei grundsätzliche Regeln:

–    Jeder child scope „sieht“ alle Variablen des parent scopes, ggfls. auch in mehreren Ebenen
–    Der Inhalt einer Variablen kann nur in dem scope verändert werden, in dem die Variable erzeugt wurde, es sei denn die scope Bezeichnung wird explizit angegeben.

Eine explizite Angabe des scopes erlaubt also die Manipulation von Variablen außerhalb des aktuellen scopes (welcher im Übrigen immer local scope genannt wird). Eine Folge von dieser Architektur ist, dass in mehreren scopes Variablen mit dem gleichen Namen existieren und unterschiedliche Werte haben können. Ein Beispiel veranschaulicht das.

1
2
3
4
5
6
7
8
9
10
1.    function Show-Var
2.    {
3.        $var=123
4.        $var
5.        $Script:var
6.    }
7.  
8.    $var="abc"
9.    $var
10.    Show-Var

In diesem Skriptschnipsel wird zunächst eine Funktion definiert (zum Thema Funktionen siehe Kapitel 4). Diese Funktion erzeugt (durch Zuweisung) die Variable $var mit dem Wert 123. Anschließend wird der Variableninhalt ausgegeben (Zeile 4). In Zeile 5 wird der Inhalt der Variablen $var aus dem script scope ausgegeben ($Script:var), danach endet die Funktion. Im eigentlichen Skript (ab Zeile 8) wird die Variable $var mit dem Wert abc belegt und anschließend auf dem Bildschirm ausgegeben. Danach wird die im Vorfeld definierte Funktion aufgerufen. Das Skript liefert folgende Ausgabe:

1
2
3
1.    abc
2.    123
3.    abc

Hier mag etwas verwirrend sein, dass innerhalb der Funktion auf „etwas“ zugegriffen wird, was noch nicht existiert ($Script:var). Dies resultiert lediglich aus der Tatsache, dass innerhalb von PowerShell Skripten Funktionen definiert werden müssen, bevor sie aufgerufen werden, d.h. nicht an jeder beliebigen Stelle im Skript stehen dürfen. Die Ausgabe im obigen Beispiel wird jeweils durch die Zeilen 9, 4 und 5 des Skriptes verursacht. Das Cmdlet Get-Variable unterstützt den Parameter „-Scope“, mit dem der Scope einer Variablen überprüft werden kann.

Das Thema Variablen und Scopes ist noch etwas komplexer als hier dargestellt. Folgende Befehle in der PowerShell geben zusätzliche Informationen zu dem Thema:

1
2
3
4
1.    Get-Help variable
2.    Get-Help about_Variables
3.    Get-Help about_Automatic_Variables
4.    Get-Help about_Scopes

„Obwohl das immer wesentlich mehr Tipparbeit bedeutet, es empfiehlt sich immer, sprechende Namen für die Variablen zu vergeben. Das trägt wesentlich zur Verbesserung der Lesbarkeit von Skripten bei. Besonders bei langen und komplexeren Skripten macht sich die Zusatzarbeit bezahlt!“