Powershell: Parâmetro de análise / passagem: tokens não citados que se parecem com argumentos nomeados com dois pontos como separador são quebrados em dois quando passados ​​indiretamente via $ Args / @Args

Criado em 11 mar. 2018  ·  3Comentários  ·  Fonte: PowerShell/PowerShell

Relacionado: # 6291, # 6292 e # 4624

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

Observação: os tokens em questão, como -foo:bar , _parecem_ como argumentos nomeados do PowerShell (e, nos bastidores, são inicialmente sempre analisados ​​como tal - consulte o comentário de @BrucePay abaixo), mas devem ser transmitidos como -is (exceto para possivelmente expandir a string) ao chamar programas externos.

Os tokens que se parecem com -foo.bar sofrem um destino semelhante (ver # 6291).

Isso já funciona conforme o esperado com a passagem de argumento _direct_ (por exemplo,
echoArgs -foo:bar passa -foo:bar como um único argumento
), mas não ao passar $Args / splatting ( @Args ).

Observação: o problema é fundamental para o uso de $Args / @Args e, embora talvez menos comum, também afeta seu uso ao chamar comandos nativos do PowerShell - consulte o comentário abaixo .

Passos para reproduzir

Execute no 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

Comportamento esperado

-foo:bar
---
-foo.bar

Comportamento real

-foo:
bar
---
-foo
.bar

Os argumentos são inesperadamente quebrados em dois. Veja o comentário vinculado para o plano de fundo.

Dados ambientais

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

Comentários muito úteis

Passei a última semana ou mais lutando com esse problema. Depois de rastreá-lo até valores de parâmetro de troca forçada (como -foo:$bar ) não definidos após salpicar com @Args , pensei que esse fosse um problema de escopo obscuro. Imagine minha surpresa quando descobri que forçar qualquer valor de parâmetro de switch dessa maneira não teria o comportamento esperado. Eu testei mesmo com a versão Powershell 7 Preview 1 e o mesmo problema ainda surge. Eu espero que isso seja corrigido depois de mais de um ano sendo um problema conhecido ...

Para referência, este é o teste que criei para mostrar o bug. Vi em uma máquina Server 2016 com Powershell 7 Preview 1, bem como em uma máquina Server 2012 R2 com 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>

Todos 3 comentários

Observação: os tokens em questão, como - foo: bar, parecem argumentos nomeados do PowerShell,

@ mklement0 Conforme descrevo nos comentários em # 6292, esses _são_ chamados de argumentos do PowerShell. Sempre. A vinculação de parâmetros é feita muito depois que a compilação é concluída. Agora, no AST compilado, o token para -foo: tem um sinalizador indicando que não havia espaço após ele no código-fonte. O NativeCommandParameterBinder olha para este elemento AST para ver se ele tem o sinalizador definido e, em seguida, concatena o parâmetro e o argumento sem espaço entre eles. Se não estiver definido, um espaço será inserido. Isso só funciona se os argumentos forem literais (ou seja, NativeCommandParameter foi o acesso ao AST para o argumento). No caso de splatting, os argumentos são valores, não argumentos literais, portanto, você obtém um espaço.

Uma maneira de corrigir isso é propagar a propriedade do token "NoSpace" em metadados no valor da string correspondente. O NativeCommandParameterBinder poderia então verificar esses metadados ao converter sua matriz arg em uma string. Provavelmente, vale a pena pensar um pouco mais sobre isso para ver se há outros casos (especialmente * nix casos específicos) que devem ser resolvidos.

6492 (já fechado como uma duplicata) mostra que o splatting @args também é interrompido ao chamar funções do PowerShell (não apenas programas externos):

Suportar esse cenário é presumivelmente ainda mais complicado, porque a expectativa aqui é que os parâmetros nomeados sejam passados ​​como estão, com seus tipos originais.

Aqui está uma reprodução simplificada:

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

A solução alternativa - e solução preferível para começar - é definir o mesmo bloco param() na função de retransmissão e splat com @PSBoundParameters .

Passei a última semana ou mais lutando com esse problema. Depois de rastreá-lo até valores de parâmetro de troca forçada (como -foo:$bar ) não definidos após salpicar com @Args , pensei que esse fosse um problema de escopo obscuro. Imagine minha surpresa quando descobri que forçar qualquer valor de parâmetro de switch dessa maneira não teria o comportamento esperado. Eu testei mesmo com a versão Powershell 7 Preview 1 e o mesmo problema ainda surge. Eu espero que isso seja corrigido depois de mais de um ano sendo um problema conhecido ...

Para referência, este é o teste que criei para mostrar o bug. Vi em uma máquina Server 2016 com Powershell 7 Preview 1, bem como em uma máquina Server 2012 R2 com 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>
Esta página foi útil?
0 / 5 - 0 avaliações