Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my boolean of value 0 returning true?

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.

.\[scriptname] [string1] [string2] [bool1] [bool2]

This works fine, and I've checked that they are all being passed correctly.

However, I've found something rather strange when PowerShell asks for parameters; it sets both booleans to true.

.\[scriptname] [string1] [string2]
please enter bool1: 0
please enter boo2: 0

It then runs the script as if bool1 and bool2 were set to true, and not to what I've set them to. I have true passing in all sorts of different things, and it always results in true.

I'm unsure as to why this is happening, and wanted to know if anyone has come across a cause or solution to this bizarre problem!

I've also found that the Task Scheduler has a similar issue. Set it up with

powershell -file [scriptlocation] [string1] [string2] [bool1] [bool2]

example:

powershell -file "C:\script1.ps1" "c:\fileOne.txt" "c:\folder1" 0 0

Both booleans come through as strings.

like image 592
Hazz22 Avatar asked Aug 29 '13 16:08

Hazz22


People also ask

Is 0 Boolean true?

Boolean Variables and Data Type ( or lack thereof in C )Zero is used to represent false, and One is used to represent true. For interpretation, Zero is interpreted as false and anything non-zero is interpreted as true.

Why is the Boolean value of 0 false?

If the Boolean value is true , the result is an int with a value of 1. If the scalar value is equal to 0, the Boolean value is 0; otherwise the Boolean value is 1. A zero, null pointer, or null member pointer value is converted to false . All other values are converted to true .

What makes a Boolean true?

Boolean. TRUE is a reference to an object of the class Boolean, while true is just a value of the primitive boolean type. Classes like Boolean are often called "wrapper classes", and are used when you need an object instead of a primitive type (for example, if you're storing it in a data structure).

Is a bool automatically true?

bool "bar" is by default true, but it should be false, it can not be initiliazied in the constructor. is there a way to init it as false without making it static?


1 Answers

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:

  • Set your variable as an [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
  • If you are using the bools as logic switches, consider the [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.
like image 87
Anthony Neace Avatar answered Nov 15 '22 09:11

Anthony Neace