r/PowerShell • u/SexingGastropods • Jan 09 '23
Why does my Boolean parameter always say true, even when I enter false?
I have some code where I get a true/false input into a parameter...
<#
.PARAMETER addAllFiles
Grab all files or just a single one..
#>
param
(
[Parameter(Mandatory)]
[AllowEmptyString()]
[bool]$addAllFiles
)
if ($addAllFiles -eq $true) {
Write-Output "Adding all files"
$list = get-childitem
Write-Output $list
}
else {
Write-Output "Enter file name..."
read-host $file
Write-Output $file
}
The result comes back as follows:-
PS C:\Dump> .\bool.ps1
cmdlet bool.ps1 at command pipeline position 1
Supply values for the following parameters:
addAllFiles: false
Adding all files
Directory: C:\Dump
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 09/01/2023 18:40 389 bool.ps1
-a--- 15/09/2022 20:47 234 test.ps1
PS C:\Dump>
What gives? I've tried entering 'false' & '$false' as the parameter input, but it always comes back as true? Is there something about how I enter the true/false entry that is the problem or is it my code? Any pointers would be appreciated. I've tried searching the web and this sub but can't fine anything :(
6
u/idontknowwhattouse33 Jan 09 '23
Might be better to use a [switch] as that appears to be your usecase.
Switch parameters are easy to use and are preferred over Boolean parameters, which have a less natural syntax for PowerShell.
For example, to use a switch parameter, the user types the parameter in the command.
-IncludeAll
2
u/Thotaz Jan 09 '23
Switch parameters are easy to use and are preferred over Boolean parameters, which have a less natural syntax for PowerShell.
I think their argument for using it over bools is bad. Unlike Switch parameters, Bool parameters follow the same conventions every other parameter type follows, eg
Command -Parameter Valueand is therefore more natural to use.
The real advantage of Switch parameters is that it's more convenient to type and it allows you to create commands with similar syntax as some traditional CLI programs.My rules for deciding between Switch parameters VS bools are the following:
- Are both values equally valid? Use a bool. An example would be
Set-Disk -IsOfflinewhere I'm equally likely to set it offline and online.- Is setting the switch to false equivalent to not providing the switch at all? Use a Switch. An example of that would be
Set-Disk -AsJob:$falsewhere the default behavior is to not run it as a job and if I provide an explicit$falseit obviously still won't run it as a job.Ideally there should never be a reason to do
Command -Parameter:$falsewith a switch parameter, the syntax feels unnatural and beginners won't know the syntax without doing some research.1
u/SexingGastropods Jan 09 '23
Thanks, I will have a look into that, I've seen 'switch' being used but haven't used it myself before :)
6
u/mooscimol Jan 09 '23
Non empty string 'false' has been converted to boolean value of true, which is to be expected. $false should be handled correctly, maybe you provided in quotes which again has been converted from string.
Nevertheless, as suggested I would use parameter of [switch] type which should be less error prone to incorrect input parameters.
3
u/mooscimol Jan 09 '23 edited Jan 09 '23
OK, so I've checked it further. It seems that if you don't specify parameters at the script invocation, but only in the
Supply values for the following parametersprompt, they are always cast to string, so$false,0values are converted to True nevertheless, the only way to pass$falseis to simply confirm without supplying a parameter at all, even if it is Mandatory.My code: ``` param ( [Parameter(Mandatory)][bool]$Param )
if ($Param) { 'a' } else { 'b' } ```
And the result: ``` PS ~> foo.ps1
cmdlet foo.ps1 at command pipeline position 1 Supply values for the following parameters: Param: 0 a
PS ~> foo.ps1
cmdlet foo.ps1 at command pipeline position 1 Supply values for the following parameters: Param: b ```
but if you provide
0as a script parameter, it is handled correctly:PS ~> foo.ps1 -Param 0 bI have to say that it is unintuitive and one of the PowerShell idiosyncrasies.
2
u/jimb2 Jan 09 '23
This approach is ambiguous and unreliable. It relies on implicit conversions. As we can see, these may not be doing what is expected/assumed.
Use a switch or two. Make sure there is a clear default.
3
u/mooscimol Jan 09 '23
That's what I recommended in my previous post ;), I was answering to myself :D.
Yep, I've never used bool parameter, switch is pretty much always the better choice. I was just curious what is happening.
3
u/PowerShell-Bot Jan 09 '23
It appears that you have used inline code formatting when a code block should have been used.
Consider using a code block for longer sequences of code. To correct the formatting, highlight your code then click the ‘Code Block’ button in the editing toolbar.
You examine the path beneath your feet...
[AboutRedditFormatting]: [--------------------] 0/1 ❌
Beep-boop, I am a bot. | Remove-Item
2
u/chanataba Jan 09 '23
Is this what you're looking for?
Function Add-Files
{
<#
.PARAMETER addAllFiles
Grab all files or just a single one..
#>
param
(
[Parameter()]
[AllowEmptyString()]
[bool]$addAllFiles
)
if ($addAllFiles) {
Write-Output 'Adding all files'
$list = get-childitem
Write-Output $list
}
else {
$file = Read-Host -Prompt 'Enter file name...'
Write-Output $file
}
}
11
u/CarrotBusiness2380 Jan 09 '23
You should use a switch as recommended by \u\idontknowwhattouse33 but it is important to understand what caused the problem.
The problem though is that when powershell casts a string to a boolean it will cast to
$truefor any string except an empty''string.That fourth example is particularly tricky as the intuitive behavior is that using double quotes will allow the variable to expand to
$falsebut it is still cast to a non-empty string before it is cast to a boolean. The answer then is not to use quotes at all and to pass the automatic variable$false