Freigeben über


8. Erklärungen

Redaktionelle Notiz

Wichtig

Die Windows PowerShell Language Specification 3.0 wurde im Dezember 2012 veröffentlicht und basiert auf Windows PowerShell 3.0. Diese Spezifikation spiegelt nicht den aktuellen Status von PowerShell wider. Es ist nicht geplant, diese Dokumentation zu aktualisieren, um den aktuellen Zustand widerzuspiegeln. Diese Dokumentation wird hier zur historischen Referenz vorgestellt.

Das Spezifikationsdokument steht als Microsoft Word-Dokument vom Microsoft Download Center unter: https://www.microsoft.com/download/details.aspx?id=36389 Dieses Word-Dokument wurde hier auf Microsoft Learn zur Präsentation konvertiert. Während der Konvertierung wurden einige redaktionelle Änderungen vorgenommen, um die Formatierung für die Docs-Plattform zu berücksichtigen. Einige Tippfehler und kleinere Fehler wurden korrigiert.

8.1 Anweisungsblöcke und -listen

Syntax:

Tipp

Die ~opt~ Notation in den Syntaxdefinitionen gibt an, dass die lexikalische Entität in der Syntax optional ist.

statement-block:
    new-lines~opt~ { statement-list~opt~ new-lines~opt~ }

statement-list:
    statement
    statement-list statement

statement:
    if-statement
    label~opt~ labeled-statement
    function-statement
    flow-control-statement statement-terminator
    trap-statement
    try-statement
    data-statement
    inlinescript-statement
    parallel-statement
    sequence-statement
    pipeline statement-terminator

statement-terminator:
    ;
    new-line-character

Beschreibung:

Eine -Anweisung gibt eine Art von Aktion an, die ausgeführt werden soll. Sofern nicht in dieser Klausel anders angegeben, werden Anweisungen in lexikalischer Reihenfolge ausgeführt.

Mit einem statement-block kann ein Satz von Anweisungen in einer einzelnen syntaktischen Einheit gruppiert werden.

8.1.1 Anweisungen mit Bezeichnung

Syntax:

labeled-statement:
    switch-statement
    foreach-statement
    for-statement
    while-statement
    do-statement

Beschreibung:

Einer Iterationsanweisung (§8.4) oder einer Switch-Anweisung (§8.6) kann optional unmittelbar eine Anweisungsbezeichnung label vorangestellt werden. Eine Anweisungsbezeichnung wird als optionales Ziel einer Break-Anweisung (§8.5.1) oder Continue-Anweisung (§8.5.2) verwendet. Eine Beschriftung ändert jedoch nicht den Steuerungsfluss.

Leerraum zwischen dem Doppelpunkt (:) und dem darauf folgenden Token ist nicht zulässig.

Beispiele

:go_here while ($j -le 100) {
    # ...
}

:labelA
for ($i = 1; $i -le 5; ++$i) {
    :labelB
    for ($j = 1; $j -le 3; ++$j) {
        :labelC
        for ($k = 1; $k -le 2; ++$k) {
            # ...
        }
    }
}

8.1.2 Anweisungswerte

Der Wert einer Anweisung ist der kumulative Satz von Werten, den sie in die Pipeline schreibt. Wenn die Anweisung einen einzelnen skalaren Wert schreibt, ist dies der Wert der Anweisung. Wenn die Anweisung mehrere Werte schreibt, ist der Wert der Anweisung der Satz von Werten, die in Elementen eines nicht eingeschränkten 1dimensionalen Arrays gespeichert sind, in der Reihenfolge, in der sie geschrieben wurden. Betrachten Sie das folgende Beispiel:

$v = for ($i = 10; $i -le 5; ++$i) { }

Es gibt keine Iterationen der Schleife, und es wird nichts in die Pipeline geschrieben. Der Wert der Anweisung ist $null.

$v = for ($i = 1; $i -le 5; ++$i) { }

Trotz fünf Schleifendurchläufen wird nichts in die Pipeline geschrieben. Der Wert der Anweisung ist $null.

$v = for ($i = 1; $i -le 5; ++$i) { $i }

Es finden fünf Schleifendurchläufe statt, und jedes Mal wird der int-Wert $i in die Pipeline geschrieben. Der Wert der Anweisung ist object[] von Länge 5.

$v = for ($i = 1; $i -le 5; ) { ++$i }

Trotz fünf Schleifendurchläufen wird nichts in die Pipeline geschrieben. Der Wert der Anweisung ist $null.

$v = for ($i = 1; $i -le 5; ) { (++$i) }

Es finden fünf Schleifendurchläufe statt, wobei jeder Wert in die Pipeline geschrieben wird. Der Wert der Anweisung ist object[] von Länge 5.

$i = 1; $v = while ($i++ -lt 2) { $i }

Die Schleife wird einmal durchlaufen. Der Wert der Anweisung ist der int-Wert 2.

Hier sind einige weitere Beispiele:

# if $count is not currently defined then define it with int value 10
$count = if ($count -eq $null) { 10 } else { $count }

$i = 1
$v = while ($i -le 5) {
    $i                   # $i is written to the pipeline
    if ($i -band 1) {

        "odd"            # conditionally written to the pipeline

    }

    ++$i                 # not written to the pipeline

}
# $v is object[], Length 8, value 1,"odd",2,3,"odd",4,5,"odd"

8.2 Pipelineanweisungen

Syntax:

pipeline:
    assignment-expression
    expression redirections~opt~ pipeline-tail~opt~
    command verbatim-command-argument~opt~ pipeline-tail~opt~

assignment-expression:
    expression assignment-operator statement

pipeline-tail:
    | new-lines~opt~ command
    | new-lines~opt~ command pipeline-tail

command:
    command-name command-elements~opt~
    command-invocation-operator command-module~opt~ command-name-expr command-elements~opt~

command-invocation-operator: one of
    &   .

command-module:
    primary-expression

command-name:
    generic-token
    generic-token-with-subexpr

generic-token-with-subexpr:
    No whitespace is allowed between ) and command-name.
    generic-token-with-subexpr-start statement-list~opt~ )

command-namecommand-name-expr:
    command-name

primary-expressioncommand-elements:
    command-element
    command-elements command-element

command-element:
    command-parameter
    command-argument
    redirection

command-argument:
    command-name-expr

verbatim-command-argument:
    --% verbatim-command-argument-chars

Beschreibung:

redirections wird in §7.12 erläutert, assignment-expression in §7.11 und der command-invocation-operator-Punkt (.) in §3.5.5. Eine Erläuterung der Argument-zu-Parameter-Zuordnung in Befehlsaufrufen finden Sie unter §8.14.

Der erste Befehl in einer Pipeline ist ein Ausdruck oder ein Befehlsaufruf. In der Regel beginnt ein Befehlsaufruf mit einem command-name, bei dem es sich in der Regel um einen reinen Bezeichner handelt. Befehlselemente die Argumentliste für den Befehl darstellt. Ein Zeilenvorschubzeichen oder ein Semikolon ohne Escapezeichen beendet eine Pipeline.

Ein Befehlsaufruf besteht aus dem Namen des Befehls gefolgt von null oder mehr Argumenten. Die Regeln für Argumente sind wie folgt:

  • Ein Argument, das kein Ausdruck ist, aber beliebiger Text ohne unformatierte Leerzeichen enthält, wird so behandelt, als wäre es doppelt zitiert. Die Groß-/Kleinschreibung wird beibehalten.

  • Variablenersetzung und Erweiterung des Teilausdrucks (§2.3.5.2) erfolgen in expandable-string-literal und expandable-here-string-literal.

  • Text in Anführungszeichen ermöglicht, führende, nachfolgende und eingebettete Leerzeichen in den Wert des Arguments aufzunehmen. [Hinweis: Das Vorhandensein von Leerzeichen in einem zitierten Argument wandelt kein einzelnes Argument in mehrere Argumente um. Ende des Hinweises]

  • Wenn Sie Klammern um ein Argument setzen, bewirkt dies, dass der Ausdruck ausgewertet wird, wobei das Ergebnis anstelle des Texts des ursprünglichen Ausdrucks übergeben wird.

  • Um ein Argument zu übergeben, das wie ein Schalterparameter aussieht (§2.3.4), aber nicht als solches vorgesehen ist, schließen Sie dieses Argument in Anführungszeichen ein.

  • Wenn Sie ein Argument angeben, das einem Parameter entspricht, der die [switch] Typeinschränkung aufweist (§8.10.5), bewirkt das Vorhandensein des Argumentnamens allein, dass dieser Parameter auf $truefestgelegt wird. Der Wert des Parameters kann jedoch explizit festgelegt werden, indem ein Suffix an das Argument angefügt wird. Beispiel: Bei einem Parameter p mit Typeinschränkung legt ein Argument -p:$true p auf True fest, -p:$false hingegen auf False.

  • Ein Argument von -- gibt an, dass alle darauf folgenden Argumente in ihrer tatsächlichen Form übergeben werden müssen, als ob doppelte Anführungszeichen um sie herum platziert wurden.

  • Ein Argument von --% gibt an, dass alle darauf folgenden Argumente mit minimaler Analyse und Verarbeitung übergeben werden müssen. Dieses Argument wird als verbatim-Parameter bezeichnet. Argumente nach dem Verbatim-Parameter sind keine PowerShell-Ausdrücke, auch wenn sie syntaktisch gültige PowerShell-Ausdrücke sind.

Wenn der Befehlstyp "Application" lautet, wird der Parameter --% nicht an den Befehl übergeben. Die Argumente nach --% haben alle Umgebungsvariablen (Zeichenfolgen, die von %umgeben sind) erweitert. Beispiel:

echoargs.exe --% "%path%" # %path% is replaced with the value $Env:path

Die Reihenfolge der Auswertung von Argumenten ist nicht angegeben.

Informationen zur Parameterbindung finden Sie unter §8.14. Informationen zur Namenssuche finden Sie unter §3.8.

Nachdem die Argumentverarbeitung abgeschlossen wurde, wird der Befehl aufgerufen. Wenn der aufgerufene Befehl normal beendet wird (§8.5.4), wird die Kontrolle an den Punkt im Skript oder in der Funktion zurückgegeben, der unmittelbar nach dem Aufruf des Befehls folgt. Eine Beschreibung des Verhaltens bei einer abnormen Beendigung finden Sie unter break (§8.5.1), continue (§8.5.2), throw (§8.5.3), exit (§8.5.5), try (§8.7) und trap (§8.8).

Normalerweise wird ein Befehl aufgerufen, indem man seinen Namen gefolgt von Argumenten verwendet. Der Befehlsaufrufoperator &kann jedoch verwendet werden. Wenn der Befehlsname Leerzeichen ohne Escapezeichen enthält, muss er in Anführungszeichen gesetzt und mit diesem Operator aufgerufen werden. Da ein Skriptblock keinen Namen hat, muss er auch mit diesem Operator aufgerufen werden. Beispielsweise sind die folgenden Aufrufe eines Befehlsaufrufs Get-Factorial gleichwertig:

Get-Factorial 5
& Get-Factorial 5
& "Get-Factorial" 5

Direkte und indirekte rekursive Funktionsaufrufe sind zulässig. Zum Beispiel

function Get-Power([int]$x, [int]$y) {
    if ($y -gt 0) { return $x * (Get-Power $x (--$y)) }
    else { return 1 }
}

Beispiele

New-Object 'int[,]' 3,2
New-Object -ArgumentList 3,2 -TypeName 'int[,]'

dir E:\PowerShell\Scripts\*statement*.ps1 | ForEach-Object {$_.Length}

dir E:\PowerShell\Scripts\*.ps1 |
    Select-String -List "catch" |
    Format-Table Path, LineNumber -AutoSize

8.3 Die If-Anweisung

Syntax:

if-statement:
    if new-lines~opt~ ( new-lines~opt~ pipeline new-lines~opt~ ) statement-block
        elseif-clauses~opt~ else-clause~opt~

elseif-clauses:
    elseif-clause
    elseif-clauses elseif-clause

elseif-clause:
    new-lines~opt~ elseif new-lines~opt~ ( new-lines~opt~ pipeline new-lines~opt~ ) statement-block

else-clause:
    new-lines~opt~ else statement-block

Beschreibung:

Die steuernden pipeline-Ausdrücke müssen booleschen Typs oder implizit in diesen Typ konvertierbar sein. Die else-clause ist optional. Null (0) oder mehr Vorkommen der elseif-clause sind möglich.

Wenn der Test der pipeline der obersten Ebene True ergibt, wird ihr statement-block ausgeführt, und die Ausführung der Anweisung wird beendet. Andernfalls wird, wenn eine elseif-clause vorhanden ist und der Test ihrer pipeline True ergibt, ihr statement-block ausgeführt, und die Ausführung der Anweisung wird beendet. Andernfalls wird, wenn eine else-clause vorhanden ist, ihr statement-block ausgeführt.

Beispiele

$grade = 92
if ($grade -ge 90) { "Grade A" }
elseif ($grade -ge 80) { "Grade B" }
elseif ($grade -ge 70) { "Grade C" }
elseif ($grade -ge 60) { "Grade D" }
else { "Grade F" }

8.4 Iterationsanweisungen

8.4.1 Die While-Anweisung

Syntax:

while-statement:
    while new-lines~opt~ ( new-lines~opt~ while-condition new-lines~opt~ ) statement-block

while-condition:
    new-lines~opt~ pipeline

Beschreibung:

Der steuernde Ausdruck while-condition muss typ bool aufweisen oder implizit in diesen Typ konvertierbar sein. Der Schleifenkörper, der aus dem statement-block besteht, wird wiederholt ausgeführt, bis der steuernde Ausdruck das Ergebnis False ermittelt. Der steuernde Ausdruck wird vor jeder Ausführung des Schleifenkörpers ausgewertet.

Beispiele

$i = 1
while ($i -le 5) {                     # loop 5 times
    "{0,1}`t{1,2}" -f $i, ($i*$i)
    ++$i
}

8.4.2 Die Do-Anweisung

Syntax:

do-statement:
    do statement-block new-lines~opt~ while new-lines~opt~ ( while-condition new-lines~opt~ )
    do statement-block new-lines~opt~ until new-lines~opt~ ( while-condition new-lines~opt~ )

while-condition:
    new-lines~opt~ pipeline

Beschreibung:

Der steuernde Ausdruck while-condition muss typ bool aufweisen oder implizit in diesen Typ konvertierbar sein. In der while-Form wird der Schleifenkörper, der aus dem statement-block besteht, wiederholt ausgeführt, während der steuernde Ausdruck das Ergebnis True ermittelt. In der until-Form wird der Schleifenkörper wiederholt ausgeführt, bis der steuernde Ausdruck das Ergebnis True ermittelt. Der steuernde Ausdruck wird nach jeder Ausführung des Schleifenkörpers ausgewertet.

Beispiele

$i = 1
do {
    "{0,1}`t{1,2}" -f $i, ($i * $i)
}
while (++$i -le 5)                 # loop 5 times

$i = 1
do {
    "{0,1}`t{1,2}" -f $i, ($i * $i)
}
until (++$i -gt 5)                 # loop 5 times

8.4.3 Die For-Anweisung

Syntax:

for-statement:
    for new-lines~opt~ (
        new-lines~opt~ for-initializer~opt~ statement-terminator
        new-lines~opt~ for-condition~opt~ statement-terminator
        new-lines~opt~ for-iterator~opt~
        new-lines~opt~ ) statement-block

    for new-lines~opt~ (
        new-lines~opt~ for-initializer~opt~ statement-terminator
        new-lines~opt~ for-condition~opt~
        new-lines~opt~ ) statement-block

    for new-lines~opt~ (
        new-lines~opt~ for-initializer~opt~
        new-lines~opt~ ) statement-block

for-initializer:
    pipeline

for-condition:
    pipeline

for-iterator:
    pipeline

Beschreibung:

Der kontrollierende Ausdruck für die Bedingung muss vom Typ bool sein oder implizit in diesen Typ konvertierbar sein. Der Schleifenkörper, der aus dem statement-block besteht, wird wiederholt ausgeführt, während der steuernde Ausdruck das Ergebnis True ermittelt. Der steuernde Ausdruck wird vor jeder Ausführung des Schleifenkörpers ausgewertet.

Der Ausdruck for-initializer wird vor der ersten Auswertung des steuernden Ausdrucks ausgewertet. Der Ausdruck for-initializer wird nur für seine Nebenwirkungen ausgewertet. Jeder erzeugte Wert wird verworfen und nicht in die Pipeline geschrieben.

Der Ausdruck for-iterator wird nach jeder Ausführung des Schleifenkörpers ausgewertet. Der Ausdruck for-iterator wird nur für seine Nebenwirkungen ausgewertet. Jeder erzeugte Wert wird verworfen und nicht in die Pipeline geschrieben.

Wenn der Ausdruck for-condition ausgelassen wird, ermittelt der steuernde Ausdruck das Ergebnis True.

Beispiele

for ($i = 5; $i -ge 1; --$i) { # loop 5 times
    "{0,1}`t{1,2}" -f $i, ($i * $i)
}

$i = 5
for (; $i -ge 1; ) { # equivalent behavior
    "{0,1}`t{1,2}" -f $i, ($i * $i)
    --$i
}

8.4.4 Die Foreach-Anweisung

Syntax:

foreach-statement:
    foreach new-lines~opt~ foreach-parameter~opt~ new-lines~opt~
        ( new-lines~opt~ variable new-lines~opt~ *in* new-lines~opt~ pipeline
        new-lines~opt~ ) statement-block

foreach-parameter:
    -parallel

Beschreibung:

Der Schleifenkörper, der aus dem statement-block besteht, wird für jedes Element ausgeführt, das von der Variablen variable in der von pipeline bestimmten Sammlung bestimmt wird. Der Gültigkeitsbereich der -Variablen ist nicht auf die foreach-Anweisung beschränkt. Daher behält sie ihren endgültigen Wert bei, nachdem die Ausführung des Schleifenkörpers abgeschlossen ist. Wenn Pipeline einen Skalar (mit Ausnahme des Werts $null) anstelle einer Auflistung angibt, wird dieser Skalar als Eine Sammlung eines Elements behandelt. Wenn Pipeline den Wert $nullbestimmt, wird Pipeline als Eine Sammlung von Nullelementen behandelt.

Wenn der foreach-parameter-parallel angegeben wird, ist das Verhalten implementierungsdefiniert.

Der foreach-Parameter‑parallel ist nur in einem Workflow zulässig (§8.10.2).

Jede Foreach-Anweisung verfügt über einen eigenen Enumerator $foreach (§2.3.2.2, §4.5.16), der nur während der Ausführung dieser Schleife vorhanden ist.

Die von der pipeline erzeugten Objekte werden gesammelt, bevor der statement-block mit der Ausführung beginnt. Mit dem ForEach-Object-Cmdlet wird jedoch der statement-block für jedes Objekt ausgeführt, während es erstellt wird.

Beispiele

$a = 10, 53, 16, -43
foreach ($e in $a) {
    ...
}
$e # the int value -43

foreach ($e in -5..5) {
    ...
}

foreach ($t in [byte], [int], [long]) {
    $t::MaxValue # get static property
}

foreach ($f in Get-ChildItem *.txt) {
    ...
}

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }
foreach ($e in $h1.Keys) {
    "Key is " + $e + ", Value is " + $h1[$e]
}

8.5 Flusssteuerungsanweisungen

Syntax:

flow-control-statement:
    break label-expression~opt~
    continue label-expression~opt~
    throw pipeline~opt~
    return pipeline~opt~
    exit pipeline~opt~

label-expression:
    simple-name
    unary-expression

Beschreibung:

Eine Ablaufsteuerungsanweisung bewirkt eine bedingungslose Übertragung der Kontrolle an einen anderen Ort.

8.5.1 Die Break-Anweisung

Beschreibung:

Eine Break-Anweisung mit label-expression wird als bezeichnete Break-Anweisung bezeichnet. Eine Break-Anweisung ohne label-expression wird als nicht bezeichnete Break-Anweisung bezeichnet.

Außerhalb einer Trap-Anweisung beendet eine nicht bezeichnete Break-Anweisung direkt innerhalb einer Iterationsanweisung (§8.4) die Ausführung dieser kleinsten einschließenden Iterationsanweisung. Eine nicht bezeichnete Break-Anweisung direkt in einer Switch-Anweisung (§8.6) beendet den Musterabgleich für die switch-condition des aktuellen „switch“. Ausführliche Informationen zur Verwendung von „break“ in einer Trap-Anweisung finden Sie unter (§8.8).

Einer Iterations- oder Switch-Anweisung kann optional unmittelbar eine Anweisungsbezeichnung vorangestellt werden (§8.1.1). Eine solche Anweisungsbezeichnung kann als Ziel einer bezeichneten Break-Anweisung verwendet werden. In diesem Fall beendet diese Anweisung die Ausführung der anvisierten einschließenden Iterationsanweisung.

Eine bezeichnete Break-Anweisung muss in keinem lokalen Bereich aufgelöst werden. Die Suche nach einer übereinstimmenden Bezeichnung kann auch über Skript- und Funktionsaufrufgrenzen hinweg den Aufrufstapel hinauf fortgesetzt werden. Wenn keine übereinstimmende Bezeichnung gefunden wird, wird der aktuelle Befehlsaufruf beendet.

Der Name der durch label-expression angegebenen Bezeichnung muss keinen konstanten Wert aufweisen.

Wenn label-expression ein unary-expression ist, wird er in eine Zeichenfolge konvertiert.

Beispiele

$i = 1
while ($true) { # infinite loop
    if ($i * $i -gt 100) {
        break # break out of current while loop
    }
    ++$i
}

$lab = "go_here"
:go_here
for ($i = 1; ; ++$i) {
    if ($i * $i -gt 50) {
        break $lab # use a string value as target
    }
}

:labelA
for ($i = 1; $i -le 2; $i++) {

    :labelB
    for ($j = 1; $j -le 2; $j++) {

        :labelC
        for ($k = 1; $k -le 3; $k++) {
            if (...) { break labelA }
        }
    }
}

8.5.2 Die Continue-Anweisung

Beschreibung:

Eine continue-Anweisung mit label-expression wird als bezeichnete Continue-Anweisung bezeichnet. Eine Continue-Anweisung ohne label-expression wird als nicht bezeichnete Continue-Anweisung bezeichnet.

Die Verwendung continue von einer Trap-Anweisung aus wird in §8.8erläutert.

Eine nicht bezeichnete continue-Anweisung innerhalb einer Schleife beendet die Ausführung der aktuellen Schleife und überträgt die Steuerung an die schließende geschweifte Klammer der kleinsten einschließenden Iterationsanweisung (§8.4). Eine nicht bezeichnete continue-Anweisung innerhalb eines „switch“ beendet die Ausführung der aktuellen switch-Iteration und überträgt die Steuerung an die switch-condition des kleinsten einschließenden switch (§8.6).

Einer Iterationsanweisung oder einer switch Anweisung (§8.6) kann optional sofort eine Anweisungsbezeichnung vorangestellt werden (§8.1.1). Eine solche Anweisungsbezeichnung kann als Ziel einer eingeschlossenen bezeichneten continue-Anweisung verwendet werden. In diesem Fall beendet diese Anweisung die Ausführung der aktuellen Schleife oder switch-Iteration und überträgt die Steuerung an die anvisierte einschließende Iteration oder switch-Anweisungsbezeichnung.

Ein bezeichnetes continue muss in keinem lokalen Bereich aufgelöst werden. Die Suche nach einer übereinstimmenden Bezeichnung kann auch über Skript- und Funktionsaufrufgrenzen hinweg den Aufrufstapel hinauf fortgesetzt werden (continue). Wenn keine übereinstimmende Bezeichnung gefunden wird, wird der aktuelle Befehlsaufruf beendet.

Der Name der durch label-expression angegebenen Bezeichnung muss keinen konstanten Wert aufweisen.

Wenn label-expression ein unary-expression ist, wird er in eine Zeichenfolge konvertiert.

Beispiele

$i = 1
while (...) {
    ...
    if (...) {
        continue # start next iteration of current loop
    }
    ...
}

$lab = "go_here"
:go_here
for (...; ...; ...) {
    if (...) {
        continue $lab # start next iteration of labeled loop
    }
}

:labelA
for ($i = 1; $i -le 2; $i++) {

    :labelB
    for ($j = 1; $j -le 2; $j++) {

        :labelC
        for ($k = 1; $k -le 3; $k++) {
            if (...) { continue labelB }
        }
    }
}

8.5.3 Die Throw-Anweisung

Beschreibung:

Eine Ausnahme ist eine Möglichkeit zum Behandeln einer System- oder Anwendungsfehlerbedingung. Die Throw-Anweisung löst eine Ausnahme aus. (Eine Erläuterung zur Ausnahmebehandlung finden Sie unter §8.7.)

Wenn die pipeline ausgelassen wird und die Throw-Anweisung nicht in einer catch-clause enthalten ist, ist das Verhalten implementierungsdefiniert. Wenn die pipeline vorhanden ist und die Throw-Anweisung sich in einer catch-clause befindet, wird die Ausnahme, die von dieser catch-clause abgefangen wurde, erneut ausgelöst, nachdem eine finally-clause ausgeführt wurde, die der catch-clause zugeordnet ist.

Wenn die pipeline vorhanden ist, ist der Typ der ausgelösten Ausnahme implementierungsdefiniert.

Wenn eine Ausnahme ausgelöst wird, wird die Steuerung an die erste Catch-Klausel in einer einschließenden Try-Anweisung übertragen, die die Ausnahme behandeln kann. Die Position, an der die Ausnahme anfänglich ausgelöst wird, wird als Wurfpunktbezeichnet. Sobald eine Ausnahme ausgelöst wird, werden die in §8.7 beschriebenen Schritte wiederholt befolgt, bis eine Catch-Klausel, die der Ausnahme entspricht, gefunden wird oder keine gefunden werden kann.

Beispiele

throw
throw 100
throw "No such record in file"

Wenn die pipeline ausgelassen wird und die Throw-Anweisung nicht aus einer catch-clause stammt, wird der Text „ScriptHalted“ in die Pipeline geschrieben, und der Typ der ausgelösten Ausnahme ist System.Management.Automation.RuntimeException.

Wenn die -Pipeline vorhanden ist, wird die Ausnahme in ein Objekt vom Typ System.Management.Automation.RuntimeExceptioneingeschlossen, das Informationen zur Ausnahme als System.Management.Automation.ErrorRecord-Objekt enthält, die über $_zugänglich sind.

Beispiel 1: throw 123 führt zu einer Ausnahme vom Typ RuntimeException. $_.TargetObject enthält das umschlossene Objekt aus dem Catch-Block, in diesem Fall ein System.Int32 mit dem Wert 123.

Beispiel 2: throw "xxx" führt zu einer Ausnahme vom Typ RuntimeException. $_.TargetObject enthält das umschlossene Objekt aus dem Catch-Block, in diesem Fall ein System.String mit dem Wert „xxx“.

Beispiel 3: throw 10,20 führt zu einer Ausnahme vom Typ RuntimeException. $_.TargetObject enthält das umschlossene Objekt aus dem Catch-Block, in diesem Fall ein System.Object[], ein uneingeschränktes Array von zwei Elementen mit den System.Int32-Werten 10 und 20.

8.5.4 Die Return-Anweisung

Beschreibung:

Die return-Anweisung schreibt den/die von Pipelinefestgelegten Wert(e) (falls vorhanden) in die Pipeline und gibt die Steuerung an den Aufrufer der Funktion oder des Skripts zurück. Eine Funktion oder ein Skript kann 0 (null) oder mehr return-Anweisungen enthalten.

Wenn die Ausführung die schließende geschweifte Klammer einer Funktion erreicht, wird ein implizites return ohne pipeline angenommen.

Die return-Anweisung ist ein wenig „syntaktisches Zuckerbrot“, damit sich Programmierer so ausdrücken können wie in anderen Sprachen. Eine Funktion oder ein Skript geben jedoch tatsächlich alle Werte, die von dieser Funktion oder diesem Skript in die Pipeline geschrieben werden, sowie alle Werte, die von pipeline angegeben werden, als Wert zurück. Wenn nur ein skalarer Wert in die Pipeline geschrieben wird, ist sein Typ der Typ des zurückgegebenen Werts. Andernfalls ist der Rückgabetyp ein uneingeschränktes Array, das alle in die Pipeline geschriebenen Werte enthält.

Beispiele

function Get-Factorial ($v) {
    if ($v -eq 1) {
        return 1 # return is not optional
    }

    return $v * (Get-Factorial ($v - 1)) # return is optional
}

Der Aufrufer von Get-Factorial erhält ein int zurück.

function Test {
    "text1" # "text1" is written to the pipeline
    # ...
    "text2" # "text2" is written to the pipeline
    # ...
    return 123 # 123 is written to the pipeline
}

Der Anrufer von Test erhält ein nicht eingeschränktes 1-dimensionales Array mit drei Elementen zurück.

8.5.5 Die Exit-Anweisung

Beschreibung:

Die Exit-Anweisung beendet das aktuelle Skript und gibt die Steuerung und einen Beendigungscode an die Hostumgebung oder das aufrufende Skript zurück. Wenn pipeline angegeben wird, wird der dort festgelegte Wert bei Bedarf in „int“ konvertiert. Wenn keine solche Konvertierung vorhanden ist oder Pipeline weggelassen wird, wird der Int-Wert Null zurückgegeben.

Beispiele

exit $count # terminate the script with some accumulated count

8.6 Die Switch-Anweisung

Syntax:

switch-statement:
    switch new-lines~opt~ switch-parameters~opt~ switch-condition switch-body

switch-parameters:
    switch-parameter
    switch-parameters switch-parameter

switch-parameter:
    -Regex
    -Wildcard
    -Exact
    -CaseSensitive
    -Parallel

switch-condition:
    ( new-lines~opt~ pipeline new-lines~opt~ )
    -File new-lines~opt~ switch-filename

switch-filename:
    command-argument
    primary-expression

switch-body:
    new-lines~opt~ { new-lines~opt~ switch-clauses }

switch-clauses:
    switch-clause
    switch-clauses switch-clause

switch-clause:
    switch-clause-condition statement-block statement-terimators~opt~

switch-clause-condition:
    command-argument
    primary-expression

Beschreibung:

Wenn Umschaltbedingung einen einzelnen Wert angibt, wird die Kontrolle an einen oder mehrere übereinstimmende Musteranweisungsblöcke übergeben. Wenn keine Muster übereinstimmen, können einige Standardaktionen ausgeführt werden.

Eine Switch-Anweisung muss mindestens eine switch-clause enthalten, die jeweils mit einem Muster (einer nicht standardmäßigen Switch-Klausel) oder dem Schlüsselwort default (einer standardmäßigen Switch-Klausel) beginnt. Eine Switch-Anweisung muss null (0) oder eine standardmäßige Switch-Klausel (default) und null (0) oder mehr nicht standardmäßige Switch-Klauseln enthalten. Switch-Klauseln können in beliebiger Reihenfolge geschrieben werden.

Mehrere Muster haben möglicherweise denselben Wert. Ein Muster muss kein Literal sein, und ein Schalter kann Muster mit unterschiedlichen Typen aufweisen.

Wenn der Wert von switch-condition einem Musterwert entspricht, wird der statement-block dieses Musters ausgeführt. Wenn mehrere Musterwerte mit dem Wert von switch-condition übereinstimmen, wird in lexikalischer Reihenfolge der statement-block jedes übereinstimmenden Musters ausgeführt, es sei denn, eines dieser statement-block-Vorkommen enthält eine break-Anweisung (§8.5.1).

Wenn der Wert der -Schalterbedingung keinem Musterwert entspricht und eine default-Schalterklausel vorhanden ist, wird der -Anweisungsblock ausgeführt; andernfalls wird der Musterabgleich für diese -Schalterbedingung beendet.

Switches können geschachtelt sein, wobei jeder Switch über einen eigenen Satz von Switch-Klauseln verfügt. In solchen Fällen gehört eine switch-Klausel zur innersten Switch-Anweisung, die sich derzeit im Bereich befindet.

Beim Eintritt in jeden -Anweisungsblock-wird $_ automatisch der Wert der -Schaltbedingung- zugewiesen, die dazu führte, dass die Steuerung zu diesem -Anweisungsblock-wechselte. $_ ist auch in der switch-clause-condition dieses statement-block verfügbar.

Der Abgleich von Nicht-Zeichenfolgen erfolgt durch Testen auf Gleichheit (§7.8.1).

Wenn der Abgleich Zeichenfolgen umfasst, wird die Groß-/Kleinschreibung beim Vergleich standardmäßig nicht beachtet. Wenn der switch-parameter-CaseSensitive vorhanden ist, wird die Groß-/Kleinschreibung beim Vergleich beachtet.

Ein Muster kann Platzhalterzeichen (§3.15) enthalten, in diesem Fall werden Vergleiche von Platzhalterzeichenfolgen durchgeführt, jedoch nur, wenn der Switch-Parameter-Wildcard vorhanden ist. Standardmäßig wird Groß-/Kleinschreibung beim Vergleich nicht unterschieden.

Ein Muster kann einen regulären Ausdruck (§3.16) enthalten, in diesem Fall werden Zeichenfolgenvergleiche für reguläre Ausdrücke ausgeführt, jedoch nur, wenn der Switch-Parameter vorhanden-Regex ist. Standardmäßig wird Groß-/Kleinschreibung beim Vergleich nicht unterschieden. Wenn -Regex vorhanden ist und ein Muster übereinstimmt, wird $Matches im -Schalterklausel---Anweisungsblock für dieses Muster definiert.

Ein switch-parameter kann abgekürzt werden. Jeder unterschiedliche vordere Teil eines Parameters kann verwendet werden. Beispielsweise sind ‑Regex, ‑Rege, ‑Reg, ‑Reund ‑R gleichwertig.

Wenn in Konflikt stehende switch-parameter angegeben werden, hat der lexikalisch letzte den Vorrang. Das Vorhandensein von ‑Exact deaktiviert -Regex und -Wildcard; sie hat jedoch keine Auswirkungen auf ‑Case.

Wenn der switch-Parameter‑Parallel angegeben wird, ist das Verhalten implementierungsabhängig definiert.

Der Schalterparameter‑Parallel ist nur in einem Workflow zulässig (§8.10.2).

Wenn es sich bei einem Muster um einen Skriptblockausdruckhandelt, wird dieser Block ausgewertet, und das Ergebnis wird bei Bedarf in bool konvertiert. Wenn das Ergebnis den Wert $truehat, wird der entsprechende -Anweisungsblock ausgeführt; andernfalls wird er nicht ausgeführt.

Wenn Schalterbedingung mehrere Werte angibt, wird der Schalter auf jeden Wert in lexikalischer Reihenfolge angewendet, indem die oben beschriebenen Regeln für eine Switch-Bedingung verwendet werden, die einen einzelnen Wert angibt. Jede Switch-Anweisung hat einen eigenen Enumerator, $switch (§2.3.2.2, §4.5.16), das nur während der Ausführung dieses Schalters vorhanden ist.

Eine Switch-Anweisung kann eine Bezeichnung haben und bezeichnete und nicht bezeichnete Break- und Continue-Anweisungen (§8.5.1 und §8.5.2) enthalten.

Wenn switch-condition gleich -Fileswitch-filename ist, führt die Switch-Anweisung Iterationen über die Werte in der durch switch-filename festgelegten Datei durch, anstatt Iterationen über die Werte in einem Ausdruck durchzuführen. Die Datei wird Zeile für Zeile gelesen, wobei jede Zeile einen Wert enthält. Zeilentrennzeichen sind in den Werten nicht enthalten.

Beispiele

$s = "ABC def`nghi`tjkl`fmno @#$"
$charCount = 0; $pageCount = 0; $lineCount = 0; $otherCount = 0
for ($i = 0; $i -lt $s.Length; ++$i) {
    ++$charCount
    switch ($s[$i]) {
        "`n" { ++$lineCount }
        "`f" { ++$pageCount }
        "`t" { }
        " " { }
        default { ++$otherCount }
    }
}

switch -Wildcard ("abc") {
    a* { "a*, $_" }
    ?B? { "?B? , $_" }
    default { "default, $_" }
}

switch -Regex -CaseSensitive ("abc") {
    ^a* { "a*" }
    ^A* { "A*" }
}

switch (0, 1, 19, 20, 21) {
    { $_ -lt 20 } { "-lt 20" }
    { $_ -band 1 } { "Odd" }
    { $_ -eq 19 } { "-eq 19" }
    default { "default" }
}

8.7 Die Try/Finally-Anweisung

Syntax:

try-statement:
    try statement-block catch-clauses
    try statement-block finally-clause
    try statement-block catch-clauses finally-clause

catch-clauses:
    catch-clause
    catch-clauses catch-clause

catch-clause:
    new-lines~opt~ catch catch-type-list~opt~
    statement-block

catch-type-list:
    new-lines~opt~ type-literal
    catch-type-list new-lines~opt~ , new-lines~opt~

type-literalfinally-clause:
    new-lines~opt~ finally statement-block

Beschreibung:

Die try-Anweisung bietet einen Mechanismus zum Abfangen von Ausnahmen, die während der Ausführung eines Blocks auftreten. Die try-Anweisung bietet auch die Möglichkeit, einen Codeblock anzugeben, der immer ausgeführt wird, wenn das Steuerelement die Try-Anweisung verlässt. Das Auslösen einer Ausnahme über die Throw-Anweisung wird in §8.5.3beschrieben.

Ein Try-Block ist der statement-block, der der Try-Anweisung zugeordnet ist. Ein Catch-Block ist der statement-block, der einer catch-clause zugeordnet ist. Ein Finally-Block ist der statement-block, der einer finally-clause zugeordnet ist.

Eine catch-clause ohne catch-type-list wird als allgemeine Catch-Klausel bezeichnet.

Jede catch-clause ist ein Ausnahmehandler, und eine catch-clause, deren catch-type-list den Typ der ausgelösten Ausnahme enthält, ist eine übereinstimmende Catch-Klausel. Eine allgemeine Catch-Klausel stimmt mit allen Ausnahmetypen überein.

catch-clause und finally-clause sind zwar optional, aber eine davon muss mindestens vorhanden sein.

Die Verarbeitung einer ausgelösten Ausnahme besteht darin, die folgenden Schritte wiederholt auszuwerten, bis eine Catch-Klausel gefunden wird, die der Ausnahme entspricht.

  • Im aktuellen Bereich wird jede Try-Anweisung untersucht, die den Throw-Punkt einschließt. Für jede try-Anweisung S, beginnend mit der innersten try-Anweisung und endend mit der äußersten Try-Anweisung, werden die folgenden Schritte ausgewertet:

    • Wenn der try Block von S den Wurfpunkt einschließt und wenn S eine oder mehrere Catch-Klauseln aufweist, werden die Catch-Klauseln in lexikalischer Reihenfolge untersucht, um einen geeigneten Handler für die Ausnahme zu finden. Die erste Catch-Klausel, die den Ausnahmetyp oder einen Basistyp des Ausnahmetyps angibt, wird als Übereinstimmung betrachtet. Eine allgemeine Catch-Klausel wird für jeden Ausnahmetyp als Übereinstimmung betrachtet. Wenn eine übereinstimmende Catch-Klausel gefunden wird, wird die Ausnahmeverarbeitung abgeschlossen, indem die Steuerung an den Block dieser Catch-Klausel übertragen wird. Innerhalb einer übereinstimmenden Catch-Klausel enthält die Variable $_ eine Beschreibung der aktuellen Ausnahme.

    • Wenn andernfalls der try Block oder ein catch Block von S den Wurfpunkt einschließt und wenn S einen finally-Block aufweist, wird das Steuerelement an den letzten Block übertragen. Wenn der finally-Block eine weitere Ausnahme auslöst, wird die Verarbeitung der aktuellen Ausnahme beendet. Andernfalls wird die Verarbeitung der aktuellen Ausnahme fortgesetzt, wenn das Steuerelement das Ende des finally Blocks erreicht.

  • Wenn sich ein Ausnahmehandler nicht im aktuellen Bereich befindet, werden die obigen Schritte für den eingeschlossenen Bereich mit einem Auslösenpunkt wiederholt, der der Anweisung entspricht, aus der der aktuelle Bereich aufgerufen wurde.

  • Wenn die Ausnahmeverarbeitung alle Bereiche beendet, was darauf hindeutet, dass für die Ausnahme kein Handler vorhanden ist, ist das Verhalten undefiniert.

Um nicht erreichbare Catch-Klauseln in einem Try-Block zu verhindern, gibt eine Catch-Klausel möglicherweise keinen Ausnahmetyp an, der einem Typ entspricht oder von einem Typ abgeleitet ist, der in einer früheren Catch-Klausel innerhalb dieses Try-Blocks angegeben wurde.

Die Anweisungen eines finally-Blocks werden immer ausgeführt, wenn das Steuerelement eine try-Anweisung verlässt. Dies gilt, ob die Steuerungsübertragung als Ergebnis einer normalen Ausführung auftritt, als Ergebnis der Ausführung einer break, continueoder return Anweisung oder aufgrund einer Ausnahme, die aus der try-Anweisung ausgelöst wird.

Wenn während der Ausführung eines finally Blocks eine Ausnahme ausgelöst wird, wird die Ausnahme an die nächste eingeschlossene try-Anweisung weitergeleitet. Wenn eine andere Ausnahme gerade behandelt wurde, geht diese Ausnahme verloren. Der Prozess der Generierung einer Ausnahme wird weiter in der Beschreibung der throw-Anweisung erläutert.

try Anweisungen können mit trap Anweisungen koexistieren; einzelheiten hierzu finden Sie unter §8.8.

Beispiele

$a = New-Object 'int[]' 10
$i = 20 # out-of-bounds subscript

while ($true) {
    try {
        $a[$i] = 10
        "Assignment completed without error"
        break
    }

    catch [IndexOutOfRangeException] {
        "Handling out-of-bounds index, >$_<`n"
        $i = 5
    }

    catch {
        "Caught unexpected exception"
    }

    finally {
        # ...
    }
}

Jede ausgelöste Ausnahme wird als System.Management.Automation.RuntimeException ausgelöst. Wenn typspezifische catch-clause-Vorkommen im try-Block enthalten sind, wird die InnerException-Eigenschaft der Ausnahme überprüft, um zu versuchen, eine Übereinstimmung zu finden, z. B. mit dem oben genannten Typ System.IndexOutOfRangeException.

8.8 Die Trap-Anweisung

Syntax:

trap-statement:
    *trap* new-lines~opt~ type-literal~opt~ new-lines~opt~ statement-block

Beschreibung:

Eine trap-Anweisung mit und ohne type-literal ist analog zu einem catch-Block (§8.7) mit und ohne catch-type-list, mit der Ausnahme, dass eine trap-Anweisung jeweils nur einen Typ abfangen kann.

Mehrere trap-Anweisungen können in demselben Anweisungsblockdefiniert werden, und ihre Definitionsreihenfolge ist irrelevant. Wenn zwei trap-Anweisungen mit demselben type-literal im gleichen Bereich definiert sind, wird die lexikalisch erste verwendet, um eine Ausnahme des übereinstimmenden Typs zu verarbeiten.

Im Gegensatz zu einem catch-Block stimmt eine trap-Anweisung exakt mit einem Ausnahmetyp überein; es wird kein abgeleiteter Typabgleich ausgeführt.

Wenn eine Ausnahme auftritt und keine übereinstimmende trap-Anweisung im aktuellen Bereich vorhanden ist, wird im umschließenden Bereich nach einer übereinstimmenden Trap-Anweisung gesucht. Dabei kann im aufrufenden Skript, der aufrufenden Funktion oder dem Filter und dann in deren Aufrufer usw. gesucht werden. Wenn die Suche alle Bereiche beendet und anzeigt, dass für die Ausnahme kein Handler vorhanden ist, ist das Verhalten nicht definiert.

Ein Anweisungskörper einer trap-Anweisung wird nur ausgeführt, um die entsprechende Ausnahme zu verarbeiten. Andernfalls wird er von der Ausführung übergangen.

Wenn der Anweisungskörper einer trap-Anweisung normal beendet wird, wird standardmäßig ein Fehlerobjekt in den Fehlerstream geschrieben, die Ausnahme als behandelt betrachtet und die Ausführung mit der Anweisung fortgesetzt, die unmittelbar auf die Anweisung im Bereich folgt, die die trap-Anweisung enthält, die die Ausnahme sichtbar gemacht hat. Die Ursache der Ausnahme könnte in einem Befehl liegen, den der Befehl aufruft, der die trap-Anweisung enthält.

Wenn die letzte Anweisung, die in einem Anweisungskörper einer trap-Anweisung ausgeführt wird, „continue“ lautet (§8.5.2), wird das Schreiben des Fehlerobjekts in den Fehlerstream unterdrückt, und die Ausführung mit der Anweisung fortgesetzt, die unmittelbar auf die Anweisung im Bereich folgt, die die Trap-Anweisung enthält, die die Ausnahme sichtbar gemacht hat. Wenn die letzte Anweisung, die in einem Anweisungskörper einer trap-Anweisung ausgeführt wird, „break“ lautet (§8.5.1), wird das Schreiben des Fehlerobjekts in den Fehlerstream unterdrückt und die Ausnahme erneut ausgelöst.

In einer trap Anweisung enthält die Variable $_ eine Beschreibung des aktuellen Fehlers.

Berücksichtigen Sie den Fall, in dem eine Ausnahme, die in einem try-Block ausgelöst wurde, keinen übereinstimmenden catch-Block aufweist, aber eine übereinstimmende trap-Anweisung auf einer höheren Blockebene vorhanden ist. Nach Ausführung der Finally-Klausel des try-Blocks erhält die trap-Anweisung auch dann die Steuerung, wenn ein übergeordneter Bereich über einen übereinstimmenden catch-Block verfügt. Wenn eine trap-Anweisung innerhalb des try-Blocks selbst definiert ist und dieser try-Block über einen übereinstimmenden catch-Block verfügt, übernimmt die trap-Anweisung die Steuerung.

Beispiele

Im folgenden Beispiel wird das Fehlerobjekt geschrieben und die Ausführung mit der Anweisung fortgesetzt, die unmittelbar auf die Anweisung folgt, die den Trap verursacht hat, d. h, „Fertig“ wird in die Pipeline geschrieben.

$j = 0; $v = 10/$j; "Done"
trap { $j = 2 }

Im folgenden Beispiel wird das Schreiben des Fehlerobjekts unterdrückt und die Ausführung mit der Anweisung fortgesetzt, die unmittelbar auf die Anweisung folgt, die den Trap verursacht hat, d. h, „Fertig“ wird in die Pipeline geschrieben.

$j = 0; $v = 10/$j; "Done"
trap { $j = 2; continue }

Im folgenden Beispiel wird das Schreiben des Fehlerobjekts unterdrückt und die Ausnahme erneut ausgelöst.

$j = 0; $v = 10/$j; "Done"
trap { $j = 2; break }

Im folgenden Beispiel befinden sich Trap und Ausnahme generierende Anweisungen im gleichen Bereich. Nach Erfassen und Behandeln der Ausnahme wird die Ausführung mit dem Schreiben von „1“ in die Pipeline fortgesetzt.

&{trap{}; throw '\...'; 1}

Im folgenden Beispiel befinden sich Trap und Ausnahme generierende Anweisungen in verschiedenen Bereichen. Nach Erfassen und Behandeln der Ausnahme wird die Ausführung mit dem Schreiben von „2“ (nicht „1“) in die Pipeline fortgesetzt.

trap{} &{throw '\...'; 1}; 2

8.9 Die Datenschutzerklärung

Syntax:

data-statement:
    data new-lines~opt~ data-name data-commands-allowed~opt~ statement-block

data-name:
    simple-name

data-commands-allowed:
    new-lines~opt~ -SupportedCommand data-commands-list

data-commands-list:
    new-lines~opt~ data-command
    data-commands-list , new-lines~opt~ data-command

data-command:
    command-name-expr

Beschreibung:

Eine Datendeklaration erstellt einen Datenabschnitt, wodurch die Daten dieses Abschnitts separat vom Code gehalten werden. Diese Trennung unterstützt Einrichtungen wie separate Zeichenfolgenressourcendateien für Text, z. B. Fehlermeldungen und Hilfezeichenfolgen. Sie unterstützt auch die Internationalisierung, indem es einfacher ist, Zeichenfolgen zu isolieren, zu finden und zu verarbeiten, die in verschiedene Sprachen übersetzt werden.

Ein Skript oder eine Funktion kann null oder mehr Datenabschnitte aufweisen.

Der -Anweisungsblock eines Datenabschnitts ist darauf beschränkt, nur die folgenden PowerShell-Features zu enthalten:

  • Alle Operatoren außer -match
  • Die Anweisung if
  • Die folgenden automatischen Variablen: $PSCulture, $PSUICulture, $true, $falseund $null.
  • Kommentare
  • Rohrleitungen
  • Durch Semikolons getrennte Anweisungen (;)
  • Literale
  • Aufrufe des ConvertFrom-StringData-Cmdlets
  • Alle anderen Cmdlets, die über den Parameter SupportedCommand identifiziert werden

Wenn das Cmdlet ConvertFrom-StringData verwendet wird, können die Schlüssel-Wert-Paare mithilfe einer beliebigen Form eines Zeichenfolgenliterals ausgedrückt werden. expandable-string-literal und expandable-here-string-literal dürfen jedoch keine Variablenersetzungen oder Teilausdruckerweiterungen enthalten.

Beispiele

Der parameter SupportedCommand gibt an, dass die angegebenen Cmdlets oder Funktionen nur Daten generieren. Der folgende Datenabschnitt enthält beispielsweise ein vom Benutzer geschriebenes Cmdlet, ConvertTo-Xml, das Daten in einer XML-Datei formatiert:

data -SupportedCommand ConvertTo-Xml {
    Format-Xml -Strings string1, string2, string3
}

Betrachten Sie das folgende Beispiel, in dem der Datenabschnitt einen ConvertFrom-StringData Befehl enthält, der die Zeichenfolgen in eine Hashtabelle konvertiert, deren Wert $messageszugewiesen ist.

$messages = data {
    ConvertFrom-StringData -StringData @'
    Greeting = Hello
    Yes = yes
    No = no
'@
}

Auf die Schlüssel und Werte der Hashtabelle wird über $messages.Greeting, $messages.Yesund $messages.Nozugegriffen.

Jetzt kann dies als englischsprachige Ressource gespeichert werden. Ressourcen für Deutsch- und Spanisch können in separaten Dateien mit den folgenden Datenabschnitten erstellt werden:

$messages = data {
    ConvertFrom-StringData -StringData @"
    Greeting = Guten Tag
    Yes = ja
    No = nein
"@
}

$messagesS = data {
    ConvertFrom-StringData -StringData @"
    Greeting = Buenos días
    Yes = sí
    No = no
"@
}

Wenn dataname vorhanden ist, wird die Variable (ohne Verwendung eines führenden $) benannt, in der der Wert der Datenanweisung gespeichert werden soll. Insbesondere entspricht $name = data { ... }data name { ... }.

8.10 Funktionsdefinitionen

Syntax:

function-statement:
    function new-lines~opt~ function-name function-parameter-declaration~opt~ { script-block }
    filter new-lines~opt~ function-name function-parameter-declaration~opt~ { script-block }
    workflow new-lines~opt~ function-name function-parameter-declaration~opt~ { script-block }

function-name:
    command-argument

command-argument:
    command-name-expr

function-parameter-declaration:
    new-lines~opt~ ( parameter-list new-lines~opt~ )

parameter-list:
    script-parameter
    parameter-list new-lines~opt~ , script-parameter

script-parameter:
    new-lines~opt~ attribute-list~opt~ new-lines~opt~ variable script-parameter-default~opt~

script-block:
    param-block~opt~ statement-terminators~opt~ script-block-body~opt~

param-block:
    new-lines~opt~ attribute-list~opt~ new-lines~opt~ param new-lines~opt~
        ( parameter-list~opt~ new-lines~opt~ )

parameter-list:
    script-parameter
    parameter-list new-lines~opt~ , script-parameter

script-parameter-default:
    new-lines~opt~ = new-lines~opt~ expression

script-block-body:
    named-block-list
    statement-list

named-block-list:
    named-block
    named-block-list named-block

named-block:
    block-name statement-block statement-terminators~opt~

block-name: one of
    dynamicparam   begin   process   end

Beschreibung:

Eine Funktionsdefinition gibt ggf. den Namen der definierten Funktion, des Filters oder des Workflows sowie die Namen der Parameter an. Sie enthält auch null oder mehr Anweisungen, die ausgeführt werden, um den Zweck dieser Funktion zu erreichen.

Jede Funktion ist eine Instanz der Klasse System.Management.Automation.FunctionInfo.

8.10.1 Filterfunktionen

Während eine normale Funktion einmal in einer Pipeline ausgeführt wird und über $inputauf die Eingabeauflistung zugreift, ist ein Filter eine spezielle Art von Funktion, die einmal für jedes Objekt in der Eingabeauflistung ausgeführt wird. Das derzeit verarbeitete Objekt ist über die Variable $_verfügbar.

Ein Filter ohne benannte Blöcke (§8.10.7) entspricht einer Funktion mit einem Prozessblock, jedoch ohne Anfangs- oder Endblock.

Betrachten Sie die folgende Filterfunktionsdefinition und -aufrufe:

filter Get-Square2 { # make the function a filter
    $_ * $_ # access current object from the collection
}

-3..3 | Get-Square2 # collection has 7 elements
6, 10, -3 | Get-Square2 # collection has 3 elements

Jeder Filter ist eine Instanz der Klasse System.Management.Automation.FilterInfo (§4.5.11).

8.10.2 Workflowfunktionen

Eine Workflowfunktion ist wie eine normale Funktion mit implementierungsdefinierter Semantik. Eine Workflowfunktion wird in eine Abfolge von Windows Workflow Foundation-Aktivitäten übersetzt und im Windows Workflow Foundation-Modul ausgeführt.

8.10.3 Verarbeitung von Argumenten

Betrachten Sie die folgende Definition für eine Funktion namens Get-Power:

function Get-Power ([long]$Base, [int]$Exponent) {
    $result = 1
    for ($i = 1; $i -le $Exponent; ++$i) {
        $result *= $Base
    }
    return $result
}

Diese Funktion hat zwei Parameter, $Base und $Exponent. Es enthält auch eine Reihe von Anweisungen, die bei nicht negativen Exponentenwerten $Base^$Exponent^ berechnet und das Ergebnis an den Aufrufer Get-Powerzurückgibt.

Wenn ein Skript, eine Funktion oder ein Filter mit der Ausführung beginnt, wird jeder Parameter auf den Wert des entsprechenden Arguments initialisiert. Wenn kein entsprechendes Argument vorhanden ist und ein Standardwert (§8.10.4) angegeben wird, wird dieser Wert verwendet; andernfalls wird der Wert $null verwendet. Daher ist jeder Parameter eine neue Variable, so als ob er am Anfang des Skriptblocksdurch Zuweisung initialisiert wurde.

Wenn ein Skriptparameter eine Typeinschränkung (z. B. [long] und [int] oben) enthält, wird der Wert des entsprechenden Arguments bei Bedarf in diesen Typ konvertiert; andernfalls tritt keine Konvertierung auf.

Wenn ein Skript, eine Funktion oder ein Filter mit der Ausführung beginnt, wird die Variable $args darin als nicht eingeschränktes 1dimensionales Array definiert, das alle Argumente enthält, die nicht durch Namen oder Position gebunden sind, in lexikalischer Reihenfolge.

Betrachten Sie die folgende Funktionsdefinition und -aufrufe:

function F ($a, $b, $c, $d) { ... }

F -b 3 -d 5 2 4       # $a is 2, $b is 3, $c is 4, $d is 5, $args Length 0
F -a 2 -d 3 4 5       # $a is 2, $b is 4, $c is 5, $d is 3, $args Length 0
F 2 3 4 5 -c 7 -a 1   # $a is 1, $b is 2, $c is 7, $d is 3, $args Length 2

Weitere Informationen zur Parameterbindung finden Sie unter §8.14.

8.10.4 Parameterinitialisierer

Die Deklaration eines Parameters p kann einen Initialisierer enthalten. In diesem Fall wird der Wert dieses Initialisierers verwendet, um p zu initialisieren, vorausgesetzt, dass p an keine Argumente im Aufruf gebunden ist.

Betrachten Sie die folgende Funktionsdefinition und -aufrufe:

function Find-Str ([string]$Str, [int]$StartPos = 0) { ... }

Find-Str "abcabc" # 2nd argument omitted, 0 used for $StartPos
Find-Str "abcabc" 2 # 2nd argument present, so it is used for $StartPos

8.10.5 Die [switch]-Typeinschränkung

Wenn ein Switch-Parameter übergeben wird, muss der entsprechende Parameter im Befehl durch den Typschalter eingeschränkt werden. Der Typschalter hat zwei Werte: "True" und "False".

Betrachten Sie die folgende Funktionsdefinition und -aufrufe:

function Process ([switch]$Trace, $P1, $P2) { ... }

Process 10 20                # $Trace is False, $P1 is 10, $P2 is 20
Process 10 -Trace 20         # $Trace is True, $P1 is 10, $P2 is 20
Process 10 20 -Trace         # $Trace is True, $P1 is 10, $P2 is 20
Process 10 20 -Trace:$false  # $Trace is False, $P1 is 10, $P2 is 20
Process 10 20 -Trace:$true   # $Trace is True, $P1 is 10, $P2 is 20

8.10.6 Pipelines und Funktionen

Wenn ein Skript, eine Funktion oder ein Filter in einer Pipeline verwendet wird, wird eine Sammlung von Werten an dieses Skript oder diese Funktion übermittelt. Das Skript, die Funktion oder der Filter erhält Zugriff auf diese Sammlung über den Enumerator $input (§2.3.2.2, §4.5.16), das für den Eintrag in dieses Skript, die Funktion oder den Filter definiert ist.

Betrachten Sie die folgende Funktionsdefinition und -aufrufe:

function Get-Square1 {
    foreach ($i in $input) {   # iterate over the collection
        $i * $i
    }
}

-3..3 | Get-Square1            # collection has 7 elements
6, 10, -3 | Get-Square1        # collection has 3 elements

8.10.7 Benannte Blöcke

Die Anweisungen in einem Skriptblock- können zu einem großen nicht benannten Block gehören, oder sie können in einen oder mehrere benannte Blöcke verteilt werden. Benannte Blöcke ermöglichen die benutzerdefinierte Verarbeitung von Sammlungen, die aus Pipelines stammen; Benannte Blöcke können in beliebiger Reihenfolge definiert werden.

Die Anweisungen in einem Begin-Block (d. h. einem, das mit dem Schlüsselwort 'begin' markiert ist) werden einmal ausgeführt, bevor das erste Pipeline-Objekt übermittelt wird.

Die Anweisungen in einem Prozessblock (d. h. eines, das mit dem Schlüsselwortprozess gekennzeichnet ist) werden für jedes zugestellte Pipelineobjekt ausgeführt. ($_ ermöglicht den Zugriff auf das aktuelle Objekt, das von der Eingabeauflistung aus der Pipeline verarbeitet wird.) Dies bedeutet, dass der Prozessblock überhaupt nicht ausgeführt wird, wenn eine Sammlung von Nullelementen über die Pipeline gesendet wird. Wenn das Skript oder die Funktion jedoch außerhalb eines Pipelinekontexts aufgerufen wird, wird dieser Block genau einmal ausgeführt, und $_ auf $nullfestgelegt ist, da kein aktuelles Auflistungsobjekt vorhanden ist.

Die Anweisungen in einem Endblock (d. h. eines, das mit dem Schlüsselwortende gekennzeichnet ist) werden einmal ausgeführt, nachdem das letzte Pipelineobjekt übermittelt wurde.

8.10.8 Dynamicparam-Block

Die Unterabschnitte §8.10 befassen sich bisher mit statischen Parametern, die als Teil des Quellcodes definiert sind. Es ist auch möglich, dynamische Parameter über einen dynamicparam block, eine andere Form von benanntem Block (§8.10.7) zu definieren, die mit dem Schlüsselwort dynamicparamgekennzeichnet ist. Ein Großteil dieser Abläufe ist implementierungsspezifisch festgelegt.

Dynamische Parameter sind Parameter eines Cmdlets, einer Funktion, eines Filters oder eines Skripts, die nur unter bestimmten Bedingungen verfügbar sind. Ein solcher Fall ist der Encoding Parameter des cmdlets Set-Item.

Verwenden Sie im -Anweisungsblock-eine If-Anweisung, um die Bedingungen anzugeben, unter denen der Parameter in der Funktion verfügbar ist. Verwenden Sie das Cmdlet New-Object, um ein Objekt eines implementierungsdefinierten Typs zu erstellen, um den Parameter darzustellen, und geben Sie dessen Namen an. Verwenden Sie außerdem New-Object, um ein Objekt eines anderen implementierungsdefinierten Typs zu erstellen, um die implementierungsdefinierte Attribute des Parameters darzustellen.

Das folgende Beispiel zeigt eine Funktion mit Standardparametern namens Name und Path sowie einen optionalen dynamischen Parameter namens DP1. Der parameter DP1 befindet sich im PSet1-Parametersatz und weist einen Typ von Int32auf. Der DP1--Parameter ist nur in der Sample-Funktion verfügbar, wenn der Wert des Path-Parameters "HKLM:" enthält und angibt, dass er im HKEY_LOCAL_MACHINE Registrierungslaufwerk verwendet wird.

function Sample {
    param ([string]$Name, [string]$Path)
    dynamicparam {
        if ($Path -match "*HKLM*:") {
            $dynParam1 = New-Object System.Management.Automation.RuntimeDefinedParameter("dp1", [int32], $attributeCollection)

            $attributes = New-Object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = 'pset1'
            $attributes.Mandatory = $false

            $attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection``1[System.Attribute]
            $attributeCollection.Add($attributes)

            $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
            $paramDictionary.Add("dp1", $dynParam1)
            return $paramDictionary
        }
    }
}

Der Typ, der zum Erstellen eines Objekts zur Darstellung eines dynamischen Parameters verwendet wird, ist System.Management.Automation.RuntimeDefinedParameter.

Der Typ, der zum Erstellen eines Objekts verwendet wird, um die Attribute des Parameters darzustellen, ist System.Management.Automation.ParameterAttribute.

Zu den implementierungsdefinierten Attributen des Parameters gehören Obligatorisch, Positionund ValueFromPipeline.

8.10.9 Param-Block

Ein param-block- bietet eine alternative Möglichkeit zum Deklarieren von Parametern. Beispielsweise sind die folgenden Sätze von Parameterdeklarationen gleichwertig:

function FindStr1 ([string]$Str, [int]$StartPos = 0) { ... }
function FindStr2 {
    param ([string]$Str, [int]$StartPos = 0) ...
}

Ein Paramblock ermöglicht eine Attributliste auf dem Paramblock, während eine Funktionsparameterdeklaration dies nicht tut.

Ein Skript kann über einen param-block, aber nicht über eine function-parameter-declaration verfügen. Eine Funktions- oder Filterdefinition kann eine function-parameter-declaration oder einen param-blockaufweisen, aber nicht beides.

Betrachten Sie das folgende Beispiel:

param ( [Parameter(Mandatory = $true, ValueFromPipeline=$true)]
        [string[]] $ComputerName )

Der einzige Parameter, $ComputerName, hat den Typ string[], er ist erforderlich, und er nimmt Eingaben aus der Pipeline.

Siehe §12.3.7 für eine Diskussion über das Attribut Parameter und weitere Beispiele.

8.11 Die parallele Aussage

Syntax:

parallel-statement:
    *parallel* statement-block

Die parallele Anweisung enthält null oder mehr Anweisungen, die in einer definierten Implementierung ausgeführt werden.

Eine parallele Anweisung ist nur in einem Workflow zulässig (§8.10.2).

8.12 Die Sequence-Anweisung

Syntax:

sequence-statement:
    *sequence* statement-block

Die Sequenz-Anweisung enthält null oder mehr Anweisungen, die in der durch die Implementierung festgelegten Weise ausgeführt werden.

Eine Sequenz-Anweisung ist nur in einem Workflow zulässig (§8.10.2).

8.13 Die Inlinescript-Anweisung

Syntax:

inlinescript-statement:
    inlinescript statement-block

Die Inlinescript-Anweisung enthält null oder mehr Anweisungen, die in einer definierten Implementierung ausgeführt werden.

Eine Inlinescript-Anweisung ist nur in einem Workflow zulässig (§8.10.2).

8.14 Parameterbindung

Wenn ein Skript, eine Funktion, ein Filter oder ein Cmdlet aufgerufen wird, kann jedes Argument nach Position an den entsprechenden Parameter gebunden werden, wobei der erste Parameter die Position Null aufweist.

Betrachten Sie das folgende Definitionsfragment für eine Funktion namens Get-Powerund die Aufrufe an diese Funktion:

function Get-Power ([long]$Base, [int]$Exponent) { ... }

Get-Power 5 3       # argument 5 is bound to parameter $Base in position 0
                    # argument 3 is bound to parameter $Exponent in position 1
                    # no conversion is needed, and the result is 5 to the power 3

Get-Power 4.7 3.2   # double argument 4.7 is rounded to int 5, double argument
                    # 3.2 is rounded to int 3, and result is 5 to the power 3

Get-Power 5         # $Exponent has value $null, which is converted to int 0

Get-Power           # both parameters have value $null, which is converted to int 0

Wenn ein Skript, eine Funktion, ein Filter oder ein Cmdlet aufgerufen wird, kann ein Argument anhand des Namens an den entsprechenden Parameter gebunden werden. Dazu wird ein Parameter mit Argumentverwendet, bei dem es sich um ein Argument handelt, das den Namen des Parameters mit einem führenden Gedankenstrich (-) gefolgt vom zugeordneten Wert für dieses Argument darstellt. Der verwendete Parametername kann jede Schreibweise ohne Groß-/Kleinschreibung aufweisen und ein beliebiges Präfix verwenden, das den entsprechenden Parameter eindeutig kennzeichnet. Vermeiden Sie bei der Auswahl von Parameternamen die Verwendung der Namen der allgemeinen Parameter.

Berücksichtigen Sie die folgenden Aufrufe für die Funktion Get-Power:

Get-Power -Base 5 -Exponent 3   # -Base designates $Base, so 5 is
                                # bound to that, -Exponent designates
                                # $Exponent, so 3 is bound to that

Get-Power -Exp 3 -Bas 5         # $Base takes on 5 and $Exponent takes on 3

Get-Power -E 3 -B 5             # $Base takes on 5 and $Exponent takes on 3

Auf der anderen Seite müssen für Aufrufe der folgenden Funktion

function Get-Hypot ([double]$Side1, [double]$Side2) {
    return [Math]::Sqrt($Side1 * $Side1 + $Side2 * $Side2)
}

müssen Parameter -Side1 und -Side2verwenden, da kein Präfix vorhanden ist, das den Parameter eindeutig bestimmt.

Derselbe Parametername kann nicht mehrmals mit oder ohne andere zugeordnete Argumentwerte verwendet werden.

Parameter können Attribute haben (§12). Informationen zu den einzelnen Attributen finden Sie in den Abschnitten in §12.3. Informationen zu Parametersätzen finden Sie unter §12.3.7.

Ein Skript, eine Funktion, ein Filter oder ein Cmdlet kann Argumente über die Befehlszeile, von der Pipeline oder von beiden empfangen. Hier sind die Schritte zum Auflösen der Parameterbindung:

  1. Binden aller benannten Parameter, dann
  2. Binden von Positionsparametern, dann
  3. Binden aus der Pipeline nach Wert (§12.3.7) mit exakter Übereinstimmung, dann
  4. Binden aus der Pipeline nach Wert (§12.3.7) mit Konvertierung, dann
  5. Binden aus der Pipeline nach Name (§12.3.7) mit exakter Übereinstimmung, dann
  6. Binden aus der Pipeline nach Name (§12.3.7) mit Konvertierung

Mehrere dieser Schritte umfassen die Umwandlung, wie in §6 beschrieben. Der Satz von Konvertierungen, die in der Bindung verwendet werden, ist jedoch nicht genau mit dem in Sprachkonvertierungen verwendeten Satz identisch. Genauer gesagt

  • Obwohl der Wert $null in bool umgewandelt werden kann, kann $null nicht an boolgebunden werden.
  • Wenn der Wert $null an einen Switch-Parameter für ein Cmdlet übergeben wird, wird er so behandelt, als ob $true übergeben wurde. Wenn sie jedoch an einen Switchparameter für eine Funktion übergeben wird, wird sie so behandelt, als ob $false übergeben wurde.
  • Parameter vom Typ "bool" oder "switch" können nur an numerische oder bool-Argumente gebunden werden.
  • Wenn der Parametertyp keine Auflistung ist, aber das Argument eine Art Sammlung ist, wird keine Konvertierung versucht, es sei denn, der Parametertyp ist Objekt oder PsObject. (Der Hauptpunkt dieser Einschränkung besteht darin, das Konvertieren einer Auflistung in einen Zeichenfolgenparameter zu verbieten.) Andernfalls werden die üblichen Konvertierungen versucht.

Wenn der Parametertyp IList oder ICollection<T>ist, werden nur diese Konvertierungen über Konstruktor, op_Implicit und op_Explicit versucht. Wenn keine solchen Konvertierungen vorhanden sind, wird eine spezielle Konvertierung für Parameter vom Typ "Collection" verwendet, die IList, ICollection<T>und Arrays enthält.

Positionsparameter sollten nach Möglichkeit ohne Typkonvertierung gebunden werden. Zum Beispiel

function Test {
    [CmdletBinding(DefaultParameterSetName = "SetB")]
    param([Parameter(Position = 0, ParameterSetName = "SetA")]
        [decimal]$Dec,
        [Parameter(Position = 0, ParameterSetName = "SetB")]
        [int]$In
    )
    $PSCmdlet.ParameterSetName
}

Test 42d   # outputs "SetA"
Test 42    # outputs "SetB"