I\'ve been working on some PowerShell scripts and found something a little odd. I have a script that accepts 4 mandatory parameters: two strings and two Booleans.
This blog by Jeffrey Snover offers some insight on the behavior of booleans in Powershell. Below is an excerpt, where he creates a simple function "test" to return true or false depending on the input parameter:
PS> test "0"
TRUE
PS> test 0
FALSE
PS> test 1
TRUE
PS> test 0.0
FALSE
PS> test 0x0
FALSE
PS> test 0mb
FALSE
PS> test 0kb
FALSE
PS> test 0D
FALSE
PS> test 0.00000001
TRUE
“0” is TRUE because it is a STRING and it has a length of 1. 0 is FALSE because it is a number and that number is 0. In PowerShell, any number which evaluates to 0 is FALSE and every non-zero number is TRUE. The example shows you a floating point zero, a hexadecimal zero, 0 megs, 0 kilos, 0 decimal, there are all sorts of zeros but to PowerShell, they all evaluate to FALSE.
Without any sample code it is hard to say exactly what is happening, but what we can say is that your input isn't being identified as zero by Powershell. Perhaps it is a string? This would be true if you used Read-Host
to get user input. Here's an example:
PS C:\> $test = Read-Host "Input"
Input: 0
PS C:\> $test.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
PS C:\> test $test
TRUE
PS C:\> $test = [Int32]$test
PS C:\> test $test
FALSE
You can check by using GetType()
on the variable in question, and fixing it may be a simple matter of explicitly casting to the desired type.
The more I read your question -- unless I've misunderstood it -- this seems to address your problems. Especially where you comment that you've been "passing in all sorts of different things" as any non-zero length string would evaluate to true in this context.
PS C:\> $anotherTest = "42"
PS C:\> test $anotherTest
TRUE
PS C:\> $anotherTest = [Int32]$anotherTest
PS C:\> test $anotherTest
TRUE
Edit: Alright, I've worked a bit more on the problem now that I have some idea what your environment is. First, everything I told you above is true, so please don't disregard it. The problem you're experiencing is that the boolean type conversion is handling the powershell mandatory prompt input in a way that isn't immediately obvious.
So some situation exists where this code snippet:
param
(
[Parameter(mandatory=$true)][bool]$myBool
)
Write-Host $myBool
Will cause the following result when you use powershell's mandatory parameter prompt instead of submitting the variable on the command line:
PS C:\> .\script.ps1
cmdlet script.ps1 at command pipeline position 1
Supply values for the following parameters:
myBool: 0
True
Let me re-iterate: In Powershell, all strings that are not of a null length evaluate to true. This includes "0", and this includes string literals. But what's the problem? We've already explicitly declared our variable as a bool
, so it should understand that I mean 0, right?
Wrong. A rather unfortunate situation is created where we're expecting a bool, or at least a string, when we set our input to the prompt. We do indeed eventually get out bool, but remember what happens to non-null strings when we convert them to bools? The type conversion to bool is being applied to the literal input you set at the prompt, which is not a numeric type. Since the input is of a non-null length, the bool conversion evaluates to true. You are essentially performing this operation:
PS C:\> [bool]$myBool = [bool]"0"
PS C:\> $myBool
True
The big problem with this is that since we've already converted our variable to a bool, the string has been consumed and we're just left with the value 1, or True. So your "0" literally turned into 1. We can't get the 0 back anymore. What should we do? I'll list a couple of options:
[int]
type instead of a [bool]
. The bool conversion consumed the "0" string and turned it into a 1, so why not use a type that won't do that? Powershell understands numerical 0s and 1s to be true and false, so you can use any numerical type.Example with output:
param
(
[Parameter(mandatory=$true)][int]$myBool
)
Write-Host $myBool
PS C:\> .\script1.ps1
cmdlet script1.ps1 at command pipeline position 1
Supply values for the following parameters:
myBool: 0
0
[switch]
parameter type instead. Switches always evaluate to false unless you explicitly set them. You shouldn't ever expose the prompt this way, so you won't encounter this problem. More info here.