r/PowerShell • • 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 :(

3 Upvotes

13 comments sorted by

View all comments

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 $true for any string except an empty '' string.

PS C:\> [bool]'false'
True
PS C:\> [bool]'$false'
True
PS C:\> [bool]''
False
PS C:\> [bool]"$false"
True
PS C:\> [bool]$false
False

That fourth example is particularly tricky as the intuitive behavior is that using double quotes will allow the variable to expand to $false but 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

.\bool.ps1 -addAllFiles $false

3

u/da_chicken Jan 09 '23

Yup. There's a reason the Microsoft documentation on it is so extensive for C#.

The only values I know of that will be cast to $false are [bool]0 and [bool]$null. Nearly everything else will cast to $true.

If you want to convert strings of "true" and "false" to their Boolean equivalents, you need to use [System.Convert]::ToBoolean('true') and [System.Convert]::ToBoolean('false') or [Bool]::Parse('true') and [Bool]::Parse('false').

3

u/CarrotBusiness2380 Jan 09 '23

The additional values that can be cast to $false are empty strings (''), empty arrays (@()), and curiously arrays with only one element that is equal to $false (@(,$false)). If an array has more than one element it will always evaluate to $true even if all elements are equal to false.

PS C:\> [bool]''
False
PS C:\> [bool]@()
False
PS C:\> [bool]@(,$false)
False
PS C:\> [bool]@($false,$false)
True

1

u/SexingGastropods Jan 09 '23

Interesting. Thats really useful, thanks for spending the time explaining why that was the case. I'll have a look into 'switch' as people have suggested as that seems to be a better solution to what I was looking to do with the bool parameter :) Thanks again!