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,**

for example `> 3.14 -and $true `

True

`> 0 -and $true `

False

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 `–bNot`

**Any non-empty string is true. Only empty strings are false**.

For example. `> "" -and $true `

False

`> "Hello, world" -and $true `

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 `> [boolean][string]$false `

True

If you need the text "true" to convert to True and "False" to convert to false you can use the [Convert] class `> [convert]::ToBoolean("false") `

False

**Any non-empty object is treated as true. An empty object , or array, or Null converts to false. **

`> (dir *.jpg) -and $true `

True

> (dir *.pjg) -and $true

False

> @() –and $true

False

**Any array with one element is treated as that element. **

`> @(0) -and $true `

False

**Any array with multiple elements is treated as true ****even if all those elements are false** `> @($false,$false) -and $true `

True

**Rule 2. Null is less than to anything except another null**

` `

```
```> "" -gt $null

True

` `

**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"

125

```
```

`> "25" * 5 `

2525252525

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 `

False

> $true -eq 3.14

True

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" `

True

> "false" -eq $true

False

**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 `

3

4

` `

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`