Powershell – Conditional Logic


To totally unlock this section you need to Log-in


Login

As with other programming languages, PowerShell is a dynamic scripting language. Script code can be executed based on conditions that exist or occur. For example, a script might prompt for user input and run a block of code based on the data supplied by the user. A process or application may stop running, triggering an action within a script.

Conditional Logic allows us to write scripts in a complex environment, it adds the intelligence required to create decision-making scripts. Launch PowerShell and let's get started.

Comparing Data

We are going to compare data using the following PowerShell Comparison and Logical Operators.

Table 1: PowerShell Comparison Operators:

I'm not going to join in the great debate over why these operators where chosen, they exists within PowerShell and must be used. Special note: When comparing text strings, by default PowerShell is not case-sensitive.
"TOM" and "tom" would compare "equal to" (-eq).

However, you can force PowerShell to compare values based on case-sensitivity. By appending an "i" to the operator, you're telling PowerShell to be "case-insensitive." Appending a "c" forces PowerShell to compare as "case-sensitive".

Examples:

Tom -eq TOM. The result is "True"
Tom -ieq TOM. The result is "True"
Tom -ceq TOM. The result is "False"

Table 2: PowerShell Logical Operators:

Now that we have the table listings of Operators, let's do some examples to show their use and results:

7 -eq 7<enter>
Result is "True"

7 -ne 7<enter> Result is "False"
7 -lt 10<enter> Result is "True"
7 -gt 10<enter> Result is "False"
"Tom" -eq "tOm"<enter> Result is "True"
"Tom" -ceq "tOm"<enter> Result is "False"

I'm going to skip the logical operators for now, we'll get back to them in a moment. What's important to understand is each code snippet is providing a result, either True or False.

The results are used in the decision-making process within PowerShell scripts.

Conditional Logic

Now that we have results, what do we do with them? We need a way to apply comparison results with conditional logic (the decision-making process). PowerShell supports two logic statements to help out:

  1. if - evaluates a comparison, then either executes or sidesteps code blocks based on the result. if statements require result of the comparison to beTrue to execute it's associated code block.
  2. switch - Does the same as the if statement with the exception that it can evaluate multiple comparisons, each having the ability to execute code blocks. This is the same as a "select case" or "case" statements in VBScript and other programming languages.

Using the "if" Statement

The if statement syntax:

if (condition) {code block}
elseif (condition) {code block}
else (condition) {code block}

  • condition = an expression that results to a Boolean Value (True or False).
  • code block = what to execute if condition is True.
  • elseif (optional) = test an alternative condition if preceding condition was False.
  • else (optional) = executes it's code block whenever none of the if or elseif statements return a True result.

Let's do a simple script that shows the if statement in action:

  • Copy the code into clogic.ps1 file and save it to the "MyScripts" directory.
  • Run the script: "C:\MyScripts\clogic.ps1<enter>" -or- type ".\clogic.ps1" if you are currently working in the MyScripts directory.
$x = 2 #creates a variable x and assigns 2 as the value
  if ($x -eq 5) {Write-Host "Hello my name is Bob"}
    elseif ($x -eq 4) {Write-Host "Hello, my name is Sue"}
    elseif ($x -eq 2) {Write-Host "Hello, my name is Troy"}
    elseif ($x -gt 1) {Write-Host "Hello, my name is Mary"}
  else {"I have no idea what my name is?"}

The result should be Hello, my name is Troy as the condition ($x -eq 2) resulted in aTrue value and executed the script block {}. But I purposely threw you a curve ball. Notice that the last elseif statement ($x -gt 1) would also result in a True condition, so why doesn't it's script block get executed?

This is by design, once an if statement conditionresults in a True value the associated script block is executed and PowerShell stops testing subsequent conditions.

The way around this is to use a switch statement which we will discuss in this PowerShell training session.

Real-World Example

Sometimes different Operating Systems use different WMI classes and/or properties. I ran into this difference when attempting to enumerate printers on Windows XP, Windows 2003, and Windows 2000.
I used an if statement to test the OS version and based on the version, PowerShell would run the code block associated for each OS. Here's the code I used: copy the following code into a .ps1 script file. Name it PrintReport.ps1 and execute the script:

$strComputer = Read-Host "Printer Report – Enter Computer Name"
$OS = Get-WmiObject -Class win32_OperatingSystem -namespace "root\CIMV2" `
-ComputerName $strComputer
# if statement to run code for Windows XP and Windows 2003 Server.
if (($OS.Version -eq "5.1.2600") -or ($OS.Version -eq "5.2.3790"))
{
    write-host "Computer Name: " $strComputer
    #nested if statement
    if ($OS.Version -eq "5.1.2600") {write-host "OS Version: Windows XP"}
    elseif ($OS.Version -eq "5.2.3790") {write-host "OS Version: Windows 2003"}
        $colPrinters = Get-WmiObject -Class win32_Printer -namespace "root\CIMV2" `
        -computerName $strComputer
            foreach ($objPrinter in $colPrinters) {
            write-host "Name: " $objPrinter.Name
            write-host "Description: " $objPrinter.Description
            write-host
            }
}
# if statement to run code for Windows 2000 Server
elseif ($OS.Version -eq "5.0.2195")
{
    write-host "Computer Name: " $strComputer
    write-host "OS Version: Windows 2000 Server"
        $colPrinters = Get-WmiObject -Class win32_PrintJob -namespace "root\CIMV2" `
        -computername $strComputer
        foreach ($objPrinter in $colPrinters) {
        write-host "Name: " $objPrinter.Name
        write-host "Description: " $objPrinter.Description
        write-host
        }
}
# if OS not identified
else {write-host "The OS for: $strComputer is not supported."}
write-host "–END OF REPORT–"

When the script is executed, you are prompted to enter the computer name you wish to enumerate. By adding the "Read-Host" cmdlet, you're now able to enumerate other computers on your network. Pretty cool stuff going on here, let's break it down.

Step 1

$strComputer = Read-Host "Printer Report – Enter Computer Name"

Creates a variable called $strComputer and assigns a value supplied from user input.

Step 2. 

$OS = Get-WmiObject -Class win32_OperatingSystem -namespace "root\CIMV2" -ComputerName $strComputer

Creates the variable "$OS" and assigns the win32_OperatingSystem class object. Something else to look at. Even though it looks like two lines of code, it's actually one line of code.

Step 3. 

if (($OS.Version -eq "5.1.2600") -or ($OS.Version -eq "5.2.3790"))

Here is where we talk about Logical Operators.

What you need to know: the Not operators -not and ! (both mean NOT) allow you to modify the results of a condition. For example:

if (1 -eq 1) – results in a True value and runs the script block.
if (!(1 -eq 1) – results in a False value and skips the script block.

The -or operator means at least one of the conditions must be True to execute the script block.

For example:

if ((1 -gt 2) -or (2 -gt 1)) 

If one of the conditions are True so, its associated script block will execute.

The -and operator means that all conditions must be True to execute the script block.

For example:

if ((1 -ge 1) -and (2 -ge 1))

Both conditions are True, script block executes.

if ((1 -ge 1) -and (2 -le 1))

In this case the first condition is True, whereas the second is False. The script block is skipped.

Step 4

{
write-host "Computer Name: " $strComputer
#nested if statement
 if ($OS.Version -eq "5.1.2600") {write-host "OS Version: Windows XP"} elseif ($OS.Version -eq "5.2.3790") {write-host "OS Version: Windows 2003"}
$colPrinters = Get-WmiObject -Class win32_Printer -namespace "root\CIMV2" `
-computerName $strComputer
foreach ($objPrinter in $colPrinters) {
write-host "Name: " $objPrinter.Name
write-host "Description: " $objPrinter.Description
write-host
}
}

In Step 3  if one of the conditions are True the script block in Step 4. is executed. The script block writes the following information to the screen:

  • The Computer Name
  • The OS Type – Note, in RED, we can nest additional if statements within code blocks. Now you are stating to see how complex PowerShell, as a scripting language, can be.
  • The script block then enumerates the win32_Printer class and sends the requested property information to the screen.
  • Once the block completes, PowerShell skips to Step 8 and writes "–END OF REPORT–" to let the end user know it has completed.

If none of the conditions are True in step 3. PowerShell moves to the next if statement, in this example that would be...

Step 5

elseif ($OS.Version -eq "5.0.2195")

If this condition results in a True value, the script block in Step 6 is executed.

Step 6

{
    write-host "Computer Name: " $strComputer
    write-host "OS Version: Windows 2000 Server"
        $colPrinters = Get-WmiObject -Class win32_PrintJob -namespace "root\CIMV2" `
        -computername $strComputer
        foreach ($objPrinter in $colPrinters) {
        write-host "Name: " $objPrinter.Name
        write-host "Description: " $objPrinter.Description
        write-host
        }
}

The result of the script block outputs the following information to the screen:

  • Computer Name
  • OS version
  • Requested Property information of the win32_PrintJob class.
  • Once the block completes, PowerShell skips to Step 8. and writes "–END OF REPORT–" to let the end user know it has completed.

If the result in Step 5 is False, PowerShell continues reading the script and finds the "else" statement.

Step 7

else {write-host "The OS for: "$strComputer" is not supported."}

It will outputs " The OS is not supported."

Step 7 runs when all conditions in the script end with a False value.

Step 8

write-host "–END OF REPORT–"

Let's you know the script has completed. This example shows just how dynamic our scripts can be, based on conditions that exist in our environment. And how we can write if statements to test those conditions and run script blocks according to the results of those tests.

Using the Switch Statement for Multiple Comparisons

Since we can use elseif statements to test multiple conditions, there may come a time when too many additional tests lend to difficult script writing and down-right ugliness. There are other times where you want to test multiple conditions that result in multiple True values and you don't want the script to stop testing when it receives the first True value (as it does with an if statement).

The option that allows you to accomplish this is the switch statement.

The PowerShell switch statement organizes a collection of tests that are evaluated using the same expression.

The Switch statement syntax:

switch (expression)
{
  (test) {code block}
  value {code block}
  default {code block}
}

  • Test = An evaluated expression.
  • Value =  A value, like a number or text string.
  • Default = Default code block to run if none of the expressions return a True value.

Here is an example from Ed Wilson's PowerShell book: "Windows PowerShell Step by Step". Save the script code as ComputerRoles.ps1 and run the script:

$objWMI = Get-WmiObject -Class win32_ComputerSystem -namespace "root\CIMV2"
"Computer "+ $objWMI.name + " is a: "
switch ($objWMI.domainRole)
  {
  0 {Write-Host "Stand alone workstation"}
  1 {Write-Host "Member workstation"}
  2 {Write-Host "Stand alone server"}
  3 {Write-Host "Member server"}
  4 {Write-Host "Back-up domain controller"}
  5 {Write-Host "Primary domain controller"}
  default {Write-Host "The role can not be determined"}
  }

In this example I used a number value which correlates to the value of the domain role property within the win32_ComputerSystem WMI class. When the value was returned as True, the script block output the role using the "Write-Host" cmdlet.

Modify the script to prompt user for "Computer Name":

$strComputer = Read-Host "Enter Computer Name"
$objWMI = Get-WmiObject -Class win32_ComputerSystem -namespace "root\CIMV2" `
  -computername $strComputer
Write-Host "Computer: $strComputer is a:"
switch ($objWMI.domainRole)
  {
  0 {Write-Host "Stand alone workstation"}
  1 {Write-Host "Member workstation"}
  2 {Write-Host "Stand alone server"}
  3 {Write-Host "Member server"}
  4 {Write-Host "Back-up domain controller"}
  5 {Write-Host "Primary domain controller"}
  default {Write-Host "The role can not be determined"}
  }

Now that we can input the $strComputer value, we can run this script on any remote computer in the environment, as long we have local admin rights.

This next example has no real purpose other than demonstrating how the switch statement works using the (test) expression with multiple True value results.

Unlike if statements, switch statements continue running when True value matches are found. So it is possible that more than one code block will be executed. Copy and Paste the code into the PowerShell shell.

The results should be obvious, test expressions that correctly equal 10 will run:

switch (10)
{
  (1 + 9) {Write-Host "Congratulations, you applied addition correctly"}
  (1 + 10) {Write-Host "This script block better not run"}
  (11 – 1) {Write-Host "Congratulations, you found the difference correctly"}
  (1 – 11) {Write-Host "This script block better not run"}
}

Conditional logic is the foundation for dynamic PowerShell script writing. We successfully demonstrated how we can control the flow of a script base on conditional responses.
In the next PowerShell training session we are going to build on what we have learned and introduce Loops, which takes flow control to the next level.