Udostępnij za pośrednictwem


8. Oświadczenia

Notatka redakcyjna

Ważny

Specyfikacja języka Windows PowerShell 3.0 została opublikowana w grudniu 2012 r. i jest oparta na Windows PowerShell 3.0. Ta specyfikacja nie odzwierciedla bieżącego stanu programu PowerShell. Nie ma planu aktualizacji tej dokumentacji w celu odzwierciedlenia bieżącego stanu. Ta dokumentacja jest przedstawiona tutaj w celu uzyskania informacji historycznych.

Dokument specyfikacji jest dostępny jako dokument programu Microsoft Word z Centrum pobierania Microsoft pod adresem: https://www.microsoft.com/download/details.aspx?id=36389 Dokument programu Word został przekonwertowany na prezentację tutaj w witrynie Microsoft Learn. Podczas konwersji wprowadzono pewne zmiany redakcyjne w celu dostosowania formatowania dla platformy Docs. Usunięto niektóre literówki i drobne błędy.

8.1 Bloki i listy instrukcji sterujących

Składnia:

Napiwek

Notacja ~opt~ w definicjach składni wskazuje, że jednostka leksykalna jest opcjonalna w składni.

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

Opis:

Instrukcja określa jakiś rodzaj akcji, która ma zostać wykonana. O ile nie określono inaczej w tej klauzuli, instrukcje są wykonywane w kolejności leksykalnej.

blok instrukcji pozwala na zgrupowanie zestawu instrukcji w jedną jednostkę składniową.

8.1.1 Instrukcje oznaczone etykietą

Składnia:

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

Opis:

Instrukcja iteracji (§8.4) lub instrukcja wyboru (§8.6) może być poprzedzona bezpośrednio przez jedną etykietę instrukcji, etykietę. Etykieta instrukcji jest używana jako opcjonalny cel instrukcji przerwania (§8.5.1) lub kontynuacji (§8.5.2). Jednak etykieta nie zmienia przepływu sterowania.

Niedozwolone jest stosowanie odstępu między dwukropkiem (:) a tokenem, który następuje po nim.

Przykłady:

: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 Wartości oświadczenia

Wartość stwierdzenia jest skumulowanym zbiorem wartości, które są zapisywane do potoku. Jeśli instrukcja zapisuje pojedynczą wartość skalarną, jest to wartość instrukcji . Jeśli instrukcja zapisuje wiele wartości, wartość instrukcji to zestaw wartości przechowywanych w elementach nieograniczonej tablicy jednowymiarowej, w kolejności, w której zostały zapisane. Rozważmy następujący przykład:

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

Nie ma iteracji pętli i nic nie jest zapisywane do potoku. Wartość stwierdzenia to $null.

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

Mimo że pętla iteruje pięć razy, nic nie jest zapisywane w potoku. Wartość wyrażenia jest $null.

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

Pętla iteruje pięć razy, za każdym razem zapisując do potoku wartość int z $i. Wartość instrukcji to object[] o długości 5.

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

Mimo że pętla iteruje pięć razy, nic nie jest zapisywane w potoku. Wartość oświadczenia to $null.

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

Pętla iteruje pięć razy, a każda wartość jest zapisywana do kanału przetwarzania. Wartość instrukcji to object[] o długości 5.

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

Pętla iteruje raz. Wartość w instrukcji to int o wartości 2.

Oto kilka innych przykładów:

# 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 Instrukcje potoku

Składnia:

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

Opis:

przekierowania omówiono w §7.12; wyrażenie-przypisania omówiono w §7.11; i operator wywołania-polecenia kropka (.) omówiono w §3.5.5. Aby zapoznać się z omówieniem mapowania argumentów do parametrów w wywołaniach poleceń, zobacz §8.14.

Pierwszym poleceniem w potoku jest wyrażenie lub wywołanie polecenia. Zazwyczaj wywołanie polecenia rozpoczyna się od nazwy polecenia, która jest zwykle nagim identyfikatorem. elementy poleceń reprezentują listę argumentów dla polecenia. Nowy wiersz lub n niezakodowany średnik kończy potok.

Wywołanie polecenia składa się z nazwy polecenia, po której następuje zero lub więcej argumentów. Reguły rządzące argumentami są następujące:

  • Argument, który nie jest wyrażeniem, ale który zawiera dowolny tekst bez niewyrażnego odstępu, jest traktowany tak, jakby był dwukrotnie cytowany. Wielkość liter jest zachowywana.

  • Podstawianie zmiennych i rozszerzanie wyrażenia podrzędnego (§2.3.5.2) odbywa się wewnątrz literału ciągu rozszerzalnego i rozszerzalnego literału here-string.

  • Tekst wewnątrz cudzysłowów umożliwia uwzględnianie wiodących, końcowych i osadzonych białych znaków w wartości argumentu. [Uwaga: Obecność białych znaków w argumentzie cytowanym nie zamienia jednego argumentu w wiele argumentów. przypis końcowy]

  • Umieszczenie nawiasów wokół argumentu powoduje, że wyrażenie jest oceniane przy użyciu przekazanego wyniku zamiast tekstu oryginalnego wyrażenia.

  • Aby przekazać argument, który wygląda jak parametr przełącznika (§2.3.4), ale nie jest przeznaczony jako taki, należy ująć ten argument w cudzysłowie.

  • Podczas określania argumentu zgodnego z parametrem mającym ograniczenie typu [switch] (§8.10.5), obecność nazwy argumentu na własną rękę powoduje ustawienie tego parametru na $true. Można jednak jawnie ustawić wartość parametru, dołączając sufiks do argumentu. Na przykład przy użyciu parametru ograniczonego typu pargument -p:$true ustawia wartość true, a -p:$false ustawia wartość p na fałsz.

  • Argument -- wskazuje, że wszystkie następujące argumenty mają zostać przekazane w ich rzeczywistej formie, tak jakby cudzysłowy zostały umieszczone wokół nich.

  • Argument --% wskazuje, że wszystkie następujące argumenty mają zostać przekazane z minimalnym analizowaniem i przetwarzaniem. Ten argument jest nazywany parametrem dosłowny. Argumenty po parametrze dosłownym nie są wyrażeniami programu PowerShell, nawet jeśli składniowo są one prawidłowymi wyrażeniami programu PowerShell.

Jeśli typem polecenia jest Aplikacja, parametr --% nie jest przekazywany do polecenia. Argumenty po --% mają rozwinięte wszystkie zmienne środowiskowe (ciągi otoczone %). Na przykład:

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

Kolejność obliczania argumentów jest nieokreślona.

Aby uzyskać informacje o powiązaniu parametrów, zobacz §8.14. Aby uzyskać informacje na temat wyszukiwania nazw, zobacz §3.8.

Po zakończeniu przetwarzania argumentów polecenie jest wywoływane. Jeśli wywołane polecenie kończy się normalnie (§8.5.4), kontrola powraca do punktu w skrypcie lub funkcji bezpośrednio po wywołaniu polecenia. Aby uzyskać opis zachowania w przypadku nietypowego zakończenia, zobacz break (§8.5.1), continue (§8.5.2), throw (§8.5.3), exit (§8.5.5), try (§8.7) i trap (§8.8).

Zazwyczaj polecenie jest wywoływane przy użyciu jego nazwy, a następnie dowolnych argumentów. Można jednak użyć operatora wywołania polecenia, &. Jeśli nazwa polecenia zawiera nieuniknione białe znaki, musi być ujęta w cudzysłów i wywołana za pomocą tego operatora. Ponieważ blok skryptu nie ma nazwy, również musi być wywoływany z tym operatorem. Na przykład następujące wywołania polecenia Get-Factorial są równoważne:

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

Bezpośrednie i pośrednie wywołania funkcji cyklicznych są dozwolone. Na przykład

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

Przykłady:

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 Instrukcja if

Składnia:

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

Opis:

Potok wyrażenia sterujące musi mieć typ logiczny albo być niejawnie konwertowalny na ten typ. Klauzula else- jest opcjonalna. Może istnieć zero lub więcej elseif-clause'ów.

Jeśli potok najwyższego poziomu ma wartość prawda, blok instrukcji zostanie wykonany, a wykonanie instrukcji kończy się. W przeciwnym razie, jeśli elseif-clause jest obecny i jego pipeline testuje wartość True, wtedy jego statement-block jest wykonywany, a wykonanie instrukcji kończy się. W przeciwnym razie, jeśli istnieje klauzula else, jej blok instrukcji zostanie wykonany.

Przykłady:

$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 Instrukcje pętli

8.4.1 Instrukcja while

Składnia:

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

while-condition:
    new-lines~opt~ pipeline

Opis:

Wyrażenie sterujące while-condition musi być typu bool lub być niejawnie konwertowalne na ten typ. Treść pętli składająca się z bloków instrukcjijest wykonywana wielokrotnie do momentu, gdy wyrażenie kontrolujące testuje wartość False. Wyrażenie sterujące jest oceniane przed każdym wykonaniem treści pętli.

Przykłady:

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

8.4.2 Instrukcja "do"

Składnia:

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

Opis:

Wyrażenie sterujące while-condition musi mieć typ logiczny lub być niejawnie konwertowane na ten typ. W formie while treść pętli, która składa się z blok-instrukcji, jest wykonywana wielokrotnie, podczas gdy kontrolujące wyrażenie testuje True. W formularzu until treść pętli jest wykonywana wielokrotnie, dopóki wyrażenie sterujące nie testuje wartości True. Wyrażenie sterujące jest oceniane po każdym wykonaniu treści pętli.

Przykłady:

$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 Instrukcja for

Składnia:

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

Opis:

Wyrażenie sterujące dla warunku musi mieć typ bool lub być niejawnie konwertowalne na ten typ. Treść pętli, która składa się z bloków instrukcji, jest wykonywana wielokrotnie, podczas gdy kontrolujące wyrażenie testuje wartość True. Wyrażenie sterujące jest oceniane przed każdym wykonaniem treści pętli.

wyrażenie for-initializer jest obliczane przed pierwszym obliczeniem wyrażenia sterującego. Wyrażenie for-initializer jest ewaluowane tylko pod kątem efektów ubocznych; każda wartość, jaką generuje, jest odrzucana i nie jest zapisywana w potoku.

Wyrażenie iteratora jest oceniane po każdym wykonaniu ciała pętli. Wyrażenie dla iteratora jest oceniane wyłącznie pod kątem skutków ubocznych; każda wartość, jaką generuje, jest pomijana i nie zostaje zapisana do potoku.

Jeśli wyrażenie dla warunku zostanie pominięte, wyrażenie kontrolne testuje True.

Przykłady:

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 Instrukcja foreach

Składnia:

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

Opis:

Treść pętli, która składa się z bloku instrukcji statement-block, jest wykonywana dla każdego elementu określonego przez zmienną variable w kolekcji określonej przez potok pipeline. Zakres zmiennej nie jest ograniczony do instrukcji foreach. W związku z tym zachowuje swoją ostateczną wartość po zakończeniu wykonywania treści pętli. Jeśli potok oznacza skalar (z wyłączeniem wartości $null) zamiast kolekcji, skalar jest traktowany jako kolekcję o jednym elemencie. Jeśli potok wyznacza wartość $null, potok jest traktowany jako kolekcja bez elementów.

Jeśli parametr foreach--parallel jest określony, zachowanie jest zależne od implementacji.

parametr foreach jest dozwolony tylko w przepływie pracy (§8.10.2).

Każda instrukcja foreach ma własny moduł wyliczający, $foreach (§2.3.2.2, §4.5.16), który istnieje tylko podczas wykonywania tej pętli.

Obiekty generowane w potoku przez są zbierane przed rozpoczęciem wykonywania bloku instrukcji . Jednak w przypadku polecenia cmdlet ForEach-Object, blok instrukcji statement-block jest wykonywany na każdym obiekcie w miarę jego generowania.

Przykłady:

$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 Instrukcje sterowania przepływem

Składnia:

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

Opis:

Instrukcja sterowania przepływem powoduje bezwarunkowy transfer sterowania do innej lokalizacji.

8.5.1 Instrukcja break

Opis:

Instrukcja break z wyrażeniem label-expression jest nazywana etykietowaną instrukcją break. Instrukcja break bez wyrażenia-etykiety jest określana jako instrukcja break bez etykiety.

Poza instrukcją pułapki instrukcja podziału bez etykiet bezpośrednio w instrukcji iteracji (§8.4) kończy wykonywanie tej najmniejszej instrukcji iteracji. Instrukcja break bez etykiety bezpośrednio w instrukcji switch (§8.6) kończy dopasowywanie wzorca dla warunku bieżącego przełącznika . Zobacz (§8.8), aby uzyskać szczegółowe informacje na temat używania przerwy w instrukcji pułapek.

Instrukcja iteracji lub instrukcja switch może być opcjonalnie poprzedzona etykietą pojedynczej instrukcji (§8.1.1). Taka etykieta może być używana jako cel instrukcji break z etykietą, która kończy wykonywanie docelowej, zamkniętej instrukcji iteracji.

Przerwanie oznaczone etykietą nie musi być rozpoznawane w żadnym zakresie lokalnym; wyszukiwanie pasującej etykiety może być kontynuowane w górę stosu wywołań, nawet przez granice skryptów i wywołań funkcji. Jeśli nie znaleziono pasującej etykiety, wywołanie bieżącego polecenia zostanie zakończone.

Nazwa etykiety oznaczonej przez wyrażenie etykiety nie musi mieć stałej wartości.

Jeśli wyrażenie-etykiety jest wyrażeniem jednoargumentowym, jest konwertowane na ciąg.

Przykłady:

$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 Instrukcja continue

Opis:

Instrukcja z wyrażeniem etykiety jest nazywana instrukcją oznaczoną etykietą continue. Instrukcja continue bez wyrażenie-etykiety jest nazywana instrukcją unlabeled continue.

Użycie continue wewnątrz instrukcji pułapki jest omawiane w §8.8.

Nieoznaczona instrukcja continue w pętli kończy wykonywanie bieżącej pętli i przenosi sterowanie do zamykającej klamry najmniejszej otaczającej instrukcji iteracyjnej (§8.4). Nieoznaczona instrukcja continue w ramach przełącznika kończy wykonywanie bieżącej iteracji switch i przekazuje sterowanie do najmniejszego otaczającego elementu switchwarunku przełączenia (§8.6).

Instrukcja iteracji lub instrukcja switch (§8.6) może być opcjonalnie poprzedzona jedną etykietą instrukcji (§8.1.1). Taka etykieta instrukcji może być używana jako element docelowy zamkniętej instrukcji continue, w tym przypadku instrukcja ta kończy wykonywanie bieżącej pętli lub iteracji switch i przenosi kontrolkę do docelowej otaczającej iteracji lub etykiety instrukcji switch.

Nie trzeba rozwiązywać continue oznaczonego etykietą w żadnym zakresie lokalnym; wyszukiwanie pasującej etykiety może przechodzić w górę stosu wywołań nawet przez granice skryptów i wywołań funkcji. Jeśli nie znaleziono pasującej etykiety, wywołanie bieżącego polecenia zostanie zakończone.

Nazwa etykiety oznaczonej przez wyrażenie etykiety nie musi mieć stałej wartości.

Jeśli wyrażenie-etykiety jest wyrażeniem jednoargumentowym, jest konwertowane na ciąg.

Przykłady:

$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 Instrukcja throw

Opis:

Wyjątkiem jest sposób obsługi warunku błędu na poziomie systemu lub aplikacji. Instrukcja throw zgłasza wyjątek. (Zobacz §8.7, aby zapoznać się z omówieniem obsługi wyjątków).

Jeśli potok zostanie pominięty i instrukcja throw nie znajduje się w klauzuli catch, zachowanie jest zdefiniowane przez implementację. Jeśli pipeline jest obecny, a instrukcja 'throw' znajduje się w klauzulą catch, wyjątek przechwycony przez tę klauzulę catch jest ponownie zgłaszany po wykonaniu każdej klauzuli finally skojarzonej z klauzulą catch.

Jeśli przepływ jest obecny, typ zgłaszanego wyjątku jest zdefiniowany przez implementację.

Po wystąpieniu wyjątku kontrolka jest przekazywana do pierwszej klauzuli catch w otaczającej instrukcji try, która może obsłużyć wyjątek. Lokalizacja, w której początkowo zgłaszany jest wyjątek, nazywana jest punktem zgłoszenia. Po wyrzuceniu wyjątku kroki opisane w §8.7 są wykonywane wielokrotnie do momentu znalezienia klauzuli catch odpowiadającej wyjątkowi lub nie można znaleźć żadnej.

Przykłady:

throw
throw 100
throw "No such record in file"

Jeśli potok zostanie pominięty, a instrukcja throw nie znajduje się w klauzuli catch, tekst "ScriptHalted" jest zapisywany w potoku, a typ zgłoszonego wyjątku jest System.Management.Automation.RuntimeException.

Jeśli potok jest obecny, zgłoszony wyjątek jest owinięty w obiekcie typu System.Management.Automation.RuntimeException, który zawiera informacje o wyjątku jako obiekt System.Management.Automation.ErrorRecord (dostępny za pośrednictwem $_).

Przykład 1: throw 123 powoduje wyjątek typu RuntimeException. W bloku catch $_.TargetObject zawiera obiekt opakowany wewnątrz, w tym przypadku System.Int32 o wartości 123.

Przykład 2: throw "xxx" powoduje wyjątek typu RuntimeException. Z poziomu bloku catch $_.TargetObject zawiera obiekt owinięty wewnątrz, w tym przypadku System.String o wartości "xxx".

Przykład 3: throw 10,20 powoduje wyjątek typu RuntimeException. Z poziomu bloku catch, $_.TargetObject zawiera obiekt, który jest owinięty wewnątrz, w tym przypadku System.Object[], tablicę nieograniczoną z dwóch elementów z wartościami System.Int32` 10 i 20.

8.5.4 Instrukcja return

Opis:

Instrukcja return zapisuje w potoku wartości określone przez potok , jeśli są, i zwraca kontrolę do funkcji lub wywołującego skryptu. Funkcja lub skrypt mogą mieć zero lub więcej return instrukcji.

Jeśli wykonanie osiągnie nawias zamykający funkcji, zakłada się, że return bez potoku.

Instrukcja return to pewien rodzaj "cukru składniowego", który umożliwia programistom wyrażanie się jak w innych językach; jednak wartość zwracana z funkcji lub skryptu to w rzeczywistości wszystkie wartości zapisane w potoku przez tę funkcję lub skrypt plus wszelkie wartości określone przez potok . Jeśli do potoku jest zapisywana tylko wartość skalarna, to jej typ jest typem zwracanej wartości; w przeciwnym razie typ zwracany to nieograniczona tablica jednowymiarowa zawierająca wszystkie wartości zapisane w potoku.

Przykłady:

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

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

Obiekt wywołujący Get-Factorial otrzymuje z powrotem int.

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

Wywołanie do Test zwraca nieograniczoną, 1-wymiarową tablicę trzech elementów.

8.5.5 Instrukcja exit

Opis:

Instrukcja exit kończy bieżący skrypt i zwraca kontrolę oraz kod zakończenia do środowiska hosta lub skryptu wywołującego. Jeśli zostanie dostarczony potok , wartość, którą oznacza, zostanie przekonwertowana na int, jeśli będzie to konieczne. Jeśli taka konwersja nie istnieje lub jeśli potok zostanie pominięty, zwracana jest wartość int zero.

Przykłady:

exit $count # terminate the script with some accumulated count

8.6 Instrukcja switch

Składnia:

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

Opis:

Jeśli warunek przełącznika wyznacza jedną wartość, sterowanie jest przekazywane do jednego lub więcej pasujących bloków instrukcji dopasowania wzorca. Jeśli nie są zgodne wzorce, można wykonać akcję domyślną.

Przełącznik musi zawierać co najmniej jedną klauzulę switch-, z których każda zaczyna się od wzorca (klauzula przełącznika inna niż domyślna) lub słowa kluczowego default (klauzula przełącznika domyślna). Przełącznik musi zawierać zero lub jedną klauzulę przełącznika default oraz zero lub więcej klauzul przełączników innych niż domyślne. Klauzule switch mogą być zapisywane w dowolnej kolejności.

Wiele wzorców może mieć tę samą wartość. Wzorzec nie musi być literałem, a przełącznik może mieć wzorce z różnymi typami.

Jeśli wartość warunku przełącznika pasuje do wartości wzorca, blok instrukcji danego wzorca jest wykonywany. Jeśli wiele wartości wzorców pasuje do wartości warunku przełącznika , wykonywany jest blok instrukcji każdego pasującego wzorca, w kolejności leksykalnej, chyba że którykolwiek z tych bloków instrukcji zawiera instrukcję , zgodnie z §8.5.1 .

Jeżeli wartość warunku przełącznika nie pasuje do żadnej wartości wzorca, a istnieje klauzula przełącznika default, wykonywany jest jej blok instrukcji ; w przeciwnym razie dopasowanie wzorca dla tego warunku przełącznika zostaje przerwane.

Przełączniki mogą być zagnieżdżone, a każdy przełącznik ma własny zestaw klauzul przełączających. W takich przypadkach klauzula przełącznika należy do najbardziej wewnętrznego przełącznika obecnie w obszarze działania.

Przy wejściu do każdego bloku instrukcji, wartość $_ jest automatycznie przypisywana warunkowi przełącznika , który spowodował przejście do tego bloku instrukcji. $_ jest również dostępny w bloku instrukcji's warunku przełącznika.

Dopasowywanie obiektów innych niż ciągi odbywa się przez sprawdzenie równości (§7.8.1).

Jeśli dopasowanie obejmuje ciągi znaków, domyślnie porównanie jest bez uwzględniania wielkości liter. Obecność przełącznika-parametru -CaseSensitive powoduje, że porównanie uwzględnia wielkość liter.

Wzorzec może zawierać znaki wieloznaczne (§3.15), w takim przypadku przeprowadzane są porównania ciągów z użyciem znaków wieloznacznych, ale tylko wtedy, gdy obecny jest przełącznik parametr -Wildcard. Domyślnie porównanie jest niewrażliwe na różnicę w wielkości liter.

Wzorzec może zawierać wyrażenie regularne (§3.16), w którym przypadku wykonywane są porównania ciągów wyrażeń regularnych, ale tylko wtedy, gdy obecny jest switch-parameter -Regex. Domyślnie porównanie jest niewrażliwe na wielkość liter. Jeśli -Regex jest obecny i wzorzec jest dopasowany, $Matches jest definiowana w klauzuli switch w bloku instrukcji dla tego dopasowania.

Można skrócić parametr przełącznika do; można użyć dowolnego odrębnego początku parametru. Na przykład ‑Regex, ‑Rege, ‑Reg, ‑Rei ‑R są równoważne.

Jeśli określono sprzeczne parametry-przełączniki, ostateczne w kolejności leksykalnej zwyciężą. Obecność ‑Exact wyłącza -Regex i -Wildcard; nie ma natomiast wpływu na ‑Case.

Jeśli określono przełącznik-parametr z‑Parallel, zachowanie jest określane przez implementację.

Przełącznik parametru ‑Parallel jest dozwolony tylko w procesie (§8.10.2).

Jeśli wzorzec jest blok-wyrażenie skryptu, ten blok jest oceniany, a wynik jest konwertowany na wartość boolowską, jeśli to konieczne. Jeśli wynik ma wartość $true, zostanie wykonany odpowiedni blok instrukcji ; w przeciwnym razie blok nie zostanie wykonany.

Jeśli warunek przełącznika wyznacza wiele wartości, przełącznik jest stosowany do każdej wartości w kolejności leksykalnej przy użyciu reguł opisanych powyżej dla warunku przełącznika, który wyznacza jedną wartość. Każda instrukcja switch ma własny moduł wyliczający, $switch (§2.3.2.2, §4.5.16), który istnieje tylko podczas wykonywania tego przełącznika.

Instrukcja switch może mieć etykietę i może zawierać oznaczone i nieoznaczone instrukcje break (§8.5.1) oraz continue (§8.5.2).

Jeśli -Fileswitch-filename, zamiast iterować po wartościach w wyrażeniu, przełącznik iteruje po wartościach w pliku wyznaczonym przez switch-filename. Plik jest odczytywany po jednym wierszu, gdzie każdy wiersz zawiera jedną wartość. Znaki terminatora wiersza nie są uwzględniane w wartościach.

Przykłady:

$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 Instrukcja try/finally

Składnia:

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

Opis:

Instrukcja try udostępnia mechanizm umożliwiający przechwytywanie wyjątków, które występują podczas wykonywania bloku. Instrukcja try umożliwia również określenie bloku kodu, który jest zawsze wykonywany, gdy kontrolka opuszcza instrukcję try. Proces zgłaszania wyjątku za pośrednictwem instrukcji throw jest opisany w §8.5.3.

Blok try to blok instrukcji skojarzony z instrukcją try. Blok catch to blok instrukcji powiązany z klauzulą catch. blok finally to blok instrukcji związany z klauzulą finally.

Klauzula catch bez listy catch-type jest nazywana ogólną klauzulą catch.

Każda klauzula łapania jest procedurą obsługi wyjątków , a klauzula łapania , której lista typów łapania zawiera typ podniesionego wyjątku, jest pasującą klauzulą łapania . Uniwersalna klauzula catch odpowiada wszystkim typom wyjątków.

Chociaż klauzule catch i klauzula finally są opcjonalne, co najmniej jedna z nich musi być obecna.

Przetwarzanie rzuconego wyjątku polega na wielokrotnym wykonywaniu kolejnych kroków aż do znalezienia klauzuli 'catch' zgodnej z wyjątkiem.

  • W obecnym zakresie każda instrukcja try, która otacza punkt rzutu, zostaje zbadana. Dla każdej instrukcji try S, począwszy od najbardziej wewnętrznej instrukcji try i kończącej się najbardziej zewnętrzną instrukcją try, oceniane są następujące kroki:

    • Jeśli blok tryS otacza punkt rzucenia, a jeśli S ma co najmniej jedną klauzulę catch, klauzule catch są badane w kolejności leksykalnej, aby znaleźć odpowiednią instrukcję obsługi dla wyjątku. Pierwsza klauzula catch, która określa typ wyjątku lub podstawowy typ tego wyjątku, jest traktowana jako dopasowanie. Ogólna klauzula catch jest uznawana za pasującą do każdego typu wyjątku. Jeśli znajduje się zgodna klauzula catch, przetwarzanie wyjątków jest wykonywane przez przeniesienie kontroli do bloku tej klauzuli catch. W pasującej klauzuli catch zmienna $_ zawiera opis bieżącego wyjątku.

    • W przeciwnym razie jeśli blok try lub blok catchS otacza punkt rzutu, a jeśli S ma blok finally, kontrolka zostanie przeniesiona do ostatecznego bloku. Jeśli blok finally zgłasza inny wyjątek, przetwarzanie bieżącego wyjątku zostanie zakończone. W przeciwnym razie, gdy kontrolka osiągnie koniec bloku finally, przetwarzanie bieżącego wyjątku jest kontynuowane.

  • Jeśli obsługiwacz wyjątków nie znajduje się w bieżącym zakresie, powyższe kroki są powtarzane dla otaczającego zakresu z punktem wyrzucenia odpowiadającym instrukcji, z której wywołano bieżący zakres.

  • Jeśli przetwarzanie wyjątku kończy się zamknięciem wszystkich zakresów, wskazując, że procedura obsługi nie istnieje dla wyjątku, zachowanie jest nieokreślone.

Aby zapobiec niedostępnym klauzulom catch w bloku try, klauzula catch nie może określać typu wyjątku, który jest równy lub wywodzi się z typu określonego we wcześniejszej klauzuli catch w ramach tego samego bloku try.

Instrukcje bloku finally są zawsze wykonywane, gdy kontrolka pozostawia instrukcję try. Jest to prawdą, czy transfer kontrolny występuje w wyniku normalnego wykonywania, w wyniku wykonania instrukcji break, continuelub return, albo w wyniku wyjątku wyrzuconego z instrukcji try.

Jeśli podczas wykonywania bloku finally wystąpi wyjątek, zostanie on przekazany do następnej otaczającej instrukcji try. Jeśli inny wyjątek jest w trakcie obsługi, ten wyjątek zostaje utracony. Proces generowania wyjątku został dokładniej omówiony w opisie instrukcji throw.

try instrukcje mogą współistnieć z instrukcjami trap; aby uzyskać szczegółowe informacje, zobacz §8.8.

Przykłady:

$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 {
        # ...
    }
}

Każdy zgłoszony wyjątek jest zgłaszany jako System.Management.Automation.RuntimeException. Jeśli w bloku try znajdują się typu klauzula przechwytywania, właściwość InnerException wyjątku jest sprawdzana, aby znaleźć dopasowanie, na przykład z typem System.IndexOutOfRangeException powyżej.

8.8 Instrukcja pułapki

Składnia:

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

Opis:

Instrukcja trap z i bez literału typu jest analogiczna do bloku catch (§8.7) z i bez listy typów catch, z wyjątkiem tego, że instrukcja trap może obsługiwać tylko jeden typ jednocześnie.

Wiele instrukcji trap można zdefiniować w tym samym bloku instrukcji , a kolejność ich definiowania jest nieistotna. Jeśli dwie instrukcje trap o tym samym literał typu są zdefiniowane w tym samym zakresie, leksykalnie pierwsza jest używana do przetwarzania wyjątku pasującego typu.

W przeciwieństwie do bloku catch, deklaracja trap jest dokładnie dopasowana do typu wyjątku; nie jest stosowane dopasowanie do typu pochodnego.

Jeśli wystąpi wyjątek, a w aktualnym zakresie nie ma odpowiedniej instrukcji trap, wtedy w otaczającym zakresie jest poszukiwana odpowiednia instrukcja pułapki, co może obejmować wyszukiwanie w skrypcie wywołującym, funkcji lub filtrze, a następnie u jego nadawcy, i tak dalej hierarchicznie. Jeśli wyszukiwanie prowadzi do zakończenia wszystkich zakresów, co wskazuje, że nie istnieje program obsługi dla wyjątku, zachowanie jest nieokreślone.

Treść instrukcji trap jest wykonywana tylko po to, aby przetworzyć odpowiedni wyjątek; w przeciwnym razie zostaje pominięte.

Jeśli domyślnie obiekt błędu trapinstrukcji kończy się normalnie, obiekt błędu jest zapisywany w strumieniu błędów, wyjątek jest uznawany za obsłużony, a wykonanie jest kontynuowane z instrukcją bezpośrednio po instrukcji w zakresie zawierającym instrukcję trap, która uczyniła widoczny wyjątek. Przyczyną wyjątku może być polecenie, które zostało wywołane przez polecenie zawierające instrukcję trap.

Jeśli ostateczna instrukcja wykonywana w trapinstrukcja-body jest kontynuowana (§8.5.2), zapisywanie obiektu błędu do strumienia błędów jest pomijane, a wykonanie będzie kontynuowane z instrukcją bezpośrednio po instrukcji w zakresie zawierającym instrukcję pułapki, która uczyniła wyjątek widoczny. Jeśli końcowa instrukcja wykonywana w trapinstrukcja-treść jest przerywana (§8.5.1), zapisywanie obiektu błędu w strumieniu błędów jest pomijane, a wyjątek jest zgłaszany ponownie.

W instrukcji trap zmienna $_ zawiera opis bieżącego błędu.

Rozważmy przypadek, w którym wyjątek zgłoszony z bloku try nie ma odpowiadającego bloku catch, ale istnieje odpowiadająca instrukcja trap na wyższym poziomie struktury blokowej. Po wykonaniu klauzuli finally bloku try instrukcja trap uzyskuje kontrolę, nawet jeśli jakikolwiek zakres nadrzędny ma pasujący blok catch. Jeśli instrukcja trap jest zdefiniowana w samym bloku try, a blok try ma pasujący blok catch, instrukcja trap uzyskuje kontrolę.

Przykłady:

W poniższym przykładzie obiekt błędu jest zapisywany, a wykonywanie programu jest kontynuowane od razu po instrukcji, która spowodowała zatrzymanie; to znaczy, ciąg tekstowy "Done" jest umieszczany w potoku.

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

W poniższym przykładzie zapis obiektu błędu jest pomijany, a wykonywanie kodu jest kontynuowane od instrukcji znajdującej się bezpośrednio po tej, która spowodowała wyjątek; oznacza to, że ciąg "Done" jest zapisywany do potoku.

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

W poniższym przykładzie zapisywanie obiektu błędu jest tłumione, a wyjątek zostaje ponownie zgłoszony.

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

W poniższym przykładzie instrukcje wywołujące pułapki oraz generujące wyjątki znajdują się w tym samym zakresie. Po przechwyceniu i obsłużeniu wyjątku wykonywanie zostanie wznowione zapisem wartości 1 do potoku.

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

W poniższym przykładzie instrukcje dotyczące pułapek i generowania wyjątków znajdują się w różnych obszarach. Po przechwyceniu i obsłużeniu wyjątku wykonanie jest wznawiane z zapisem liczby 2 (a nie 1) do potoku.

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

8.9 Deklaracja danych

Składnia:

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

Opis:

Instrukcja danych tworzy sekcję danych , zachowując dane tej sekcji oddzielone od kodu. Ta separacja obsługuje obiekty, takie jak oddzielne pliki zasobów ciągów dla tekstu, takie jak komunikaty o błędach i ciągi Pomocy. Pomaga również wspierać internacjonalizację, ułatwiając izolowanie, lokalizowanie i przetwarzanie ciągów, które zostaną przetłumaczone na różne języki.

Skrypt lub funkcja może mieć zero lub więcej sekcji danych.

blok instrukcji sekcji danych jest ograniczony do następujących funkcji programu PowerShell:

  • Wszystkie operatory z wyjątkiem -match
  • Instrukcja if
  • Następujące zmienne automatyczne: $PSCulture, $PSUICulture, $true, $falsei $null.
  • Komentarze
  • Rurociągi
  • Instrukcje rozdzielone średnikami (;)
  • Literały
  • Wywołania cmdletu ConvertFrom-StringData
  • Wszystkie inne polecenia cmdlet zidentyfikowane przez parametr SupportedCommand

Jeśli używany jest cmdlet ConvertFrom-StringData, pary klucz/wartość można wyrazić w dowolnej formie literału tekstowego. Jednak rozszerzalne literały-ciągui rozszerzalne-tutaj-literały-ciągunie mogą zawierać żadnych podstawień zmiennych ani rozszerzeń podwyrażeń.

Przykłady:

Parametr SupportedCommand wskazuje, że określone polecenia cmdlet lub funkcje generują tylko dane. Na przykład następująca sekcja danych zawiera polecenie cmdlet napisane przez użytkownika, ConvertTo-Xml, które formatuje dane w pliku XML:

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

Rozważmy poniższy przykład, w którym sekcja danych zawiera polecenie ConvertFrom-StringData, które konwertuje ciągi na tabelę skrótów, której wartość jest przypisana do $messages.

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

Klucze i wartości tabeli skrótów są dostępne odpowiednio przy użyciu $messages.Greeting, $messages.Yesi $messages.No.

Teraz można to zapisać jako zasób w języku angielskim. Zasoby języka niemieckiego i hiszpańskiego można tworzyć w osobnych plikach z następującymi sekcjami danych:

$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
"@
}

Jeśli nazwa_danych jest obecna, to określa nazwę zmiennej, do której ma być przechowywana wartość instrukcji danych (bez użycia wiodącego $). W szczególności $name = data { ... } jest odpowiednikiem data name { ... }.

8.10 Definicje funkcji

Składnia:

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

Opis:

Definicja funkcji określa nazwę zdefiniowanej funkcji, filtru lub przepływu pracy oraz nazwy jego parametrów, jeśli istnieją. Zawiera również zero lub więcej instrukcji, które są wykonywane w celu osiągnięcia celu tej funkcji.

Każda funkcja jest wystąpieniem klasy System.Management.Automation.FunctionInfo.

Funkcje filtru 8.10.1

Podczas gdy zwykła funkcja działa raz w potoku i uzyskuje dostęp do kolekcji wejściowej za pośrednictwem $input, filtr jest specjalnym rodzajem funkcji, która działa raz dla każdego obiektu w kolekcji wejściowej. Obecnie przetwarzany obiekt jest dostępny za pośrednictwem zmiennej $_.

Filtr bez nazwanych bloków (§8.10.7) jest odpowiednikiem funkcji z blokiem procesu, ale bez żadnego bloku początkowego ani bloku końcowego.

Proszę rozważyć następującą definicję funkcji filtrującej oraz jej wywołania:

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

Każdy filtr jest wystąpieniem klasy System.Management.Automation.FilterInfo (§4.5.11).

Funkcje przepływu pracy 8.10.2

Funkcja przepływu pracy jest jak zwykła funkcja ze zdefiniowaną semantyczną implementacją. Funkcja przepływu pracy jest tłumaczona na sekwencję aktywności Windows Workflow Foundation i wykonywana w aparacie Windows Workflow Foundation.

Przetwarzanie argumentów 8.10.3

Rozważmy następującą definicję funkcji o nazwie Get-Power:

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

Ta funkcja ma dwa parametry, $Base i $Exponent. Zawiera również zestaw instrukcji, które dla wartości nieujemnych wykładników oblicza $Base^$Exponent^ i zwraca wynik do wywołującego Get-Power.

Gdy skrypt, funkcja lub filtr rozpoczyna wykonywanie, każdy parametr jest inicjowany do odpowiedniej wartości argumentu. Jeśli nie ma odpowiedniego argumentu i zostanie podana wartość domyślna (§8.10.4) jest używana; w przeciwnym razie jest używana wartość $null. W związku z tym każdy parametr jest nową zmienną tak, jakby został zainicjowany przez przypisanie na początku bloku skryptu .

Jeśli skrypt-parametr zawiera ograniczenie typu (takie jak [long] i [int] powyżej), wartość odpowiedniego argumentu jest konwertowana na ten typ, jeśli jest to konieczne; w przeciwnym razie nie ma konwersji.

Gdy skrypt, funkcja lub filtr rozpoczyna wykonywanie, zmienna $args jest zdefiniowana wewnątrz niej jako niezwiązana tablica 1-wymiarowa, która zawiera wszystkie argumenty, które nie są powiązane według nazwy lub pozycji, w kolejności leksykalnej.

Rozważmy następującą definicję funkcji i wywołania:

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

Aby uzyskać więcej informacji na temat powiązania parametrów, zobacz §8.14.

Inicjatory parametrów 8.10.4

Deklaracja parametru p może zawierać inicjator, w takim przypadku wartość inicjatora jest używana do inicjowania p pod warunkiem, że p nie jest powiązany z żadnymi argumentami w wywołaniu.

Rozważmy następującą definicję funkcji i wywołania:

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 Ograniczenie typu [switch]

Po przekazaniu parametru przełącznika odpowiedni parametr w poleceniu musi być ograniczony przez przełącznik typu. Przełącznik typu ma dwie wartości: Prawda i Fałsz.

Rozważmy następującą definicję funkcji i wywołania:

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 Potoki i funkcje

Gdy skrypt, funkcja lub filtr jest używany w potoku, do tego skryptu lub funkcji przekazywana jest kolekcja wartości. Skrypt, funkcja lub filtr uzyskuje dostęp do tej kolekcji za pomocą wyliczającego $input (§2.3.2.2, §4.5.16), który jest zdefiniowany przy wejściu do tego skryptu, funkcji lub filtru.

Rozważmy następującą definicję funkcji i wywołania:

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 Nazwane bloki

Instrukcje w bloku skryptów mogą należeć do jednego dużego bloku bez nazwy lub mogą być rozdzielone do co najmniej jednego nazwanego bloku. Bloki nazwane umożliwiają niestandardowe przetwarzanie kolekcji pochodzących z potoków; bloki nazwane można zdefiniować w dowolnej kolejności.

Instrukcje w bloku begin (czyli tym oznaczonym słowem kluczowym begin) są wykonywane raz, zanim pierwszy obiekt potoku zostanie dostarczony.

Instrukcje w bloku procesu (tj. jednym oznaczonym słowem kluczowym 'process') są wykonywane dla każdego obiektu potokowego dostarczonego. ($_ zapewnia dostęp do bieżącego obiektu przetwarzanego z kolekcji wejściowej pochodzącej z potoku). Oznacza to, że jeśli kolekcja zawierająca zero elementów jest wysyłana za pośrednictwem potoku, blok procesu nie jest w ogóle wykonywany. Jeśli jednak skrypt lub funkcja jest wywoływana poza kontekstem potoku, ten blok jest wykonywany dokładnie raz, a $_ jest ustawione na $null, ponieważ nie ma bieżącego obiektu kolekcji.

Instrukcje w bloku końcowym (tj. takim oznaczonym słowem kluczowym "end") są wykonywane raz po dostarczeniu ostatniego obiektu potoku.

Blok dynamiczny 8.10.8

Podsekcje §8.10 do tej pory dotyczą parametrów statycznych, które są zdefiniowane jako część kodu źródłowego. Istnieje również możliwość zdefiniowania parametrów dynamicznych za pomocą bloku dynamicznego, innej formy nazwanego bloku (§8.10.7), która jest oznaczona słowem kluczowym dynamicparam. Wiele z tych elementów maszynowych jest określonych przez implementację.

Parametry dynamiczne to parametry polecenia cmdlet, funkcji, filtru lub skryptu, które są dostępne tylko w określonych warunkach. Jednym z takich przypadków jest parametr kodowania parametru cmdletu Set-Item.

W bloku instrukcji, użyj instrukcji if, aby określić, kiedy parametr jest dostępny w funkcji. Użyj polecenia cmdlet New-Object, aby utworzyć obiekt typu zdefiniowanego przez implementację do reprezentowania parametru i określić jego nazwę. Ponadto użyj New-Object, aby utworzyć obiekt innego typu zdefiniowanego przez implementację w celu reprezentowania atrybutów zdefiniowanych przez implementację parametru.

W poniższym przykładzie przedstawiono funkcję o standardowych parametrach o nazwie Name and Path oraz opcjonalny parametr dynamiczny o nazwie DP1. Parametr DP1 znajduje się w zestawie parametrów PSet1 i ma typ Int32. Parametr DP1 jest dostępny w funkcji Sample tylko wtedy, gdy wartość parametru Path zawiera wartość "HKLM:", wskazując, że jest używana na dysku rejestru HKEY_LOCAL_MACHINE.

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
        }
    }
}

Typ używany do utworzenia obiektu do reprezentowania parametru dynamicznego to System.Management.Automation.RuntimeDefinedParameter.

Typ używany do utworzenia obiektu do reprezentowania atrybutów parametru jest System.Management.Automation.ParameterAttribute.

Atrybuty zdefiniowane przez implementację parametru obejmują Obowiązkowy, Pozycjai ValueFromPipeline.

Blok paramowy 8.10.9

Blok parametrów zapewnia alternatywny sposób deklarowania parametrów. Na przykład następujące zestawy deklaracji parametrów są równoważne:

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

param-block umożliwia listę atrybutów na param-block, podczas gdy nie umożliwia deklaracji parametrów funkcji.

Skrypt może mieć param-block, ale nie deklaracja parametrów funkcji. Definicja funkcji lub filtru może mieć deklarację parametrów funkcji lub blok param-block, ale nie obie.

Rozważmy następujący przykład:

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

Jeden parametr, $ComputerName, ma typ string[], jest wymagany i pobiera dane wejściowe z potoku.

Zobacz §12.3.7, aby zapoznać się z omówieniem atrybutu parametru i aby uzyskać więcej przykładów.

8.11 Instrukcja równoległa

Składnia:

parallel-statement:
    *parallel* statement-block

Instrukcja równoległa zawiera zero lub więcej instrukcji, które są wykonywane w zdefiniowany sposób implementacji.

Instrukcja równoległa jest dozwolona tylko w przepływie pracy (§8.10.2).

8.12 Instrukcja sekwencji

Składnia:

sequence-statement:
    *sequence* statement-block

Instrukcja sequence zawiera zero lub więcej instrukcji, które są wykonywane w sposób zdefiniowany przez implementację.

Deklaracja sekwencji jest dozwolona tylko w ramach przepływu pracy (§8.10.2).

8.13 Instrukcja inlinescript

Składnia:

inlinescript-statement:
    inlinescript statement-block

Instrukcja inlinescript zawiera zero lub więcej instrukcji, które są wykonywane w zdefiniowany sposób implementacji.

Instrukcja śródliniowa jest dozwolona tylko w przepływie pracy (§8.10.2).

8.14 Powiązanie parametrów

Po wywołaniu skryptu, funkcji, filtru lub polecenia cmdlet każdy argument może być powiązany z odpowiednim parametrem według pozycji, przy użyciu pierwszego parametru o pozycji zero.

Rozważmy następujący fragment definicji funkcji o nazwie Get-Poweri wywołania do niej:

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

Po wywołaniu skryptu, funkcji, filtru lub polecenia cmdlet argument może być powiązany z odpowiednim parametrem według nazwy. Jest to wykonywane przy użyciu parametru z argumentem, który jest nazwą parametru poprzedzoną myślnikiem (-), a następnie powiązaną wartością dla tego argumentu. Używana nazwa parametru może mieć dowolną pisownię bez uwzględniania wielkości liter i może używać dowolnego prefiksu, który jednoznacznie wyznacza odpowiedni parametr. Podczas wybierania nazw parametrów unikaj używania nazw typowych parametrów .

Rozważ następujące wywołania funkcji 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

Z drugiej strony wywołania następującej funkcji

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

musi używać parametrów -Side1 i -Side2, ponieważ nie ma prefiksu, który jednoznacznie wyznacza parametr.

Tej samej nazwy parametru nie można używać wiele razy z różnymi skojarzonymi wartościami argumentów lub bez nich.

Parametry mogą mieć atrybuty (§12). Aby uzyskać informacje o poszczególnych atrybutach, zobacz sekcje w §12.3. Aby uzyskać informacje o zestawach parametrów, zobacz §12.3.7.

Skrypt, funkcja, filtr lub polecenie cmdlet mogą odbierać argumenty za pośrednictwem wiersza polecenia podczas wywołania, z potoku lub z obu tych źródeł. Poniżej przedstawiono procedurę rozpoznawania powiązania parametrów:

  1. Powiąż wszystkie nazwane parametry, a następnie
  2. Powiąż parametry pozycyjne, a następnie
  3. Powiązanie z potoku na podstawie wartości (§12.3.7) z dokładnym dopasowaniem, a następnie
  4. Wiąż z potoku według wartości (§12.3.7) z konwersją, a następnie
  5. Wiązać z potokiem według nazwy (§12.3.7) z dokładnym dopasowaniem, a następnie
  6. Łącz z potoku według nazwy (§12.3.7) z konwersją

Kilka z tych kroków obejmuje konwersję, zgodnie z opisem w §6. Jednak zestaw konwersji używanych w powiązaniu nie jest dokładnie taki sam jak w przypadku konwersji języka. Specyficznie

  • Mimo że wartość $null można rzutować na bool, $null nie można przypisać do bool.
  • Gdy wartość $null jest przekazywana do parametru przełącznika dla polecenia cmdlet, jest traktowana tak, jakby $true została przekazana. Jednak po przekazaniu do parametru przełącznika w funkcji, jest traktowany tak, jakby przekazano $false.
  • Parametry typu bool lub switch mogą wiązać się tylko z argumentami liczbowymi lub logicznymi.
  • Jeśli typ parametru nie jest kolekcją, ale argument jest pewnego rodzaju kolekcją, nie zostanie podjęta żadna konwersja, chyba że typ parametru jest obiektem lub obiektem PsObject. (Głównym punktem tego ograniczenia jest uniemożliwienie konwersji kolekcji na parametr ciągu). W przeciwnym razie są podejmowane zwykłe konwersje.

Jeśli typ parametru jest IList lub ICollection<T>, są podejmowane tylko te konwersje za pośrednictwem konstruktora, op_Implicit i op_Explicit. Jeśli takie konwersje nie istnieją, jest używana specjalna konwersja parametrów typu "kolekcja", która obejmuje IList, ICollection<T>i tablice.

Parametry pozycyjne wolą być powiązane bez konwersji typu, jeśli to możliwe. Na przykład

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"