Executive Summary: Lesson 3 of Robert Sheldon's PowerShell 201 series discusses Microsoft Windows PowerShell's switch statement. The switch statement is easier to use than PowerShell's if statement when you need to test for numerous conditions and perform different actions based on those conditions. This lesson looks at the switch statement's components and demonstrates how to use them in the PowerShell console.

Windows PowerShell’s switch statement is a powerful language construct that lets you test for specific conditions, similar to an if statement. However, a switch statement is easier to implement when you want to evaluate numerous conditions. Let’s look at the various components that make up the switch statement and explore how to use them to automate such tasks as retrieving System event log entries and performing certain actions based on the type of entry, and moving and deleting files based on their filenames.

Creating Switch Statements
The switch statement compares one or more values to one or more conditions. For each condition that evaluates to true, the statement runs the script block associated with that condition. To better understand how a switch statement works, let’s take a look at its syntax:

switch <options> (<collection>)
  <condition 1> \{<script block 1>\}
  \[<condition 2> \{<script block 2>\}\]
  \[<condition 3> \{<script block 3>\}\]
  \[<condition n> \{<script block n>\}\]
  \[default \{<default script block>\}\]

The first line begins with the keyword switch, followed by one or more options and a collection. The switch statement supports five options that let you, for example, use wildcards and regular expressions. The collection, which is enclosed in parentheses, contains what you’re checking (e.g., events, files). It can consist of zero or more elements.

Windows It Pro Resources

To read the previous lessons in the PowerShell

201 series, go to “Iterating Through Collections with PowerShell’s foreach Loops,” InstantDoc ID 99873

“Controlling Your Code’s Flow with PowerShell’s Conditional Statements,” InstantDoc ID 100141

The braces in the second and last line enclose the switch statement’s script block. The first line in this block includes a condition and that condition’s script block, which is also enclosed in braces. If the condition evaluates to true, the condition’s script block runs. You can include as many condition/script block pairs as necessary. In addition, you can include an optional default clause that contains a script block, which runs only when none of the conditions evaluate to true.

Now let’s look at an example. The code in Listing 1 defines the $event variable and uses that variable in a switch statement. The first line uses the Get-EventLog cmdlet to retrieve the most recent event from the local computer’s System event log. When you use this cmdlet to retrieve System event log entries, it returns a Microsoft .NET Framework System.Diagnostics.EventLog- Entry object for each event. This object returns the information you typically find in a System event log entry, such as the when the event occurred, the type of event, and the event’s message.

In Listing 1, the Get-EventLog cmdlet assigns the information from the most recent event to the $event variable. Using the EventLogEntry object’s EntryType property, the switch statement retrieves the type of event and compares that element to the defined conditions.

In a switch statement, you can simply specify a value as a condition. PowerShell then automatically compares that value to each collection element. As callout A in Listing 1 shows, the first condition is defined as error. When this value is equal to the collection element (i.e., the EntryType property value), the condition evaluates to true and the script block runs. In other words, when the event type is error, the script block outputs the word ERROR: followed by the event’s message, which is obtained using the EventLogEntry object’s Message property.

The switch statement’s script block contains two other conditions, but you can define as many conditions as necessary. For each condition that evaluates to true, the associated script block runs. If multiple conditions evaluate to true, all associated script blocks run. In this example, only one condition script block will run because the collection contains only one element.

Note that, by default, the switch statement is case insensitive. For example, you can spell the first condition as error, ERROR, or Error, and the results will be the same. However, you can override this default behavior by specifying the -casesensitive option, as in

switch -casesensitive ($event.EntryType)

One other point I want to make concerns the collection. The code in Listing 1 retrieves the EntryType property value as part of the collection. However, you can retrieve that value in the conditions, as shown in Listing 2.

Notice that the collection now includes only $event. The conditions use the $_ builtin variable to reference the current $event value, then use the EntryType property to retrieve the entry type. When you take this approach, you must define the entire condition and enclose it in braces. For example, the condition \{$_.entrytype -eq "error"\} specifically says that the EntryType value must equal error. Listing 2 will return the same results as Listing 1.

When working with a collection that contains one element, you’ll probably want to stick with the first approach because it’s simpler. However, when a collection contains multiple elements, you have to use the second approach if the switch statement can’t work with the collection as is. For example, if you use Get-EventLog to return multiple system events, you must retrieve the EntryType value in each condition, as Listing 3 shows. In this code, the collection specifies only the variable name $events. This collection contains the last 10 system events. The conditions use the EntryType property to retrieve the entry type. Listing 3 returns results similar to those in Figure 1.

Continue to page 2

If you refer back to the switch statement’s syntax, notice that the last line in the statement’s script block is a default clause. The code in Listing 4 uses a default clause rather than defining a third condition. Any event that doesn’t contain an EntryType value of error or warning is treated as a default, which means that the returned message will begin with Info only:. Listing 4 returns the same results as Listing 3 but with a bit less work.

Using Wildcards and Regular Expressions
By default, the string value specified in the switch statement’s script block has to exactly match a condition for that condition to evaluate to true. This would be the same as using the -exact option in a switch statement. Even though the option isn’t necessary for exact matches, a person might include it to ensure that the intent of the code is clear, should anyone else review the code.

Besides the -exact option, there are options that let you use wildcards (-wildcard option) or regular expressions (-regex option) in switch statements. (If you’re unfamiliar with wildcards or regular expressions, see the PowerShell help topics about_wildcard and about_regular_ expression.) For example, the switch statement in Listing 5 uses wildcards to move files. The first line retrieves a list of text files and assigns them to the $files variable, which becomes the collection. Notice that ($files) is preceded by the -wildcard option, which tells PowerShell that wildcards will be used.

For example, the condition in callout A in Listing 5 uses the wildcard *2007*, which means the filename must contain the string 2007, with any number of characters on either side. If a filename contains the string 2007, the switch statement moves the file to the 2007 folder and displays a message indicating that the file has been moved. Because the collection contained eight files, PowerShell returns eight messages, as shown in Figure 2.

Like Listings 3 and 4, Listing 5 uses only a variable name (e.g., $files, $event) for the collection. Unlike Listings 3 and 4, Listing 5 specifies only the $_ built-in variable in each condition and not $_.PropertyName (where PropertyName is the name of the property you want to retrieve). Sometimes the only way to know which technique will work is through trial and error.

When you want to use regular expressions, you use the -regex option. For example, the switch statement in Listing 6 uses two regular expressions, the first of which is in the condition in callout A. This condition uses the regular expression archive.._200\[3-5\] .txt to delete any file whose filename begins with the string archive and ends with the string _2003.txt, _2004.txt, or _2005.txt. The condition in callout B uses the regular expression archive.._2006.txt to move any file that begins with the string archive and ends with the string _2006.txt to the 2006 folder. The default clause moves all other files to the 2007 folder. Figure 3 shows the messages outputted from the code in Listing 6.

As I mentioned previously, the switch statement supports the -casesensitive option, which lets you make the matching process case sensitive. You can use this option with other options, as Listing 7 shows. In this code, notice that I use -case instead of -casesensitive. You can use a short version of an option name if PowerShell can distinguish the correct option.

With the addition of the -casesensitive option, the filenames’ cases must exactly match. For example, the second condition (archive.._2006.txt) evaluates to true for archive05_2006.txt but not for Archive05_ 2006.txt. Because all eight files begin with uppercase, the default condition applies and all eight files are moved to the 2007 folder, as shown in Figure 4.

Working with a File’s Contents
Another useful option is -file. You use this option when you want to use a file’s contents as the collection. Each line in the file represents an element in the collection. For example, the following switch statement retrieves the Archive08_2007.txt file’s contents:

switch -regex -file `
  "line 1\)$" \{ "Line 1: $_" \}
  "line 2\)$" \{ "Line 2: $_" \}
  "line 3\)$" \{ "Line 3: $_" \}
  "line 4\)$" \{ "Line 4: $_" \}
  default \{ "Other line: $_" \}

As this example shows, you must include the file’s pathname after the keyword -file. In the switch statement’s script block, the first condition specifies that a line must end in the string line 1). If the condition evaluates to true, the phrase Line 1: is printed, followed by the line itself ($_). If none of the four conditions evaluate to true, the default clause runs, as shown in Figure 5.

Moving Forward
The switch statement is a valuable tool for working with collections and multiple conditions. You can make the statement as simple or as complex as necessary. For example, you can embed other types of flow control statements within the conditions’ script blocks. Be sure to try out various configurations and access different types of data stores to better learn how to take full advantage of all that the switch statement has to offer.