Even if you only script every now and then, PowerShell logical operators will sooner or later cross your path. If you think that you already mastered this topic, I have some examples for you that might be a bit puzzling if you expect PowerShell to follow the rules of basic mathematical logic.

Michael Pietroforte

Michael Pietroforte is the founder and editor of 4sysops. He is a Microsoft Most Valuable Professional (MVP) with more than 30 years of experience in IT management and system administration.

Spock

The little riddle ^

If you don’t understand right away what is happening in the following example, I recommend reading the rest of the article.

Note that you’ll only get this result if no error occurred in your current PowerShell session. The statement above appears to evaluate whether the automatic variable $Error, which contains the error messages of previous commands, is empty or not.

In formal logic, this could be expressed as A ∨ ¬ A, which means, in English, A or not A (like in a=b or a≠b) This is always true in classical logic. Obviously, PowerShell follows a different logic here. The following statement gives you a little clue how PowerShell arrived at this seemingly illogical conclusion:

The German philosopher Martin Heidegger once had a hard time in coming to the conclusion that nothingness negates itself. With PowerShell you can calculate the answer to this age-old philosophical question in a blink of an eye. So you see, you can even automate philosophical thinking with PowerShell. 😉

You say that's all very interesting but you still don't understand why the first statement results in False? Then it's save to say that you didn't master PowerShell’s logical operators yet and you have to read the rest of this post.

The logical operators ^

You usually need logical operators in conditional statements or loops where you have to evaluate a certain condition. The evaluation of an expression that contains logical operators usually results in the Boolean values True or False . Unlike in some other programming languages, you can’t reference these values directly and you need the automatic variables $True and $False to assign the values of True and False to a variable. Thus, $a = True produces an error message in PowerShell, but $a = $True works just fine.

Since we now know the truth about True and False, we can have a closer look on how to process truth values with logical operators. The table below lists all logical operators that PowerShell understands.

Logical Operator ExampleNameDescription
$a -and $bLogical andTrue if $a and $b are True,
otherwise False
$a -or $bLogical orFalse if $a and $b are False,
otherwise True
$a -xor $bLogical exclusive orTrue if either $a or $b is True,
otherwise False
-not($a) (alternatively !($a))Logical notTrue if $a is False,
otherwise False

Other programming languages support more logical operators, but the truth is that, in two-valued logic (Boolean logic), you can say anything that can be said with just two operators. For instance, “$a -and $b” can be expressed as “!(!$a -or !$b).”

PowerShell will always evaluate the expression above as True, regardless of the values of $a and $b. However, you should use logical operators in a way that is easy for humans to understand. This doesn’t necessarily mean that you have to minimize the number of logical operators.

Short circuiting ^

As the example above also demonstrates, in mathematical logic, truth values can often be determined without evaluating all components of an expression. You can use this fact to improve your code’s performance. For instance, in an -or statement, the first operand should be the one with the easy-to-determine Boolean value because, if it is evaluated as True, PowerShell won’t test the second operand.

With the -and operator, it works just the other way around. Say you have to test whether certain conditions have to be met on the local and a remote computer. You should test the local computer first because, if the condition doesn’t apply to that computer, PowerShell doesn’t even have to connect to the remote computer. This feature of PowerShell is called short circuiting.

In the following example, PowerShell will test if the file exists on the local computer and will only copy it to the remote computer if it doesn’t already exist at the remote location.

It makes sense here to first test the local computer because, if the file doesn’t exist, PowerShell doesn’t have to establish a connection to the remote computer to determine if the file exists there.

Operator overloading ^

I think it is about time to solve our little riddles from the beginning. The first thing we need to understand is why “!($Null)” evaluates as True. PowerShell is quite generous with the things you feed into its logical operators. This generosity is called operator overloading. PowerShell can evaluate the truth value not only of items of the Boolean data type.

The -Not operator in the example evaluated the string as False, not because PowerShell intends to give the lie to Gödel, but because we gave the -Not operator something to chew on. In contrast, if we feed an empty string to the -Not operator, it will evaluate as True. This means if you apply the -Not operator to a non-Boolean variable, it will determine if the variable is empty or not.

However, exceptions to this rule exist:

PowerShell treats the numbers 0 and 1 like False and True. The other logical operators can process non-Boolean values as well:

This one is my favorite:

Isn’t it amazing? PowerShell even knows about Hamlet. You noticed it. We are inching closer to our first riddle. Because the left-hand side (LHS) and the right-hand side (RHS) are both expressions that are not empty, PowerShell comes to the conclusion that the whole statement must be True.

The riddle's solution ^

We need one more little piece of information to understand why “($Error -eq $Null) -or ($Error -ne $Null)” evaluates as False. Try this one:

It seems PowerShell follows the common rules of Boolean logic here. Thus, our riddle must be connected to the $Error variable. This variable stores previous error messages in an array (in an ArrayList, to be precise, which, in contrast to an array, supports the dynamic addition of new elements). If you use the -eq operator with an array (or an ArrayList, for that matter), PowerShell won’t return a Boolean value. Instead, it will return the operand:

If you use the -ne operator instead, you will receive the members that don’t match your term:

And if the array doesn’t contain the tested element at all, PowerShell returns nothing:

Thus, if no error occurred in your current session, “$Error -ne $Null” and “$Error -ne $Null” will both return nothing (and not Boolean values).

Therefore, in this case, “($Error -eq $Null) -or ($Error -ne $Null)” can be translated into:

As explained above, if you feed an empty variable into a logical operator, it treats the value as False. Now, you probably wonder how you can test whether the $Error variable is empty or not. This is how:

Or, if you want to know whether no error occurred so far, use this:

For the sake of completeness, the proper way to express “($Error -eq $Null) -or ($Error -ne $Null)” in PowerShell is this:

Not that this statement has any useful application in your scripts, but at least we now know that PowerShell has some basic understanding of Murphy’s law. 😉

Win the monthly 4sysops member prize for IT pros

Share
0

Related Posts

6 Comments
  1. M Mashwani 3 years ago

    Variable expansion only happens with the operator on the left. Therefore, you can also do this as an alternative to avoid variable expansion on an array:
    “($Null -eq $Error) -or ($Null -ne $Error)” => True

    As a general rule, if I want to check if something is $Null or not, I always put $Null as the first condition so I never run into problems with the way PowerShell handles arrays in such scenarios.

    0

  2. Michael Pietroforte 3 years ago

    You are right, in this case operator overloading only occurs if the array is on the left-hand side. If you want to check if a variable is empty, you don't really need the $Null variable. As demonstrated in the post, you can test it directly:

    If ($myVariable) {"This variable is not empty"}

    0

  3. M Mashwani 3 years ago

    If the variable is a single element array where the first element is $null, then the check to see if the variable is empty or not will fail.
    $a=@($null)
    If($a) {$true} else {$false} => False

    $a=@($null,$null)
    If($a) {$true} else {$false} => True

    As you can see above, PowerShell automatically expands single element arrays and treats them as if they are not arrays. Therefore, you have to be very careful about how you check for the existence of arrays to not run into strange bugs.

    I use the below function to help me out:
    Function IsNullOrEmpty {
    PowerShell will set $a = 0
    If you set [switch]$b = $null ==> PowerShell will set $b = $false
    If you set [string]$c = $null ==> PowerShell will set $c = ''

    After people complained about not being able to set variables of [string] type to $null,
    PowerShell 3 gained the ability to set a [string] type to $null like this:
    [string]$d = [System.Management.Automation.Language.NullString]::Value
    .LINK
    #>
    [CmdletBinding()]
    Param (
    [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [AllowNull()]
    [AllowEmptyString()]
    [AllowEmptyCollection()]
    $InputObject
    )
    Process {
    ## Switching the comparison order of this 'If' statement can give inaccurate
    ## results when arrays are involved, so don't touch.
    If ($null -eq $InputObject) {
    Write-Output $true
    }
    ElseIf (($InputObject -is [array]) -and (-not $InputObject.Count)) {
    Write-Output $true
    }
    ElseIf (($InputObject -is [string]) -and (-not $InputObject)) {
    Write-Output $true
    }
    ## To handle null values from SQL databases.
    ElseIf ($InputObject -is [DBNull]) {
    Write-Output $true
    }
    Else {
    Write-Output $false
    }
    }
    }

    0

  4. M Mashwani 3 years ago

    Sorry about the above paste of the funciton. It got mangled as a comment. I've posted the function on pastebin here: http://pastebin.com/bEtNJhk8

    0

  5. Michael Pietroforte 3 years ago

    I think we agree that an array that is empty (not defined) is something different than an array which only contains elements with empty values (NULL). Likewise, a scalar (or a single element array) that is empty is something different than a scalar that contains NULL. Thus, my test won't fail if I just want to know if a variable is empty.

    However, if you explicitly assign empty values ($Null) as placeholders to variables, then we are talking about something completely different. In this case, if you want to test, if an array is empty (not defined), you can test it this way:

    If($myArray.count) {"I am not empty, but I might contain empty elements"}

    And if you want to test whether $Null has been assigned to a variable, we are talking again about a completely different animal. If you want to check whether a string is empty or NULL, you can use the .NET method IsNullOrEmpty()

    If([string]::IsNullOrEmpty($myString)) {"I am either empty or NULL"}

    0

  6. Emil 2 months ago

    The problem is that here is the result of the initial script in my PS console:

    Windows PowerShell
    Copyright (C) 2015 Microsoft Corporation. All rights reserved.

    PS C:\windows\system32> ($Error -eq $Null) -or ($Error -ne $Null)
    True
    PS C:\windows\system32>

     

    0

Leave a reply

Your email address will not be published. Required fields are marked *

*

CONTACT US

Please ask IT administration questions in the forum. Any other messages are welcome.

Sending
© 4sysops 2006 - 2017

Log in with your credentials

or    

Forgot your details?

Create Account