I was in a conversation on twitter recently about the way operations in PowerShell aren’t always commutative. We expect addition, multiplication and equality operators to work the same way whether we write 2 x 3 or 3 x 2.
But what happens in a language like PowerShell which tries to flatten out the differences between types and let you multiply a text string by a number? Let’s explain
Rule 1. If the operator dictates types, then PowerShell will convert the operands to match.
The classic case is for the –and and –or operators: PowerShell will covert the operands to Booleans – knowing how the conversion is done opens up some useful shortcuts and also avoids some traps:
Any non-zero number is treated as true. Only Zero is false,
> 3.14 -and $true
> 0 -and $true
In some programming languages
8 –or 16 would calculate a "bitwise OR" (also called a binary OR), in other words it would convert 8 to binary 0000 1000 and convert 16 to binary 0001 0000 and do OR operations on each column to produce 0001 1000 – 24 in decimal. PowerShell provides this functionality though separate operators
‑bOr, ‑bAnd –bXor and
Any non-empty string is true. Only empty strings are false.
> "" -and $true
> "Hello, world" -and $true
The string "FALSE" is not empty, and so is treated as the Boolean value True. If you convert $False to a string and back to a boolean it doesn’t come back to false
If you need the text "true" to convert to True and "False" to convert to false you can use the [Convert] class
Any non-empty object is treated as true. An empty object , or array, or Null converts to false.
> (dir *.jpg) -and $true
> (dir *.pjg) -and $true
> @() –and $true
Any array with one element is treated as that element.
> @(0) -and $true
Any array with multiple elements is treated as true even if all those elements are false
> @($false,$false) -and $true
Rule 2. Null is less than to anything except another null
> "" -gt $null
Rule 3. If the operator does not dictate types and the arguments are different types, the first operand’s type determines behaviour
This causes bewilderment in people who don’t understand it, because an operator which is normally commutative (works the same with the operands reversed) is only commutative if the operands are of the same type.
> 5 * "25"
> "25" * 5
The string “25” is converted to a number, 5×25 = 125, but if the string is placed first, the multiplication operator repeats it.
> 3.14 -eq $true
> $true -eq 3.14
Converting $true to a number returns 1. Converting a (non-zero) number to a Boolean returns true.
Similarly converting any non empty string to a Boolean returns true, but converting false to a string returns “false”
$true -eq "false"
> "false" -eq $true
Rule 4. When applied to an array , an operator which returns a Boolean when applied to single items, will return an array of items which individually return true
> @(1,2,3,4) –gt 2
When you put this together with tests for null, confusion can result: see if you can work out what the following returns.
> @($null,1,2,””,$null) –eq $null
And why the following return the opposite results
> [boolean](@($null,1,2,””,$null) –eq $null)
> [boolean](@($null,1,2,”” ) –eq $null)
Hint : if you can’t work it out try
(@($null,1,2,””,$null) –eq $null).Count