How to pass boolean values to a PowerShell script from a command prompt
Asked Answered
S

11

138

I have to invoke a PowerShell script from a batch file. One of the arguments to the script is a boolean value:

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

The command fails with the following error:

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

As of now I am using a string to boolean conversion inside my script. But how can I pass boolean arguments to PowerShell?

Scudder answered 22/2, 2011 at 14:31 Comment(0)
S
77

It appears that powershell.exe does not fully evaluate script arguments when the -File parameter is used. In particular, the $false argument is being treated as a string value, in a similar way to the example below:

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

Instead of using -File you could try -Command, which will evaluate the call as script:

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

As David suggests, using a switch argument would also be more idiomatic, simplifying the call by removing the need to pass a boolean value explicitly:

CMD> powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify
Turn: 1
Unify: True
Silvia answered 4/9, 2011 at 22:53 Comment(2)
For those (like me) who have to keep the "-File" parameter, and can't change to a switch argument, but do have control over the string values that are sent, then the simplest solution is to convert the parameter to a boolean using [System.Convert]::ToBoolean($Unify); the string values must then be "True" or "False".Napolitano
In order for [System.Convert]::ToBoolean($Unify) to evaluate to true, $Unify must -eq "true" or "True". Otherwise, [System.Convert]::ToBoolean($Unify) evaluates to false.Belva
M
248

A more clear usage might be to use switch parameters instead. Then, just the existence of the Unify parameter would mean it was set.

Like so:

param (
  [int] $Turn,
  [switch] $Unify
)
Mummer answered 22/2, 2011 at 14:45 Comment(5)
This should be the accepted answer. To further the discussion, you can set a default value like any other parameter like so: [switch] $Unify = $falseAllene
I overlooked this answer, as I was sure Boolean was the way to go. It is not. Switch encapsulates the functionality of the boolean, and stops these kind of errors: " Cannot convert value "False" to type "System.Management.Automation.ParameterAttribute". Switches worked for me.Neral
@MarioTacke If you don't specify the switch parameter when invoking the script then it is automatically set to $false. So there's no need to explicitly set a default value.Persian
This suggestion worked very well; was able to update one of the params from [bool] to [switch] and this successfully allowed me to pass the argument via Task Scheduler.Parch
If you are using the [Parameter] attribute on any of the parameters, you have to make sure that you pass the switch parameters as switches and not as booleans. So e.g. -Unify for true and nothing for false. Otherwise -Unify $false or -Unify $true would raise error "A positional parameter cannot be found that accepts argument '$true'"Expostulation
S
77

It appears that powershell.exe does not fully evaluate script arguments when the -File parameter is used. In particular, the $false argument is being treated as a string value, in a similar way to the example below:

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

Instead of using -File you could try -Command, which will evaluate the call as script:

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

As David suggests, using a switch argument would also be more idiomatic, simplifying the call by removing the need to pass a boolean value explicitly:

CMD> powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify
Turn: 1
Unify: True
Silvia answered 4/9, 2011 at 22:53 Comment(2)
For those (like me) who have to keep the "-File" parameter, and can't change to a switch argument, but do have control over the string values that are sent, then the simplest solution is to convert the parameter to a boolean using [System.Convert]::ToBoolean($Unify); the string values must then be "True" or "False".Napolitano
In order for [System.Convert]::ToBoolean($Unify) to evaluate to true, $Unify must -eq "true" or "True". Otherwise, [System.Convert]::ToBoolean($Unify) evaluates to false.Belva
E
20

This is an older question, but there is actually an answer to this in the PowerShell documentation. I had the same problem, and for once RTFM actually solved it. Almost.

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

Documentation for the -File parameter states that "In rare cases, you might need to provide a Boolean value for a switch parameter. To provide a Boolean value for a switch parameter in the value of the File parameter, enclose the parameter name and value in curly braces, such as the following: -File .\Get-Script.ps1 {-All:$False}"

I had to write it like this:

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

So no '$' before the true/false statement, and that worked for me, on PowerShell 4.0

Eighteenmo answered 26/7, 2016 at 10:25 Comment(4)
Thank you for sharing! Solved my problem perfectly.Michelsen
The link in the answer seems to have had its content changed. However, I found the answer hereAbortionist
Current documentation link about_powershell.exe alternatively just rung powershell -h.Maurey
I'm surprised that this awkward workaround ever worked - it doesn't in Windows PowerShell v5.1 (neither with nor without a leading $); also note that it is no longer necessary in PowerShell Core. I've asked for the documentation to be corrected; see github.com/MicrosoftDocs/PowerShell-Docs/issues/4964Quint
E
19

Try setting the type of your parameter to [bool]:

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

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

This example defaults $Unity to $false if no input is provided.

Usage

.\RunScript.ps1 -Turn 1 -Unity $false
Educt answered 22/2, 2011 at 16:48 Comment(2)
Emperor XLII's answer and your comment on it regarding the -File parameter should cover every aspect of the original question. I'll leave my answer because someone may also find my hint on providing a default value useful.Educt
Well done Filburt. Your answer caused me to check my script, which already has default specified as the required value $false (I wrote that several years ago and had forgotten all about it) - so I don't even have to specify the problematic boolean parameter on the command line now. Excellent :)Alinaaline
K
7

I think, best way to use/set boolean value as parameter is to use in your PS script it like this:

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

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

So now you can use it like this:

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

So in arguments from cmd you can pass boolean value as simple string :).

Keitt answered 23/12, 2016 at 8:16 Comment(0)
D
6

Running powershell scripts on linux from bash gives the same problem. Solved it almost the same as LarsWA's answer:

Working:

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

Not working:

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
Discussion answered 27/11, 2019 at 16:30 Comment(2)
same situation here. This is dumb.Harshman
oh no it was just one : i misseddRichmond
Q
5

To summarize and complement the existing answers, as of Windows PowerShell v5.1 (the latest and last version) / PowerShell (Core) 7.3.3:

David Mohundro's answer rightfully points that instead of [bool] parameters you should use [switch] parameters in PowerShell, where the presence vs. absence of the switch name (-Unify specified vs. not specified) implies its value, which makes the original problem go away.


However, on occasion you may still need to pass the switch value explicitly, particularly if you're constructing a command line programmatically:


In PowerShell Core 7+, the original problem (described in Emperor XLII's answer) has been fixed.

That is, to pass $true explicitly to a [switch] parameter named -Unify you can now write:

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

The following values can be used: $false, false, $true, true, but note that passing 0 or 1 does not work.

Note how the switch name is separated from the value with : and there must be no whitespace between the two.

Note: If you declare a [bool] parameter instead of a [switch] (which you generally shouldn't), you must use the same syntax. Even though -Unify $false should work, it currently doesn't - see GitHub issue #10838.


In Windows PowerShell, the original problem persists, and - given that Windows PowerShell is no longer actively developed - is unlikely to get fixed.

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

With -Command you're effectively passing a piece of PowerShell code, which is then evaluated as usual - and inside PowerShell passing $true and $false works (but not true and false, as now also accepted with -File).

Caveats:

  • Using -Command can result in additional interpretation of your arguments, such as if they contain $ chars. (with -File, arguments are literals).

  • Using -Command can result in a different exit code.

For details, see this answer and this answer.

Quint answered 19/10, 2019 at 14:53 Comment(2)
The most complete answer. This one should be marked as an answer hereLyudmila
I appreciate the sentiment, @Kamarey. It's unlikely that the OP will come back and change what answer is the accepted one, but up-voting this one (which I assume you have done, thank you) will help it become more visible.Quint
L
3

In PowerShell, boolean parameters can be declared by mentioning their type before their variable.

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

You can assign value by passing $true | $false

    GetWeb -includeTags $true
Laundromat answered 25/10, 2019 at 5:18 Comment(2)
Just passing the named input arguments explicitly like that worked a treat. Thanks AhmedWetzell
The question is about calling the PowerShell CLI (powershell.exe) from cmd.exe, invoking a script that already has as [bool] parameter defined. You're answering an unrelated question.Quint
I
0

I had something similar when passing a script to a function with invoke-command. I ran the command in single quotes instead of double quotes, because it then becomes a string literal. 'Set-Mailbox $sourceUser -LitigationHoldEnabled $false -ElcProcessingDisabled $true';

Illa answered 29/10, 2019 at 21:18 Comment(0)
T
-1

Based on my test, a default value specification does not work for a parameter that is expected to be a boolean in the Function.

You can use the [switch] type or if you really want to use boolean, you should specify default value at the start of the function like below:

Function nullRules {
    Param
    (
         [Parameter(Mandatory=$false)] $boolWins

    )
   if ([DBNull]::Value.Equals($boolWins)) {$boolWins=$false}
   ....
   ....
}
Tache answered 21/9, 2022 at 18:16 Comment(1)
Based on mt testing, ([DBNull]::Value.Equals($boolWins)) returns $false whether a value is passed to $boolWins or not. Therefore, the call to set $boolWins to $false if $boolWins is $null is superfluous. If $boolWins is omitted then a default boolean value of $false is automatically assigned.Rosenda
B
-4

You can also use 0 for False or 1 for True. It actually suggests that in the error message:

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.

For more info, check out this MSDN article on Boolean Values and Operators.

Blaubok answered 21/7, 2014 at 21:50 Comment(2)
That does not work. It is expecting integer number 1 or 0, but passing it through -File interprets it as string, thus fails with same error.Isola
This answer is wrong, as the suggestion doesn't workHughie

© 2022 - 2024 — McMap. All rights reserved.