Partager via


8. Déclarations

Note éditoriale

Important

La spécification du langage Windows PowerShell 3.0 a été publiée en décembre 2012 et est basée sur Windows PowerShell 3.0. Cette spécification ne reflète pas l’état actuel de PowerShell. Il n’existe aucun plan de mise à jour de cette documentation pour refléter l’état actuel. Cette documentation est présentée ici pour référence historique.

Le document de spécification est disponible en tant que document Microsoft Word à partir du Centre de téléchargement Microsoft à l’adresse : https://www.microsoft.com/download/details.aspx?id=36389 ce document Word a été converti pour présentation ici sur Microsoft Learn. Pendant la conversion, certaines modifications éditoriales ont été apportées pour prendre en charge la mise en forme de la plateforme Docs. Certaines fautes de frappe et erreurs mineures ont été corrigées.

8.1 Blocs d’instructions et listes

Syntaxe:

Conseil

La notation ~opt~ dans les définitions de syntaxe indique que l’entité lexicale est facultative dans la syntaxe.

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

Description:

Une instruction spécifie une sorte d’action à effectuer. Sauf indication contraire dans cette clause, les instructions sont exécutées dans l’ordre lexical.

Un bloc d'instructions permet de regrouper un ensemble d’instructions en une seule unité syntaxique.

8.1.1 Déclarations étiquetées

Syntaxe:

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

Description:

Une instruction d’itération (§8.4) ou une instruction booléenne (§8.6) peut éventuellement être précédée immédiatement d’une étiquette d’instruction, label. Une étiquette d’instruction est utilisée comme cible facultative d’une instruction break (§8.5.1) ou continue (§8.5.2). Toutefois, une étiquette ne modifie pas le flux de contrôle.

L’espace blanc n’est pas autorisé entre le signe deux-points (:) et le jeton qui le suit.

Exemples:

: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 Valeurs d’instruction

La valeur d’une instruction est l’ensemble cumulatif de valeurs qu’elle envoie au pipeline. Si l’instruction écrit une valeur scalaire unique, alors cette valeur est celle de l’instruction. Si l’instruction écrit plusieurs valeurs, celles-ci représentent l’ensemble de valeurs stockées dans des éléments d’un tableau unidimensionnel non contraint, dans l’ordre dans lequel elles ont été écrites. Prenons l’exemple suivant :

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

Il n’existe aucune itération de la boucle et rien n’est écrit dans le pipeline. La valeur de l’instruction est $null.

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

Bien que la boucle itère cinq fois, rien n’est écrit dans le pipeline. La valeur de la déclaration est $null.

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

La boucle s'itère cinq fois, écrivant à chaque fois dans le pipeline la valeur int$i. La valeur de l’instruction est object[], de longueur 5.

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

Bien que la boucle itère cinq fois, rien n’est écrit dans le pipeline. La valeur de l’instruction est $null.

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

La boucle itère cinq fois avec chaque valeur écrite dans le pipeline. La valeur de l’instruction est object[], de longueur 5.

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

La boucle effectue une itération une seule fois. La valeur de l’instruction est l’int avec la valeur 2.

Voici quelques autres exemples :

# 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 Instructions de pipeline

Syntaxe:

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

Description:

Les redirections sont décrites dans le §7.12, assignment-expression est présenté dans le §7.11; et le point command-invocation-operator (.) est abordé dans le §3.5.5. Pour une discussion sur le mappage argument-à-paramètre dans les appels de commandes, consultez §8.14.

La première commande d’un pipeline est une expression ou un appel de commande. En règle générale, un appel de commande commence par un nom de commande, qui est généralement un identificateur nu. éléments de commande représente la liste d’arguments à la commande. Un point-virgule sans séquence d’échappement ou un caractère de nouvelle ligne met fin à un pipeline.

Un appel de commande se compose du nom de la commande suivi de zéro ou plusieurs arguments. Les règles régissant les arguments sont les suivantes :

  • Un argument qui n’est pas une expression, mais qui contient du texte arbitraire sans espace blanc non bouclé, est traité comme s’il était entre guillemets doubles. La casse est préservée.

  • La substitution de variable et l’extension de sous-expression (§2.3.5.2) ont lieu dans les expandable-string-literal et expandable-here-string-literal.

  • Le texte entre guillemets autorise l’inclusion des espaces blancs de début, de fin et incorporés dans la valeur de l’argument. [Remarque: la présence d’espaces blancs dans un argument entre guillemets ne transforme pas un seul argument en plusieurs arguments. fin de la remarque]

  • Le fait de placer des parenthèses autour d’un argument entraîne l’évaluation de cette expression avec le résultat passé au lieu du texte de l’expression d’origine.

  • Pour passer un argument qui ressemble à un paramètre de commutateur (§2.3.4) mais qui n’est pas prévu comme tel, placez cet argument entre guillemets.

  • Lorsque vous spécifiez un argument qui correspond à un paramètre ayant la contrainte de type [switch] (§8.10.5), la présence du nom de l’argument sur sa propre cause que ce paramètre doit être défini sur $true. Toutefois, la valeur du paramètre peut être définie explicitement en ajoutant un suffixe à l’argument. Par exemple, étant donné un paramètre contrainte de type p, un argument de -p:$true définit p sur True, tandis que -p:$false définit p sur False.

  • Un argument de -- indique que tous les arguments suivants doivent être passés sous leur forme réelle, comme si les guillemets doubles étaient placés autour d’eux.

  • Un argument de --% indique que tous les arguments suivants doivent être passés avec un minimum d’analyse et de traitement. Cet argument est appelé paramètre verbatim. Les arguments après le paramètre verbatim ne sont pas des expressions PowerShell, même si elles sont des expressions PowerShell syntactiquement valides.

Si le type de commande est Application, le paramètre --% n’est pas passé à la commande. Les arguments après --% ont des variables d’environnement (chaînes entourées de %) développées. Par exemple:

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

L’ordre d’évaluation des arguments n’est pas spécifié.

Pour plus d’informations sur la liaison de paramètres, consultez §8.14. Pour plus d’informations sur la recherche de noms, consultez §3.8.

Une fois le traitement des arguments terminé, la commande est appelée. Si la commande appelée se termine normalement (§8.5.4), le contrôle revient au point du script ou de la fonction immédiatement après l’appel de commande. Pour obtenir une description du comportement d’un arrêt anormal, consultez break (§8.5.1), continue (§8.5.2), throw (§8.5.3), exit (§8.5.5), try (§8.7) et trap (§8.8).

En règle générale, une commande est appelée à l’aide de son nom suivi de tous les arguments. Toutefois, l’opérateur d’appel de commande, &, peut être utilisé. Si le nom de la commande contient un espace blanc sans séquence d’échappement, il doit être placé entre guillemets et appelé avec cet opérateur. Comme un bloc de script n’a pas de nom, il doit également être appelé avec cet opérateur. Par exemple, les appels suivants d’un appel de commande Get-Factorial sont équivalents :

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

Les appels de fonction récursifs directs et indirects sont autorisés. Par exemple

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

Exemples:

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 L'instruction if

Syntaxe:

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

Description:

Le pipeline contrôlant les expressions doit être de type bool ou implicitement convertible en ce type. La else-clause est facultative. Il peut y avoir zéro ou plusieurs elseif-clause.

Si les tests de pipeline de niveau supérieur donnent True, le statement-block est exécuté et l’exécution de l’instruction se termine. Sinon, si une clause elseif est présente, et que son pipeline teste True, alors son bloc d'instructions est exécuté et l'exécution de l'instruction se termine. Sinon, si une else-clause est présente, son statement-block est exécuté.

Exemples:

$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 Instructions d’itération

8.4.1 L’instruction while

Syntaxe:

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

while-condition:
    new-lines~opt~ pipeline

Description:

L’expression de contrôle while-condition doit avoir le type bool ou être implicitement convertible en ce type. Le corps de la boucle, qui se compose d’un statement-block, est exécuté à plusieurs reprises jusqu’à ce que le test d’expression de contrôle ait la valeur False. L’expression de contrôle est évaluée avant chaque exécution du corps de la boucle.

Exemples:

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

8.4.2 L’instruction do

Syntaxe:

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

Description:

L’expression de contrôle while-condition doit avoir le type bool ou être implicitement convertible en ce type. Dans la forme while, le corps de la boucle, qui se compose d’un statement-block, est exécuté de façon répétée tant que l’expression de contrôle donne la valeur True. Sous la forme until, le corps de la boucle est exécuté à plusieurs reprises jusqu’à ce que l’expression de contrôle donne la valeur True. L’expression de contrôle est évaluée après chaque exécution du corps de la boucle.

Exemples:

$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 L’instruction for

Syntaxe:

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

Description:

L’expression de contrôle pour condition doit avoir le type bool ou être implicitement convertible en ce type. Le corps de la boucle, qui se compose d’un statement-block, est exécuté à plusieurs reprises tant que le test d’expression de contrôle a la valeur True. L’expression de contrôle est évaluée avant chaque exécution du corps de la boucle.

L’expression for-initializer est évaluée avant la première évaluation de l’expression de contrôle. L’expression for-initializer est évaluée pour ses effets secondaires uniquement. Toute valeur qu’elle produit est ignorée et n’est pas écrite dans le pipeline.

L’expression for-iterator est évaluée après chaque exécution du corps de la boucle. L’expression for-iterator est évaluée pour ses effets secondaires uniquement. Toute valeur qu’elle produit est ignorée et n’est pas écrite dans le pipeline.

Si l’expression pour condition est omise, l’expression de contrôle teste True.

Exemples:

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 L’instruction foreach

Syntaxe:

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

Description:

Le corps de la boucle, qui se compose d’un statement-block, est exécuté pour chaque élément désigné par la variable dans collection désignée par pipeline. L’étendue de variable n’est pas limitée à l’instruction foreach. Ainsi, elle conserve sa valeur finale une fois que le corps de la boucle a fini de s’exécuter. Si pipeline désigne un scalaire (à l’exclusion de la valeur $null) au lieu d’une collection, ce scalaire est traité comme une collection d’un élément. Si le pipeline désigne la valeur $null, le pipeline est traité comme une collection de zéro élément.

Si le foreach-parameter-parallel est spécifié, le comportement dépend de l'implémentation.

Le foreach-parameter ‑parallel n’est autorisé que dans un flux de travail (§8.10.2).

Chaque instruction foreach a son propre énumérateur, $foreach (§2.3.2.2, §4.5.16), qui existe uniquement pendant l’exécution de cette boucle.

Les objets générés par le pipeline sont collectés avant que le bloc d’instructions commence à s’exécuter. Toutefois, avec l'applet de commande ForEach-Object, le bloc d'instructions est exécuté sur chaque objet lorsqu’il est produit.

Exemples:

$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 Instructions de contrôle de flux

Syntaxe:

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

Description:

Une instruction de contrôle de flux entraîne un transfert inconditionnel du contrôle vers un autre emplacement.

8.5.1 L’instruction break

Description:

Une instruction break avec une label-expression est appelée instruction break étiquetée. Une instruction break sans label-expression est appelée instruction break sans étiquette.

En dehors d’une instruction trap, une instruction break sans étiquette directement au sein d’une instruction d’itération (§8.4) termine l’exécution de cette plus petite instruction d’itération englobante. Une instruction break sans étiquette directement dans une instruction booléenne (§8.6) termine la recherche de critères spéciaux pour la switch-condition du commutateur actuel. Pour plus d’informations sur l’utilisation de break à partir d’une instruction trap, consultez (§8.8).

Une instruction d’itération ou une instruction switch peut éventuellement être précédée immédiatement d’une étiquette d’instruction (§8.1.1). Une telle étiquette d’instruction peut être utilisée comme cible d’une instruction break étiquetée, auquel cas, cette instruction met fin à l’exécution de l’instruction d’itération englobante ciblée.

Un break étiqueté n’a pas besoin d’être résolu dans une étendue locale. La recherche d’une étiquette correspondante peut continuer jusqu’à la pile appelante même entre les limites de script et d’appel de fonction. Si aucune étiquette correspondante n’est trouvée, l’appel de commande actuel est arrêté.

Le nom de l’étiquette désignée par expression d’étiquette n’a pas besoin d’avoir une valeur constante.

Si une expression d’étiquette est une expression unaire , elle est convertie en chaîne.

Exemples:

$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 L’instruction continue

Description:

Une instruction continue avec une expression d’étiquette est appelée une instruction continue étiquetée . Une instruction continue sans label-expression est appelée instruction continue sans étiquette.

L’utilisation de continue à partir d’une instruction trap est décrite dans §8.8.

Une instruction continue sans étiquette dans une boucle termine l’exécution de la boucle en cours et transfère le contrôle à l’accolade fermante de l’instruction d’itération englobante la plus petite (§8.4). Une instruction continue sans étiquette dans un commutateur met fin à l’exécution de l’itération switch actuelle et transfère le contrôle à la plus petite switch du englobant (§8.6).

Une instruction d’itération ou une instruction switch (§8.6) peut éventuellement être précédée immédiatement d’une étiquette d’instruction (§8.1.1). Une telle étiquette d’instruction peut être utilisée comme cible d’une instruction continue étiquetée englobée, auquel cas cette instruction met fin à l’exécution de la boucle ou de l’itération switch en cours et transfère le contrôle à l’itération ou à l’étiquette d’instruction switch englobante ciblée.

Un continue étiqueté n’a pas besoin d’être résolu dans une étendue locale. La recherche d’une étiquette correspondante peut continue jusqu’à la pile appelante même entre les limites de script et d’appel de fonction. Si aucune étiquette correspondante n’est trouvée, l’appel de commande actuel est arrêté.

Le nom de l’étiquette désignée par expression d’étiquette n’a pas besoin d’avoir une valeur constante.

Si une expression d’étiquette est une expression unaire , elle est convertie en chaîne.

Exemples:

$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 L’instruction throw

Description:

Une exception est un moyen de gérer une condition d’erreur au niveau du système ou de l’application. L’instruction throw déclenche une exception. (Consultez §8.7 pour une discussion sur la gestion des exceptions.)

Si le pipeline est omis et que l’instruction throw n’est pas dans une catch-clause, le comportement est défini par l’implémentation. Si le pipeline est présent et que l’instruction throw se trouve dans une catch-clause, l’exception interceptée par cette catch-clause est de nouveau levée après l’exécution d’une finally-clause associée à la catch-clause.

Si le pipeline est présent, le type de l’exception levée est défini par l’implémentation.

Quand une exception est levée, le contrôle est transféré à la première clause catch dans une instruction try englobante qui peut gérer l’exception. L’emplacement où l’exception est levée initialement est appelé point de levée. Une fois qu’une exception est levée, les étapes décrites dans §8.7 sont suivies à plusieurs reprises jusqu’à ce qu’une clause catch qui corresponde à l’exception soit trouvée ou qu’aucune exception ne soit trouvée.

Exemples:

throw
throw 100
throw "No such record in file"

Si le pipeline est omis et que l’instruction throw n’est pas à l’intérieur d’une clause catch, le texte « ScriptHalted » est écrit dans le pipeline, et le type de l’exception levée est System.Management.Automation.RuntimeException.

Si le pipeline est présent, l’exception levée est encapsulée dans un objet de type System.Management.Automation.RuntimeException, qui comprend des informations sur l’exception en tant qu’objet System.Management.Automation.ErrorRecord (accessible via $_).

Exemple 1 : throw 123 entraîne une exception de type RuntimeException. À partir du bloc catch, $_.TargetObject contient l’objet encapsulé dans, dans notre cas, System.Int32 avec la valeur 123.

Exemple 2 : throw "xxx" entraîne une exception de type runtimeException. À partir du bloc catch, $_.TargetObject contient l’objet encapsulé dans, dans notre cas, System.String avec la valeur « xxx ».

Exemple 3 : throw 10,20 entraîne une exception de type RuntimeException. À partir du bloc catch, $_.TargetObject contient l’objet encapsulé dans, dans notre cas, un System.Object[], un tableau sans contrainte de deux éléments avec les valeurs System. Int32` 10 et 20.

8.5.4 L’instruction return

Description:

L’instruction return écrit dans le pipeline les valeurs désignées par pipeline, le cas échéant, et retourne le contrôle à l’appelant de la fonction ou du script. Une fonction ou un script peut avoir zéro ou plusieurs instructions return.

Si l’exécution atteint l’accolade fermante d’une fonction, un return implicite sans pipeline est pris par défaut.

L’instruction return est un peu de « sucre syntaxique » pour permettre aux programmeurs de s’exprimer comme ils le peuvent dans d’autres langues ; Toutefois, la valeur retournée à partir d’une fonction ou d’un script est en fait toutes les valeurs écrites dans le pipeline par cette fonction ou ce script, ainsi que toutes les valeurs spécifiées par pipeline. Si seule une valeur scalaire est écrite dans le pipeline, son type est le type de la valeur retournée ; sinon, le type de retour est un tableau 1 dimensionnel non contraint contenant toutes les valeurs écrites dans le pipeline.

Exemples:

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

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

L’appelant à Get-Factorial récupère un 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
}

L’appelant à Test récupère un tableau unidimensionnel non restreint de trois éléments.

8.5.5 L’instruction exit

Description:

L’instruction exit met fin au script actuel et retourne le contrôle et un code de sortie à l’environnement hôte ou au script appelant. Si le pipeline est fourni, la valeur qu’il désigne est convertie en int, si nécessaire. Si aucune conversion de ce type n’existe ou si pipeline est omis, la valeur int zéro est retournée.

Exemples:

exit $count # terminate the script with some accumulated count

8.6 L’instruction switch

Syntaxe:

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

Description:

Si la condition de commutateur désigne une valeur unique, le contrôle est passé à un ou plusieurs blocs d’instructions de modèle correspondants. Si aucun modèle ne correspond, une action par défaut peut être effectuée.

Un commutateur doit contenir une ou plusieurs clauses de commutation , chacune commençant par un modèle (une clause de commutation non par défaut ), ou le mot clé default (une clause de commutation par défaut ). Un commutateur doit contenir zéro ou une default clauses booléennes, et zéro, une ou plusieurs clauses booléennes hors défaut. Les clauses Switch peuvent être écrites dans n’importe quel ordre.

Plusieurs modèles peuvent avoir la même valeur. Un modèle n’a pas besoin d’être un littéral, et un commutateur peut avoir des modèles avec différents types.

Si la valeur de switch-condition correspond à une valeur de modèle, le statement-block de ce modèle est exécuté. Si plusieurs valeurs de modèle correspondent à la valeur de switch-condition, le statement-block de chaque modèle correspondant est exécuté, dans l’ordre lexical, sauf si l’un de ces statement-block contient une instruction break (§8.5.1).

Si la valeur de condition de commutation ne correspond à aucune valeur modèle, si une clause de commutation default existe, son bloc d'instructions est exécuté ; sinon, la recherche de correspondance pour cette condition de commutation est terminée.

Les commutateurs peuvent être imbriqués, chaque commutateur ayant son propre ensemble de clauses switch. Dans ce cas, une clause booléenne appartient au commutateur le plus profond actuellement dans l’étendue.

À l’entrée de chaque statement-block, $_ reçoit automatiquement la valeur de la switch-condition qui a provoqué l’accès à ce statement-block. $_ est également disponible dans la switch-clause-condition de ce statement-block.

La correspondance des éléments non textuels s'effectue en testant l'égalité (§7.8.1).

Si la correspondance implique des chaînes, par défaut, la comparaison ne respecte pas la casse. La présence du switch-parameter-CaseSensitive rend la comparaison sensible à la casse.

Un modèle peut contenir des caractères génériques (§3.15), auquel cas, les comparaisons de chaînes génériques sont effectuées, mais uniquement si le paramètre-Wildcard switch est présent. Par défaut, la comparaison respecte la casse.

Un modèle peut contenir une expression régulière (§3.16), auquel cas, les comparaisons de chaînes d’expression régulière sont effectuées, mais uniquement si le switch-parameter-Regex est présent. Par défaut, la comparaison respecte la casse. Si -Regex est présent et qu’un modèle correspond, $Matches est défini dans le switch-clausestatement-block pour ce modèle.

Un switch-parameter peut être abrégé. Tout élément de début distinct d’un paramètre peut être utilisé. Par exemple, ‑Regex, ‑Rege, ‑Reg, ‑Reet ‑R sont équivalents.

Si des switch-parameter en conflit sont spécifiés, le dernier spécifié lexicalement est prioritaire. La présence de ‑Exact désactive -Regex et -Wildcard; elle n’a aucun impact sur ‑Case, cependant.

Si le switch-parameter ‑Parallel est spécifié, le comportement est défini par l'implémentation.

Le switch-parameter‑Parallel est autorisé uniquement dans un workflow (§8.10.2).

Si un modèle est un script-block-expression, ce bloc est évalué et le résultat est converti en bool, si nécessaire. Si le résultat a la valeur , le de bloc d’instructions correspondant est exécuté ; sinon, ce n’est pas le cas.

Si la condition de commutateur désigne plusieurs valeurs, le commutateur est appliqué à chaque valeur dans l'ordre lexical, à l'aide des règles décrites ci-dessus pour une condition de commutateur qui désigne une seule valeur. Chaque instruction switch a son propre énumérateur, $switch (§2.3.2.2, §4.5.16), qui existe uniquement pendant l’exécution de ce commutateur.

Une instruction switch peut avoir une étiquette, et elle peut contenir des instructions break (§8.5.1) et continue (§8.5.2), étiquetées et non étiquetées.

Si switch-condition est -Fileswitch-filename, au lieu d’effectuer une itération au sein des valeurs d’une expression, le commutateur itère au sein des valeurs dans le fichier désigné par switch-filename. Le fichier lit une ligne à la fois avec chaque ligne contenant une valeur. Les caractères de fin de ligne ne sont pas inclus dans les valeurs.

Exemples:

$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 L’instruction try/finally

Syntaxe:

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

Description:

L’instruction try fournit un mécanisme permettant d’intercepter les exceptions qui se produisent pendant l’exécution d’un bloc. L’instruction try permet également de spécifier un bloc de code qui est toujours exécuté lorsque le contrôle quitte l’instruction try. Le processus de déclenchement d’une exception via l’instruction throw est décrit dans §8.5.3.

Un bloc try est le statement-block associé à l’instruction try. Un bloc catch est le statement-block associé à une catch-clause. Un bloc finally est le statement-block associé à une finally-clause.

Une catch-clause sans catch-type-list est appelée clause catch générale.

Chaque catch-clause est un gestionnaire d’exceptions, et une catch-clause dont la catch-type-list contient le type de l’exception levée est une clause catch correspondante. Une clause catch générale correspond à tous les types d’exceptions.

Bien que les catch-clause et la finally-clause soient facultatives, au moins l’une d’entre elles doit être présente.

Le traitement d’une exception levée consiste à évaluer les étapes suivantes à plusieurs reprises jusqu’à ce qu’une clause catch correspondant à l’exception soit trouvée.

  • Dans l’étendue actuelle, chaque instruction try qui encadre le point de levée d’exception est examinée. Pour chaque instruction try S, en commençant par l’instruction try la plus interne et se terminant par l’instruction try la plus externe, les étapes suivantes sont évaluées :

    • Si le bloc try de S englobe le point de levée et si S a une ou plusieurs clauses catch, les clauses catch sont examinées dans l’ordre lexical pour trouver un gestionnaire approprié pour l’exception. La première clause catch qui spécifie le type d’exception ou un type de base du type de l’exception est considérée comme une correspondance. Une clause catch générale est compatible avec n’importe quel type d’exception. Si une clause catch correspondante se trouve, le traitement des exceptions est terminé en transférant le contrôle vers le bloc de cette clause catch. Dans une clause catch correspondante, la variable $_ contient une description de l’exception actuelle.

    • Sinon, si le bloc try ou un bloc catch de S entoure le point de levée et si S a un bloc finally, le contrôle est transféré vers le bloc final. Si le bloc finally lève une autre exception, le traitement de l’exception actuelle est arrêté. Sinon, lorsque le contrôle atteint la fin du bloc finally, le traitement de l’exception actuelle est continué.

  • Si un gestionnaire d’exceptions n’était pas situé dans l’étendue actuelle, les étapes ci-dessus sont répétées pour l’étendue englobante avec un point de levée correspondant à l’instruction à partir de laquelle l’étendue actuelle a été appelée.

  • Si le processus de gestion des exceptions aboutit à la terminaison de toutes les étendues, et qu'il n'existe aucun gestionnaire pour l'exception, alors le comportement n'est pas spécifié.

Pour empêcher la non-accessibilité des clauses catch dans un bloc try, une clause catch ne peut pas spécifier un type d’exception qui est égal à ou dérivé d’un type spécifié dans une clause catch antérieure dans ce même bloc try.

Les instructions d’un bloc finally sont toujours exécutées lorsque le contrôle quitte une instruction try. Cela est vrai si le transfert de contrôle se produit suite à une exécution normale, à la suite de l’exécution d’une instruction break, continueou return, ou à la suite d’une exception levée de l’instruction try.

Si une exception est levée pendant l’exécution d’un bloc finally, l’exception est levée pour l’instruction try englobante suivante. Si une autre exception était en cours de traitement, cette exception est perdue. Le processus de génération d’une exception est décrit plus en détail dans la description de l’instruction throw.

try instructions peuvent coexister avec des instructions trap ; consultez §8.8 pour plus d’informations.

Exemples:

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

Chaque exception levée est déclenchée comme une System.Management.Automation.RuntimeException. S’il existe des catch-clause spécifiques au type dans le bloc try, la propriété InnerException de l’exception est inspectée pour essayer de trouver une correspondance, par exemple avec le type System.IndexOutOfRangeException ci-dessus.

8.8 L’instruction trap

Syntaxe:

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

Description:

Une instruction trap avec et sans type-literal est analogue à un bloc catch (§8.7) avec et sans catch-type-list, respectivement, sauf qu’une instruction trap ne peut intercepter qu’un seul type à la fois.

Plusieurs instructions peuvent être définies dans le mêmede bloc d’instructions , et leur ordre de définition n’est pas pertinent. Si deux instructions trap avec le même type-literal sont définies dans la même portée, la première est utilisée pour traiter une exception de type correspondant.

Contrairement à un bloc catch, une instruction trap correspond exactement à un type d’exception ; aucune correspondance de type dérivée n’est effectuée.

Lorsqu’une exception se produit, si aucune instruction trap correspondante n’est présente dans l’étendue actuelle, une instruction trap correspondante est recherchée dans l’étendue englobante, ce qui peut impliquer l’examen du script, de la fonction ou du filtre appelant, puis dans son appelant, et ainsi de suite. Si la recherche finit par mettre fin à toutes les étendues, ce qui indique qu’il n’existe aucun gestionnaire pour l’exception, alors le comportement n’est pas spécifié.

Le trap d’une instruction s’exécute uniquement pour traiter l’exception correspondante. Sinon, l’exécution la passe.

Si le trap d’une instruction se termine normalement, par défaut, un objet d’erreur est écrit dans le flux d’erreur, l’exception est considérée comme gérée et l’exécution continue avec l’instruction qui suit immédiatement celle de l’étendue contenant l’instruction trap qui a rendu l’exception visible. La cause de l’exception peut se trouver dans une commande appelée par la commande contenant l’instruction trap.

Si la dernière instruction exécutée dans le trap de l’instruction est continue (§8.5.2), l’écriture de l’objet d’erreur dans le flux d’erreur est supprimée et l’exécution se poursuit avec l’instruction qui suit immédiatement celle de l’étendue contenant l’instruction trap qui a rendu l’exception visible. Si la dernière instruction exécutée dans le trap de l’instruction est arrêtée (§8.5.1), l’écriture de l’objet d’erreur dans le flux d’erreur est supprimée et l’exception est de nouveau levée.

Dans une instruction trap, la variable $_ contient une description de l’erreur actuelle.

Considérez le cas où une exception levée à partir d’un bloc try n’a pas de bloc de catch correspondant, mais une instruction de trap correspondante existe à un niveau de bloc supérieur. Après l’exécution de la clause finally du bloc try, l’instruction trap obtient le contrôle même si une étendue parente a un bloc catch correspondant. Si une instruction trap est définie dans le bloc try lui-même et que try bloc a un bloc catch correspondant, l’instruction trap obtient le contrôle.

Exemples:

Dans l’exemple suivant, l’objet d’erreur est écrit et l’exécution se poursuit avec l’instruction qui suit immédiatement celle qui a provoqué l’interruption. Autrement dit, « Done » est écrit dans le pipeline.

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

Dans l’exemple suivant, l’écriture de l’objet d’erreur est supprimée et l’exécution se poursuit avec l’instruction qui suit immédiatement celle qui a provoqué l’interruption. Autrement dit, « Done » est écrit dans le pipeline.

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

Dans l’exemple suivant, l’écriture de l’objet d’erreur est supprimée et l’exception est levée à nouveau.

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

Dans l’exemple suivant, les instructions trap et de génération d’exception se trouvent dans la même étendue. Une fois l’exception interceptée et gérée, l’exécution reprend en écrivant 1 dans le pipeline.

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

Dans l’exemple suivant, les instructions trap et de génération d’exception se trouvent dans des étendues différentes. Une fois l’exception interceptée et gérée, l’exécution reprend en écrivant 2 (et non 1) dans le pipeline.

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

8.9 La déclaration de données

Syntaxe:

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

Description:

Une instruction de données crée une section de données , en conservant les données de cette section distinctes du code. Cette séparation prend en charge les fonctionnalités telles que des fichiers de ressources de chaîne distincts pour du texte, telles que les messages d’erreur et les chaînes d’aide. Il permet également de prendre en charge l’internationalisation en facilitant l’isolation, la localisation et le traitement des chaînes qui seront traduites dans différentes langues.

Un script ou une fonction peut avoir zéro ou plusieurs sections de données.

Dans le bloc d'instructions de la section de données, seules les fonctionnalités PowerShell suivantes sont autorisées :

  • Tous les opérateurs, sauf -match
  • Instruction if
  • Les variables automatiques suivantes : $PSCulture, $PSUICulture, $true, $falseet $null.
  • Commentaires
  • Pipelines
  • Instructions séparées par des points-virgules (;)
  • Littéraux
  • Appels à la cmdlet ConvertFrom-StringData
  • Toutes les autres applets de commande identifiées via le paramètre SupportedCommand

Si l’applet de commande ConvertFrom-StringData est utilisée, les paires clé/valeur peuvent être exprimées à l’aide de n’importe quelle forme de littéral de chaîne. Toutefois, les expandable-string-literal et expandable-here-string-literal ne doivent pas contenir de substitutions de variables ou d’extension de sous-expression.

Exemples:

Le paramètre SupportedCommand indique que les applets de commande ou fonctions données ne génèrent que des données. Par exemple, la section de données suivante inclut une applet de commande écrite par l’utilisateur, ConvertTo-Xml, qui met en forme les données dans un fichier XML :

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

Prenons l’exemple suivant, dans lequel la section de données contient une commande ConvertFrom-StringData qui convertit les chaînes en table de hachage, dont la valeur est affectée à $messages.

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

Les clés et les valeurs de la table de hachage sont accessibles à l’aide de $messages.Greeting, $messages.Yeset $messages.No, respectivement.

Vous pouvez maintenant enregistrer cette ressource sous forme de ressource en anglais. Les ressources en allemand et en espagnol peuvent être créées dans des fichiers distincts, avec les sections de données suivantes :

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

Si dataname est présent, il nomme la variable (sans utiliser un $initial) dans laquelle la valeur de l'instruction de données doit être stockée. Plus précisément, $name = data { ... } équivaut à data name { ... }.

Définitions de fonction 8.10

Syntaxe:

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

Description:

Une définition de fonction spécifie le nom de la fonction, du filtre ou du flux de travail en cours de définition et les noms de ses paramètres, le cas échéant. Elle contient également zéro ou plusieurs instructions qui sont exécutées pour atteindre l’objectif de cette fonction.

Chaque fonction est une instance de la classe System.Management.Automation.FunctionInfo.

8.10.1 Fonctions de filtre

Alors qu’une fonction ordinaire s’exécute une fois dans un pipeline et accède à la collection d’entrée via $input, un filtre est un type spécial de fonction qui s’exécute une fois pour chaque objet de la collection d’entrée. L’objet en cours de traitement est disponible via la variable $_.

Un filtre sans blocs nommés (§8.10.7) équivaut à une fonction avec un bloc de processus, mais sans bloc de début ou de fin.

Prenez en considération la définition suivante d'une fonction de filtre et ses appels :

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

Chaque filtre est une instance de la classe System.Management.Automation.FilterInfo (§4.5.11).

Fonctions de flux de travail 8.10.2

Une fonction de flux de travail est semblable à une fonction ordinaire avec la sémantique définie par l’implémentation. Une fonction de flux de travail est traduite en une séquence d’activités Windows Workflow Foundation et exécutée dans le moteur Windows Workflow Foundation.

8.10.3 Traitement des arguments

Considérez la définition suivante pour une fonction appelée Get-Power:

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

Cette fonction a deux paramètres, $Base et $Exponent. Il contient également un ensemble d’instructions qui, pour les valeurs exposantes non négatives, calcule $Base^$Exponent^ et retourne le résultat à Get-Power'appelant.

Lorsqu’un script, une fonction ou un filtre commence l’exécution, chaque paramètre est initialisé à la valeur de son argument correspondant. S’il n’existe aucun argument correspondant et qu’une valeur par défaut (§8.10.4) est fournie, cette valeur est utilisée ; sinon, la valeur $null est utilisée. Par conséquent, chaque paramètre est une nouvelle variable comme si elle a été initialisée par affectation au début de l'de bloc de script.

Si un paramètre de script contient une contrainte de type (par exemple, [long] et [int] ci-dessus), la valeur de l’argument correspondant est convertie en ce type, si nécessaire ; sinon, aucune conversion ne se produit.

Lorsqu’un script, une fonction ou un filtre commence l’exécution, la variable $args est définie à l’intérieur de celle-ci en tant que tableau 1 dimensionnel sans contrainte, qui contient tous les arguments non liés par nom ou position, dans l’ordre lexical.

Tenez compte de la définition et des appels de fonction suivants :

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

Pour plus d’informations sur la liaison de paramètres, consultez §8.14.

8.10.4 Initialiseurs de paramètres

La déclaration d’un paramètre p peut contenir un initialiseur, auquel cas, la valeur de l’initialiseur est utilisée pour initialiser p à condition que p ne soit liée à aucun argument dans l’appel.

Tenez compte de la définition et des appels de fonction suivants :

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 La contrainte de type [switch]

Lorsqu’un paramètre de commutateur est passé, le paramètre correspondant dans la commande doit être contraint par le commutateur de type. Le commutateur de type a deux valeurs, True et False.

Tenez compte de la définition et des appels de fonction suivants :

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 et fonctions

Lorsqu’un script, une fonction ou un filtre est utilisé dans un pipeline, une collection de valeurs est remise à ce script ou à cette fonction. Le script, la fonction ou le filtre accède à cette collection via l’énumérateur $input (§2.3.2.2, §4.5.16), qui est défini sur l’entrée à ce script, fonction ou filtre.

Tenez compte de la définition et des appels de fonction suivants :

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 Blocs nommés

Les instructions au sein d'un script-bloc peuvent appartenir à un large bloc sans nom, ou elles peuvent être réparties dans un ou plusieurs blocs nommés. Les blocs nommés autorisent le traitement personnalisé des regroupements provenant de pipelines ; Les blocs nommés peuvent être définis dans n’importe quel ordre.

Les instructions d’un bloc de début (c’est-à-dire, marquées avec le mot clé begin) sont exécutées une fois, avant la remise du premier objet de pipeline.

Les instructions d’un bloc de processus (c’est-à-dire marquées avec le processus de mot clé) sont exécutées pour chaque objet de pipeline remis. ($_ fournit l’accès à l’objet actuel en cours de traitement à partir de la collection d’entrée provenant du pipeline.) Cela signifie que si une collection d’éléments zéro est envoyée via le pipeline, le bloc de processus n’est pas exécuté du tout. Toutefois, si le script ou la fonction est appelé en dehors d’un contexte de pipeline, ce bloc est exécuté exactement une fois et $_ est défini sur $null, car il n’existe aucun objet de collection actuel.

Les instructions d’un bloc end (c’est-à-dire un bloc marqué avec le mot clé end) sont exécutées une fois, après la remise du dernier objet de pipeline.

8.10.8 Bloc dynamicparam

Les sous-sections de §8.10 jusqu’à présent traitent des paramètres statiques , qui sont définis dans le code source. Il est également possible de définir paramètres dynamiques via un bloc dynamicparam, une autre forme de bloc nommé (§8.10.7), qui est marquée avec le mot clé dynamicparam. La plupart de ces machines sont définies par l’implémentation.

Les paramètres dynamiques sont des paramètres d’une applet de commande, d’une fonction, d’un filtre ou d’un script qui sont disponibles uniquement dans certaines conditions. L’un de ces cas est le paramètre Encoding de l’applet de commande Set-Item.

Dans le bloc d'instructions , utilisez une instruction if pour spécifier les conditions dans lesquelles le paramètre est accessible dans la fonction. Utilisez l’applet de commande new-object pour créer un objet d’un type défini par l’implémentation pour représenter le paramètre et spécifier son nom. Utilisez également New-Object pour créer un objet d’un type défini par l’implémentation différent pour représenter les attributs définis par l’implémentation du paramètre.

L’exemple suivant montre une fonction avec des paramètres standard appelés Nom et Chemin d’accès, ainsi qu’un paramètre dynamique facultatif nommé DP1. Le paramètre DP1 se trouve dans le jeu de paramètres PSet1 et a un type de Int32. Le paramètre DP1 est disponible dans la fonction Sample uniquement lorsque la valeur du paramètre Path contient « HKLM : », indiquant qu’il est utilisé dans le lecteur de Registre 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
        }
    }
}

Le type utilisé pour créer un objet pour représenter un paramètre dynamique est System.Management.Automation.RuntimeDefinedParameter.

Le type utilisé pour créer un objet pour représenter les attributs du paramètre est System.Management.Automation.ParameterAttribute.

Les attributs définis par l’implémentation du paramètre incluent obligatoire, positionet ValueFromPipeline.

8.10.9 Bloc param

Un bloc de paramètres fournit un autre moyen de déclarer des paramètres. Par exemple, les ensembles de déclarations de paramètres suivants sont équivalents :

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

Un param-block permet d’obtenir une attribute-list sur le param-block, contrairement à une function-parameter-declaration.

Un script peut avoir un param-block mais pas une function-parameter-declaration. Une définition de fonction ou de filtre peut avoir une function-parameter-declaration ou un param-block, mais pas les deux.

Prenons l’exemple suivant :

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

Le seul paramètre, $ComputerName, est de type string[], il est requis, et il reçoit une entrée du pipeline.

Consultez §12.3.7 pour une discussion sur l’attribut Paramètre et pour plus d’exemples.

8.11 L’instruction parallel

Syntaxe:

parallel-statement:
    *parallel* statement-block

L’instruction parallèle contient zéro ou plusieurs instructions exécutées de manière définie par l’implémentation.

Une instruction parallèle est autorisée uniquement dans un flux de travail (§8.10.2).

8.12 L’instruction sequence

Syntaxe:

sequence-statement:
    *sequence* statement-block

L’instruction sequence contient zéro ou plusieurs instructions qui sont exécutées d’une façon définie par l’implémentation.

Une instruction de séquence n’est autorisée que dans un flux de travail (§8.10.2).

8.13 L’instruction inlinescript

Syntaxe:

inlinescript-statement:
    inlinescript statement-block

L’instruction inlinescript contient zéro ou plusieurs instructions qui sont exécutées de manière définie par l’implémentation.

Une instruction inlinescript n’est autorisée que dans un flux de travail (§8.10.2).

8.14 Liaison de paramètres

Lorsqu’un script, une fonction, un filtre ou une applet de commande est appelé, chaque argument peut être lié au paramètre correspondant par position, avec le premier paramètre ayant la position zéro.

Considérez le fragment de définition suivant pour une fonction appelée Get-Power, et les appels à celui-ci :

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

Lorsqu’un script, une fonction, un filtre ou une applet de commande est appelé, un argument peut être lié au paramètre correspondant par nom. Pour ce faire, utilisez un paramètre avec l’argument, qui est un argument qui est le nom du paramètre avec un tiret de début (-), suivi de la valeur associée pour cet argument. Le nom du paramètre utilisé peut avoir une orthographe qui ne respecte pas la casse et peut utiliser n’importe quel préfixe qui désigne le paramètre correspondant de manière unique. Lorsque vous choisissez des noms de paramètres, évitez d’utiliser les noms des paramètres courants .

Considérez les appels suivants à la fonction 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

En revanche, les appels à la fonction suivante

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

doit utiliser des paramètres -Side1 et -Side2, car il n’existe aucun préfixe qui désigne de manière unique le paramètre.

Le même nom de paramètre ne peut pas être utilisé plusieurs fois avec ou sans valeurs d’argument associées différentes.

Les paramètres peuvent avoir des attributs (§12). Pour plus d’informations sur les attributs individuels, consultez les sections de §12.3. Pour plus d’informations sur les jeux de paramètres, consultez §12.3.7.

Un script, une fonction, un filtre ou une applet de commande peuvent recevoir des arguments via la ligne de commande d’appel, à partir du pipeline ou des deux. Voici les étapes, dans l’ordre, pour la résolution de la liaison de paramètres :

  1. Lier tous les paramètres nommés, puis
  2. Lier des paramètres positionnels, puis
  3. Liez à partir du pipeline par valeur (§12.3.7) avec une correspondance exacte, puis
  4. Liez à partir du pipeline par valeur (§12.3.7) avec conversion, puis
  5. Liez à partir du pipeline par nom (§12.3.7) avec une correspondance exacte, puis
  6. Liez à partir du pipeline par nom (§12.3.7) avec conversion

Plusieurs de ces étapes impliquent la conversion, comme décrit dans §6. Toutefois, l’ensemble des conversions utilisées dans la liaison n’est pas exactement le même que celui utilisé dans les conversions de langage. Spécifiquement

  • Bien que la valeur $null puisse être castée en bool, $null ne peut pas être liée à bool.
  • Lorsque la valeur $null est passée à un paramètre switch pour une applet de commande, elle est traitée comme si $true a été passée. Toutefois, lorsqu’elle est passée à un paramètre booléen pour une fonction, elle est traitée comme si $false a été passé.
  • Les paramètres de type bool ou switch peuvent uniquement être liés à des arguments numériques ou bool.
  • Si le type de paramètre n’est pas une collection, mais que l’argument est une sorte de collection, aucune conversion n’est tentée, sauf si le type de paramètre est objet ou PsObject. (Le point principal de cette restriction consiste à interdire la conversion d’une collection en paramètre de chaîne.) Sinon, les conversions habituelles sont tentées.

Si le type de paramètre est IList ou ICollection<T>, seules ces conversions via le constructeur, op_Implicit et op_Explicit sont tentées. Si aucune conversion de ce type n’existe, une conversion spéciale pour les paramètres du type « collection » est utilisée, qui inclut IList, ICollection<T>et les tableaux.

Les paramètres positionnels préfèrent être liés sans conversion de type, si possible. Par exemple

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"