Comment passer des valeurs booléennes à un script PowerShell à partir d'une invite de commandes

104

Je dois appeler un script PowerShell à partir d'un fichier de commandes. L'un des arguments du script est une valeur booléenne:

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

La commande échoue avec l'erreur suivante:

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

À partir de maintenant, j'utilise une conversion de chaîne en booléen dans mon script. Mais comment puis-je transmettre des arguments booléens à PowerShell?

Mutelogan
la source

Réponses:

58

Il semble que powershell.exe n'évalue pas complètement les arguments de script lorsque le -Fileparamètre est utilisé. En particulier, l' $falseargument est traité comme une valeur de chaîne, d'une manière similaire à l'exemple ci-dessous:

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

Au lieu d'utiliser, -Filevous pouvez essayer -Command, qui évaluera l'appel en tant que script:

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

Comme David le suggère, l'utilisation d'un argument switch serait également plus idiomatique, simplifiant l'appel en supprimant la nécessité de passer une valeur booléenne explicitement:

CMD> powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify
Turn: 1
Unify: True
Empereur XLII
la source
6
Pour ceux (comme moi) qui doivent conserver le paramètre "-File" et qui ne peuvent pas passer à un argument de commutation, mais qui ont le contrôle sur les valeurs de chaîne envoyées, la solution la plus simple consiste à convertir le paramètre en un booléen utilisant [System.Convert] :: ToBoolean ($ Unify); les valeurs de chaîne doivent alors être "True" ou "False".
Chris Haines
187

Une utilisation plus claire pourrait être d'utiliser des paramètres de commutation à la place. Ensuite, juste l'existence du paramètre Unify signifierait qu'il a été défini.

Ainsi:

param (
  [int] $Turn,
  [switch] $Unify
)
David Mohundro
la source
21
Cela devrait être la réponse acceptée. Pour approfondir la discussion, vous pouvez définir une valeur par défaut comme tout autre paramètre comme ceci:[switch] $Unify = $false
Mario Tacke
J'ai négligé cette réponse, car j'étais sûr que Boolean était la voie à suivre. Ce n'est pas. Switch encapsule la fonctionnalité du booléen et arrête ce genre d'erreurs: "Impossible de convertir la valeur" False "en type" System.Management.Automation.ParameterAttribute ". Les commutateurs ont fonctionné pour moi.
TinyRacoon
2
@MarioTacke Si vous ne spécifiez pas le paramètre switch lors de l'appel du script, il est automatiquement défini sur $false. Il n'est donc pas nécessaire de définir explicitement une valeur par défaut.
doubleDown
Cette suggestion a très bien fonctionné; a pu mettre à jour l'un des paramètres de [bool] à [switch] et cela m'a permis de passer l'argument via le planificateur de tâches.
JustaDaKaje
12

C'est une question plus ancienne, mais il y a en fait une réponse à cela dans la documentation PowerShell. J'ai eu le même problème, et pour une fois RTFM l'a résolu. Presque.

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

La documentation du paramètre -File indique que «Dans de rares cas, vous devrez peut-être fournir une valeur booléenne pour un paramètre de commutateur. Pour fournir une valeur booléenne pour un paramètre de commutateur dans la valeur du paramètre File, insérez le nom et la valeur du paramètre dans accolades, telles que les suivantes: -File. \ Get-Script.ps1 {-All: $ False} "

J'ai dû l'écrire comme ceci:

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

Donc pas de '$' avant l'instruction true / false, et cela a fonctionné pour moi, sur PowerShell 4.0

LarsWA
la source
1
Merci pour le partage! J'ai parfaitement résolu mon problème.
Julia Schwarz
1
Le lien dans la réponse semble avoir changé de contenu. Cependant, j'ai trouvé la réponse ici
Slogmeister Extraordinaire
Lien vers la documentation actuelle about_powershell.exe alternativement juste sonné powershell -h.
Seth
Je suis surpris que cette solution de contournement maladroite ait jamais fonctionné - ce n'est pas le cas dans Windows PowerShell v5.1 (ni avec ni sans début $); notez également qu'il n'est plus nécessaire dans PowerShell Core . J'ai demandé que la documentation soit corrigée; voir github.com/MicrosoftDocs/PowerShell-Docs/issues/4964
mklement0
11

Essayez de définir le type de votre paramètre sur [bool]:

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

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

Cet exemple est défini $Unitypar défaut $falsesi aucune entrée n'est fournie.

Usage

.\RunScript.ps1 -Turn 1 -Unity $false
Filburt
la source
1
La réponse de l'empereur XLII et votre commentaire à ce sujet concernant le -Fileparamètre devraient couvrir tous les aspects de la question originale. Je vais laisser ma réponse car quelqu'un peut également trouver mon indice sur la fourniture d'une valeur par défaut utile.
Filburt
Bravo Filburt. Votre réponse m'a amené à vérifier mon script, qui a déjà spécifié par défaut comme valeur requise $ false (je l'ai écrit il y a plusieurs années et j'avais tout oublié) - donc je n'ai même pas à spécifier le paramètre booléen problématique sur le ligne de commande maintenant. Excellent :)
Zeek2
5

Je pense que la meilleure façon d'utiliser / définir une valeur booléenne comme paramètre est de l'utiliser dans votre script PS comme ceci:

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

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

Alors maintenant, vous pouvez l'utiliser comme ceci:

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

Ainsi, dans les arguments de cmd, vous pouvez passer une valeur booléenne sous forme de chaîne simple :).

Drasius
la source
2

Dans PowerShell, les paramètres booléens peuvent être déclarés en mentionnant leur type avant leur variable.

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

Vous pouvez attribuer une valeur en passant $ true | $ false

    GetWeb -includeTags $true
Ahmed Ali
la source
Le simple fait de passer les arguments d'entrée nommés explicitement comme cela a fonctionné un régal. Merci Ahmed
Steve Taylor
0

Pour résumer et compléter les réponses existantes , à partir de Windows PowerShell v5.1 / PowerShell Core 7.0.0-preview.4:

La réponse de David Mohundro indique à juste titre qu'au lieu de [bool]paramètres, vous devez utiliser des [switch]paramètres dans PowerShell , où la présence ou l'absence du nom du commutateur ( -Unifyspécifié ou non spécifié) implique sa valeur , ce qui fait disparaître le problème d'origine.


Cependant, à l'occasion, vous devrez peut-être toujours transmettre la valeur du commutateur explicitement , en particulier si vous construisez une ligne de commande par programme :


Dans PowerShell Core , le problème d'origine (décrit dans la réponse d'Empereur XLII ) a été corrigé .

Autrement dit, pour passer $trueexplicitement à un [switch]paramètre nommé, -Unifyvous pouvez maintenant écrire:

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

Les valeurs suivantes peuvent être utilisées: $false, false, $true, true, mais notez que le passage 0ou 1ne pas travailler.

Notez comment le nom du commutateur est séparé de la valeur avec :et il ne doit y avoir aucun espace entre les deux.

Remarque: Si vous déclarez un [bool]paramètre au lieu de a [switch](ce que vous ne devriez généralement pas), vous devez utiliser la même syntaxe; même si cela -Unify $false devrait fonctionner, cela ne fonctionne pas actuellement - voir ce problème GitHub .


Dans Windows PowerShell , le problème d'origine persiste et, étant donné que Windows PowerShell n'est plus activement développé, il est peu probable qu'il soit résolu.

  • La solution de contournement suggérée dans la réponse de LarsWA - même si elle est basée sur la rubrique d'aide officielle au moment de la rédaction de cet article - ne fonctionne pas dans la v5.1

    • Ce problème GitHub demande que la documentation soit corrigée et fournit également une commande de test qui montre l'inefficacité de la solution de contournement.
  • Utiliser -Commandau lieu de -Fileest la seule solution de contournement efficace :

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

Avec -Commandvous passez effectivement un morceau de code PowerShell , qui est ensuite évalué comme d'habitude - et à l'intérieur de PowerShell passant $trueet $falsefonctionne (mais pas true et false, comme maintenant également accepté avec -File).

Mises en garde :

  • L'utilisation -Commandpeut entraîner une interprétation supplémentaire de vos arguments, par exemple s'ils contiennent des $caractères. (avec -File, les arguments sont des littéraux ).

  • L'utilisation -Commandpeut entraîner un code de sortie différent .

Pour plus de détails, consultez cette réponse et cette réponse .

mklement0
la source
0

J'avais quelque chose de similaire lors du passage d'un script à une fonction avec invoke-command. J'ai exécuté la commande entre guillemets simples au lieu de guillemets doubles, car elle devient alors une chaîne littérale.'Set-Mailbox $sourceUser -LitigationHoldEnabled $false -ElcProcessingDisabled $true';

Bbb
la source
0

L'exécution de scripts PowerShell sur Linux à partir de bash pose le même problème. Résolu presque la même chose que la réponse de LarsWA:

Travail:

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

Ca ne fonctionne pas:

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
JanvierRK
la source
-3

Vous pouvez également utiliser 0pour Falseou 1pour True. Cela suggère en fait que dans le message d'erreur:

Impossible de traiter la transformation d'argument sur le paramètre «Unify». Impossible de convertir la valeur "System.String"type "System.Boolean", les paramètres de ce type n'acceptent que booléens ou des chiffres, l' utilisation $true, $false, 1 ou 0 au lieu.

Pour plus d'informations, consultez cet article MSDN sur les valeurs booléennes et les opérateurs .

Rahs
la source
10
Cela ne fonctionne pas. Il attend le nombre entier 1 ou 0, mais le passer à travers l' -Fileinterprète comme une chaîne, échoue donc avec la même erreur.
Erti-Chris Eelmaa
Cette réponse est fausse, car la suggestion ne fonctionne pas
mjs