Como passar valores booleanos para um script PowerShell a partir de um prompt de comando

103

Eu tenho que invocar um script PowerShell de um arquivo em lote. Um dos argumentos do script é um valor booleano:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify $false

O comando falha com o seguinte erro:

Cannot process argument transformation on parameter 'Unify'. Cannot convert value "System.String" to type "System.Boolean", parameters of this type only accept booleans or numbers, use $true, $false, 1 or 0 instead.

At line:0 char:1
+  <<<< <br/>
+ CategoryInfo          : InvalidData: (:) [RunScript.ps1], ParentContainsErrorRecordException <br/>
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,RunScript.ps1

No momento, estou usando uma string para conversão booleana dentro do meu script. Mas como posso passar argumentos booleanos para PowerShell?

mutelogan
fonte

Respostas:

57

Parece que o powershell.exe não avalia totalmente os argumentos do script quando o -Fileparâmetro é usado. Em particular, o $falseargumento está sendo tratado como um valor de string, de maneira semelhante ao exemplo abaixo:

PS> function f( [bool]$b ) { $b }; f -b '$false'
f : Cannot process argument transformation on parameter 'b'. Cannot convert value 
"System.String" to type "System.Boolean", parameters of this type only accept 
booleans or numbers, use $true, $false, 1 or 0 instead.
At line:1 char:36
+ function f( [bool]$b ) { $b }; f -b <<<<  '$false'
    + CategoryInfo          : InvalidData: (:) [f], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,f

Em vez de usar, -Filevocê pode tentar -Command, o que avaliará a chamada como script:

CMD> powershell.exe -NoProfile -Command .\RunScript.ps1 -Turn 1 -Unify $false
Turn: 1
Unify: False

Como David sugere, usar um argumento switch também seria mais idiomático, simplificando a chamada ao remover a necessidade de passar um valor booleano explicitamente:

CMD> powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify
Turn: 1
Unify: True
Imperador XLII
fonte
6
Para aqueles (como eu) que precisam manter o parâmetro "-File" e não podem mudar para um argumento switch, mas têm controle sobre os valores de string que são enviados, então a solução mais simples é converter o parâmetro em um booleano usando [System.Convert] :: ToBoolean ($ Unify); os valores da string devem ser "True" ou "False".
Chris Haines,
187

Um uso mais claro pode ser usar parâmetros de switch. Então, apenas a existência do parâmetro Unify significaria que ele foi definido.

Igual a:

param (
  [int] $Turn,
  [switch] $Unify
)
David Mohundro
fonte
21
Esta deve ser a resposta aceita. Para aprofundar a discussão, você pode definir um valor padrão como qualquer outro parâmetro, como:[switch] $Unify = $false
Mario Tacke
Esqueci essa resposta, pois tinha certeza de que Boolean era o caminho a percorrer. Não é. O switch encapsula a funcionalidade do booleano e interrompe este tipo de erro: "Não é possível converter o valor" False "para o tipo" System.Management.Automation.ParameterAttribute ". Os switches funcionaram para mim.
TinyRacoon de
2
@MarioTacke Se você não especificar o parâmetro switch ao invocar o script, ele será automaticamente definido como $false. Portanto, não há necessidade de definir explicitamente um valor padrão.
DoubleDown
Essa sugestão funcionou muito bem; foi capaz de atualizar um dos parâmetros de [bool] para [switch] e isso me permitiu passar o argumento por meio do Agendador de tarefas.
JustaDaKaje
12

Esta é uma pergunta mais antiga, mas na verdade há uma resposta para ela na documentação do PowerShell. Eu tive o mesmo problema, e desta vez o RTFM realmente o resolveu. Quase.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe

A documentação para o parâmetro -File afirma que "Em casos raros, pode ser necessário fornecer um valor booleano para um parâmetro switch. Para fornecer um valor booleano para um parâmetro switch no valor do parâmetro File, coloque o nome do parâmetro e o valor em chaves, como as seguintes: -File. \ Get-Script.ps1 {-All: $ False} "

Eu tive que escrever assim:

PowerShell.Exe -File MyFile.ps1 {-SomeBoolParameter:False}

Portanto, sem '$' antes da declaração verdadeiro / falso, e funcionou para mim, no PowerShell 4.0

LarsWA
fonte
1
Obrigado por compartilhar! Resolveu meu problema perfeitamente.
Julia Schwarz
1
O link da resposta parece ter seu conteúdo alterado. No entanto, encontrei a resposta aqui
Slogmeister Extraordinaire
Link da documentação atual about_powershell.exe, alternativamente, apenas rung powershell -h.
Seth
Estou surpreso que essa estranha solução alternativa já funcionou - não funciona no Windows PowerShell v5.1 (nem com nem sem guia $); também observe que não é mais necessário no PowerShell Core . Pedi que a documentação seja corrigida; consulte github.com/MicrosoftDocs/PowerShell-Docs/issues/4964
mklement0
11

Tente definir o tipo de seu parâmetro para [bool]:

param
(
    [int]$Turn = 0
    [bool]$Unity = $false
)

switch ($Unity)
{
    $true { "That was true."; break }
    default { "Whatever it was, it wasn't true."; break }
}

Este exemplo padrões $Unitypara $falsese nenhuma entrada é fornecida.

Uso

.\RunScript.ps1 -Turn 1 -Unity $false
Filburt
fonte
1
A resposta do Imperador XLII e seu comentário sobre o -Fileparâmetro devem cobrir todos os aspectos da pergunta original. Vou deixar minha resposta porque alguém também pode achar útil minha dica sobre como fornecer um valor padrão.
Filburt de
Filburt bem fechado. Sua resposta me fez verificar meu script, que já tem o padrão especificado como o valor obrigatório $ false (eu escrevi isso há vários anos e tinha esquecido tudo sobre ele) - então nem preciso especificar o parâmetro booleano problemático no linha de comando agora. Excelente :)
Zeek2
5

Eu acho que a melhor maneira de usar / definir o valor booleano como parâmetro é usar em seu script PS assim:

Param(
    [Parameter(Mandatory=$false)][ValidateSet("true", "false")][string]$deployApp="false"   
)

$deployAppBool = $false
switch($deployPmCmParse.ToLower()) {
    "true" { $deployAppBool = $true }
    default { $deployAppBool = $false }
}

Então agora você pode usá-lo assim:

.\myApp.ps1 -deployAppBool True
.\myApp.ps1 -deployAppBool TRUE
.\myApp.ps1 -deployAppBool true
.\myApp.ps1 -deployAppBool "true"
.\myApp.ps1 -deployAppBool false
#and etc...

Portanto, em argumentos de cmd, você pode passar o valor booleano como string simples :).

Drasius
fonte
2

No PowerShell, os parâmetros booleanos podem ser declarados mencionando seu tipo antes de sua variável.

    function GetWeb() {
             param([bool] $includeTags)
    ........
    ........
    }

Você pode atribuir valor passando $ true | $ false

    GetWeb -includeTags $true
Ahmed Ali
fonte
Apenas passar os argumentos de entrada nomeados explicitamente assim funcionou muito bem. Obrigado Ahmed
Steve Taylor
0

Para resumir e complementar as respostas existentes , a partir do Windows PowerShell v5.1 / PowerShell Core 7.0.0-preview.4:

A resposta de David Mohundro aponta corretamente que, em vez de [bool]parâmetros, você deve usar [switch]parâmetros no PowerShell , onde a presença vs. ausência do nome do switch ( -Unifyespecificado vs. não especificado) implica seu valor , o que faz com que o problema original desapareça.


No entanto, às vezes você ainda pode precisar passar o valor de switch explicitamente , especialmente se você estiver construindo uma linha de comando programaticamente :


No PowerShell Core , o problema original (descrito na resposta do Imperador XLII ) foi corrigido .

Ou seja, para passar $trueexplicitamente para um [switch]parâmetro denominado, -Unifyagora você pode escrever:

pwsh -File .\RunScript.ps1 -Unify:$true  # !! ":" separates name and value, no space

Os seguintes valores podem ser usados: $false, false, $true, true, mas nota que passa 0ou 1faz não trabalho.

Observe como o nome do switch é separado do valor com :e não deve haver nenhum espaço em branco entre os dois.

Nota: Se você declarar um [bool]parâmetro em vez de [switch](o que geralmente não deve ser feito), deverá usar a mesma sintaxe; embora -Unify $false deva funcionar, atualmente não funciona - veja este problema do GitHub .


No Windows PowerShell , o problema original persiste e - visto que o Windows PowerShell não é mais desenvolvido ativamente - é improvável que seja corrigido.

  • A solução alternativa sugerida na resposta do LarsWA - embora seja baseada no tópico de ajuda oficial no momento da redação deste documento - não funciona na v5.1

    • Este problema do GitHub pede que a documentação seja corrigida e também fornece um comando de teste que mostra a ineficácia da solução alternativa.
  • Usar em -Commandvez de -Fileé a única solução alternativa eficaz :

:: # From cmd.exe
powershell -Command "& .\RunScript.ps1 -Unify:$true" 

Com -Commandvocê está efetivamente passando uma parte do código do PowerShell , que é então avaliado como de costume - e dentro do PowerShell passando $truee $falsefunciona (mas não true e false, como agora também é aceito com -File).

Advertências :

  • Usar -Commandpode resultar em uma interpretação adicional de seus argumentos, como se eles contivessem $chars. (com -File, os argumentos são literais ).

  • O uso -Commandpode resultar em um código de saída diferente .

Para detalhes, veja esta resposta e esta resposta .

mklement0
fonte
0

Tive algo semelhante ao passar um script para uma função com invoke-command. Executei o comando entre aspas simples em vez de aspas duplas, porque então ele se torna um literal de string.'Set-Mailbox $sourceUser -LitigationHoldEnabled $false -ElcProcessingDisabled $true';

Bbb
fonte
0

A execução de scripts do PowerShell no Linux a partir do bash apresenta o mesmo problema. Resolvido quase da mesma forma que a resposta de LarsWA:

Trabalhando:

pwsh -f ./test.ps1 -bool:true

Não está funcionando:

pwsh -f ./test.ps1 -bool=1
pwsh -f ./test.ps1 -bool=true
pwsh -f ./test.ps1 -bool true
pwsh -f ./test.ps1 {-bool=true}
pwsh -f ./test.ps1 -bool=$true
pwsh -f ./test.ps1 -bool=\$true
pwsh -f ./test.ps1 -bool 1
pwsh -f ./test.ps1 -bool:1
JanRK
fonte
-3

Você também pode usar 0para Falseou 1para True. Na verdade, sugere que na mensagem de erro:

Não é possível processar a transformação do argumento no parâmetro 'Unificar'. Não é possível converter o valor "System.String"com o tipo "System.Boolean", parâmetros deste tipo só aceitam booleans ou números, utilização $true, $false, 1 ou 0 em vez.

Para obter mais informações, consulte este artigo do MSDN sobre Boolean Values ​​and Operators .

Rahs
fonte
10
Isso não funciona. Ele está esperando o número inteiro 1 ou 0, mas transmiti-lo -Fileinterpreta como string, portanto, falha com o mesmo erro.
Erti-Chris Eelmaa
Esta resposta está errada, pois a sugestão não funciona
mjs