Scripting Games 2012 Notes: Wait A Second, $True –eq “False”?!?

imageYes, what you are reading is correct,$True does in fact equal “False” in PowerShell. While this exact line was not used recently in the Scripting Games this year, people competing and submitting scripts did do something similar that gave a “false idea” that it was producing the correct data.

The event itself asked to find all running and stoppable services on a local or remote system. The solution was basically something like this:

Get-Service | Where {$_.CanStop}

Never mind that I am not using aliases or anything per the design guidelines as I am not worried about that here.

For the sake of a few examples, I am going to add a little more to this one-liner to get a more desirable output.

Get-Service | Where {$_.CanStop} | Select Name,CanStop

image

 

What I was instead seeing being submitted was something like this:

Get-Service | Where {$_.CanStop -eq "True"}

The reason for this is because it is already a boolean value and does not need to be evaluated to $True via a comparison. If you wanted to show all non-stoppable services, you would use the –Not (!) before $_.CanStop which would return all $False valued properties.

Again, lets add a little more to get a better output:

Get-Service | Where {$_.CanStop -eq "True"} | Select Name,CanStop

image

Hmmm…. Well, if you run this, it does in fact return the correct information, but let me say that it is a false sense of being correct. I will now show you why this is not the best way to perform a comparison against a property that has a boolean value.

Get-Service | Where {$_.CanStop -eq "False"} | Select Name,CanStop

image

Wait a second! We were looking for anything that was False, so why didn’t this work? Well, the short of it is that no matter what non-empty string value you use, it will always come back as $True when you compare it to $True.

$True -eq "True"
$True -eq "False"
$True -eq "Fish"

image

Pretty wild, isn’t it? Same goes for $False as well. If it is a non-empty string, it will always return $False.

$False -eq "False"
$False -eq "True"
$False -eq "Fish"

image

 

And to finish this little piece up, while non-empty strings are always $True, empty strings will always be $False:

$True -eq ""
$False -eq ""

image

Believe it or not, this is by design. In fact, there was a PowerShell Connect item submitted regarding this that was closed being “By Design”.

In designing the PowerShell language we based the semantics of the language on *successful* prior art wherever possible. PowerShell’s boolean behaviour is based on well-established existing behaviour in scripting languages including JavaScript, Perl, Python, PHP, AWK, the various UNIX shells, etc. All of these languages treat a non-empty string as true and an empty string as false. (Ruby and LUA are a bit different – all strings are true, even empty ones. This behaviour is inherited from LISP. In LISP nil is false, non-nil is true so all strings are true.)
Regarding loss of precision, using a value in a boolean context is considered an explicit conversion where loss of precision is permitted.
Having shipped Version 1 of PowerShell, changing the boolean behaviour would be a massive (and therefore unacceptable) breaking change.
All of that said, the semantics of V1 PowerShell are very oriented towards small programs. We are looking at adding a “super-strict” mode for writing larger programs where many of the implicit conversions may be suppressed and/or generate errors. Enforcing explicit boolean conversions might be something we could add. We will not add support for treating “true” as true and “false” as false as it’s not portable to a non-english locale.
-bruce

The Bruce answering this being the one and only Bruce Payette.

While this references V1, it continues to hold $True through V2 and the upcoming V3 Beta.

Keep this in mind when you are writing code so you do not have unintended consequences when your code is run or reported potentially inaccurate data.

This entry was posted in powershell, Scripting Games 2012 and tagged , , . Bookmark the permalink.

2 Responses to Scripting Games 2012 Notes: Wait A Second, $True –eq “False”?!?

  1. paulchavez says:

    I know this is old but @dfinke just bumped it so… I wanted to pass on how to use strings that say ‘true’ or ‘false’ in boolean operations, as this was something I ran into recently when integrating with Team City build parameters.

    consider the variable $do_something = ‘false’
    the following statement if ($do_something) {“Do it!”} else {“Don’t do it!”}; will return ‘Do it!’ as explained in this article. I THOUGHT if ([boolean]$do_something)… would work, but that is the same thing as evaluating the string directly.

    The solutions is to do if ([boolean]::Parse($do_something))… which will convert the string to a proper boolean.

Leave a reply to Boe Prox Cancel reply