Powershell: Analyse/passage de paramètres : les jetons sans guillemets qui ressemblent à des arguments nommés avec deux points comme séparateur sont divisés en deux lorsqu'ils sont transmis indirectement via $Args / @Args

Créé le 11 mars 2018  ·  3Commentaires  ·  Source: PowerShell/PowerShell

Connexes : #6291, #6292 et #4624

Suivi de https://github.com/PowerShell/PowerShell/issues/6292#issuecomment -371344550 :

Remarque : les jetons en question, tels que -foo:bar , _look_ comme des arguments PowerShell nommés (et, dans les coulisses, sont initialement toujours analysés comme tels - voir le commentaire de @BrucePay ci-dessous), mais doivent être transmis comme -is (sauf pour éventuellement étendre la chaîne) lors de l'appel de programmes externes.

Les jetons qui ressemblent à -foo.bar subissent le même sort (voir #6291).

Cela fonctionne déjà comme prévu avec le passage de l'argument _direct_ (par exemple,
echoArgs -foo:bar transmet -foo:bar comme argument unique
), mais pas en passant $Args / en l'éclaboussant ( @Args ).

Remarque : le problème est fondamental pour l'utilisation de $Args / @Args et, bien que peut-être moins courant, affecte également son utilisation lors de l'appel de commandes natives PowerShell - voir le commentaire ci-dessous .

Étapes à reproduire

Exécutez sur macOS ou Linux.

function baz {
  bash -c 'for a; do echo $a; done' - $Args   # note: same with <strong i="32">@Args</strong>
}

baz -foo:bar
'---'
baz -foo.bar

Comportement attendu

-foo:bar
---
-foo.bar

Comportement réel

-foo:
bar
---
-foo
.bar

Les arguments sont inopinément brisés en deux. Voir le commentaire lié pour le fond.

Données environnementales

PowerShell Core v6.0.1 on macOS 10.13.3
PowerShell Core v6.0.1 on Ubuntu 16.04.3 LTS
PowerShell Core v6.0.1 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Windows PowerShell v5.1.15063.674 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Issue-Discussion WG-Language

Commentaire le plus utile

Je viens de passer la semaine dernière à lutter contre ce problème. Après l'avoir recherché jusqu'à ce que les valeurs des paramètres de commutation forcés (comme -foo:$bar ) n'aient pas été définies après avoir éclaboussé avec @Args , j'ai pensé que cela devait être un problème de portée obscur. Imaginez ma surprise lorsque j'ai découvert que forcer une valeur de paramètre de commutateur de cette manière n'aurait pas le comportement attendu. Je l'ai testé même avec la version Powershell 7 Preview 1 et le même problème se pose toujours. J'espère que ce sera corrigé après plus d'un an de problème connu...

Pour référence, c'est le test que j'ai créé pour montrer le bogue. Vu sur une machine Server 2016 avec Powershell 7 Preview 1, ainsi qu'une machine Server 2012 R2 avec Powershell 5.1.

function foo
{
    param(
        [switch]$testArg = $false
    )

    write-host "Test arg value: '$testArg'"
}

function bar
{
    foo <strong i="9">@Args</strong>
}

$testSplat = @{
    testArg = $false
}

write-host "#### Foo tests ####"

foo
foo -testArg:$true
foo -testArg:$false
foo <strong i="10">@testSplat</strong>

write-host "#### Bar tests ####"

bar
bar -testArg:$true
bar -testArg:$false
bar <strong i="11">@testSplat</strong>

Tous les 3 commentaires

Remarque : les jetons en question, tels que - foo:bar ressemblent à des arguments PowerShell nommés,

@mklement0 Comme je le décris dans les commentaires du #6292, ces _sont_ nommés arguments PowerShell. Toujours. La liaison des paramètres est effectuée longtemps après la fin de la compilation. Maintenant, dans l'AST compilé, le jeton pour -foo: a un indicateur indiquant qu'il n'y avait pas d'espace après lui dans le code source. Le NativeCommandParameterBinder examine cet élément AST pour voir si l'indicateur est défini, puis concatène le paramètre et l'argument sans espace entre eux. S'il n'est pas défini, un espace est inséré. Cela ne fonctionne que si les arguments sont littéraux (c'est-à-dire que le NativeCommandParameter était l'accès à l'AST pour l'argument). Dans le cas des éclaboussures, les arguments sont des valeurs, pas des arguments littéraux, vous obtenez donc un espace.

Une façon de résoudre ce problème consiste à propager la propriété de jeton « NoSpace » dans les métadonnées sur la valeur de chaîne correspondante. Le NativeCommandParameterBinder pourrait alors vérifier ces métadonnées lors de la conversion de son tableau d'arguments en chaîne. Cela vaut probablement la peine de réfléchir un peu plus à cela pour voir s'il y a d'autres cas (en particulier * des cas spécifiques à nix) qui devraient être traités.

6492 (depuis fermé en tant que doublon) montre que l'éclaboussure de @args est également interrompue lors de l'appel de fonctions PowerShell (pas seulement de programmes externes) :

La prise en charge de ce scénario est probablement encore plus délicate, car l'on s'attend ici à ce que les paramètres nommés soient transmis tels quels, avec leurs types d'origine.

Voici une reproduction simplifiée :

function b {
  Param
  (
      [Switch] $p1,
      [int] $p2,
      $rest
  )
  "`$p1: [$p1]"
  "`$p2: [$p2]"
  "`$rest: [$rest]"
}

& { b <strong i="9">@args</strong> } -p1:$false 666
$p1: [True]  # `-p1:` was interpreted as just `-p1`
$p2: [0]      # `$false`, as a separate argument, was coerced to [int] 0
$rest: [666] # what was meant to be the 2nd argument was passed as the 3rd

La solution de contournement - et la solution préférable pour commencer - consiste à définir le même bloc param() dans la fonction de relais et splat avec @PSBoundParameters .

Je viens de passer la semaine dernière à lutter contre ce problème. Après l'avoir recherché jusqu'à ce que les valeurs des paramètres de commutation forcés (comme -foo:$bar ) n'aient pas été définies après avoir éclaboussé avec @Args , j'ai pensé que cela devait être un problème de portée obscur. Imaginez ma surprise lorsque j'ai découvert que forcer une valeur de paramètre de commutateur de cette manière n'aurait pas le comportement attendu. Je l'ai testé même avec la version Powershell 7 Preview 1 et le même problème se pose toujours. J'espère que ce sera corrigé après plus d'un an de problème connu...

Pour référence, c'est le test que j'ai créé pour montrer le bogue. Vu sur une machine Server 2016 avec Powershell 7 Preview 1, ainsi qu'une machine Server 2012 R2 avec Powershell 5.1.

function foo
{
    param(
        [switch]$testArg = $false
    )

    write-host "Test arg value: '$testArg'"
}

function bar
{
    foo <strong i="9">@Args</strong>
}

$testSplat = @{
    testArg = $false
}

write-host "#### Foo tests ####"

foo
foo -testArg:$true
foo -testArg:$false
foo <strong i="10">@testSplat</strong>

write-host "#### Bar tests ####"

bar
bar -testArg:$true
bar -testArg:$false
bar <strong i="11">@testSplat</strong>
Cette page vous a été utile?
0 / 5 - 0 notes