Windows PowerShell Tip of the Week

Here’s a quick tip on working with Windows PowerShell. These are published every week for as long as we can come up with new tips. If you have a tip you’d like us to share or a question about how to do something, let us know.

Find more tips in the Windows PowerShell Tip of the Week archive.

Using the Switch Statement

When the Scripting Guys attended TechEd IT Forum this past November, we took time off from our booth duties to listen to Windows PowerShell architect Jeffrey Snover talk about PowerShell. At one point in his talk, Jeffrey noted that one of the coolest and most useful features found in PowerShell is the switch statement. Needless to say, that took the Scripting Guys a little by surprise: out of all the features packed into Windows PowerShell one of the coolest and most useful is the switch statement?!? We found that a little hard to believe.

But you know what? Jeffrey just might have been right.

The Basic Switch Statement

The switch statement is similar to VBScript’s Select Case statement: it enables you to write a script that can choose from a series of options, but without requiring you to write a long series of if statements. For example, consider the following script:

$a = 5

switch ($a)
    {
        1 {"The color is red."}
        2 {"The color is blue."}
        3 {"The color is green."}
        4 {"The color is yellow."}
        5 {"The color is orange."}
        6 {"The color is purple."}
        7 {"The color is pink."}
        8 {"The color is brown."}
        default {"The color could not be determined."}
    }

In this script, we start out by assigning the value 5 to a variable named $a. We then create a Switch block that assesses the value of $a and takes the appropriate action based upon that value; that’s what this line of code does:

switch ($a)

As you can see, all we do is insert the Switch keyword followed by the value to be tested. (Oh, and as is typically the case with PowerShell, the value to be tested must be enclosed in parentheses).

What follows next is a series of statements, all enclosed in a scriptblock. (That is, all enclosed in curly braces.) The scriptblock is where we tell the script what to do based on the value being tested. For example, if $a is equal to 1 we want to echo back a message saying that the color is red. Therefore, we use this line of code, with the action we want to take also enclosed in curly braces:

1 {"The color is red."}

See how that works? You might have noticed as well that, at the tail end of the scriptblock, we specified an action to be taken if none of the preceding Case statements are true (the same thing you do with Case Else in VBScript). To do that we simply tacked on the default condition followed by the desired action:

default {"The color could not be determined."}

And there you have it: the Windows PowerShell switch statement. When we run the preceding script, the following message is echoed back to the screen:

The color is orange.

Using Wildcards with the Switch Statement

Now, we know what you’re thinking: that was all right, but it wasn’t that cool. Point taken. But suppose we told you that you could use wildcard characters in your switch statement. Would that change your opinion about just how cool the switch statement really is?

For example, consider this script, one that sets the value of $a to d14151. We’re going to assume here that d14151 is a part number, and that the d means that the color of this part is yellow. So how can we echo back the fact that the color is yellow, especially if we could have scores of part numbers that start with the letter d (d14151, d14152, d14153, etc.)? Well, here’s one way to do that:

$a = "d14151"

switch -wildcard ($a)
    {
        "a*" {"The color is red."}
        "b*" {"The color is blue."}
        "c*" {"The color is green."}
        "d*" {"The color is yellow."}
        "e*" {"The color is orange."}
        "f*" {"The color is purple."}
        "g*" {"The color is pink."}
        "h*" {"The color is brown."}
        default {"The color could not be determined."}
    }

Notice that we’ve done two things here. First, we’ve added the –wildcard parameter; this tells the switch statement that we’re going to use wildcard characters when we assess the value of $a. Second, notice that we’ve used the asterisk (a standard wildcard character meaning “anything”) in our condition statements:

"a*" {"The color is red."}

This line of code simply says, “If the value of $a starts with the letter a – and we don’t care what comes after that first letter, if anything – then echo back the fact that the color is red.” In other words, if $a is equal to a14151, or $a is equal to a7777777777, or $a is equal to apple, or $a is equal to anything that starts with the letter a then the color is red.

Does that really work? You bet it does; our part number starts with the letter d, and our script correctly echoes back the fact that the color is yellow:

The color is yellow.

Incidentally, you can put these wildcard characters anywhere in the string. Want to take action if the last character in $a is the letter d? Then use this command, with the letter d coming after the asterisk:

"*d" {"The color is yellow."}

Here’s another interesting use for wildcards. Suppose that, when it comes to color, the first letter of the part number is irrelevant. (For example, maybe the first letter indicates where the part was manufactured.) Suppose, too that it’s the last 5 characters of the part number that determine the color. How can we identify the color for a given part number? Why, like this, of course:

$a = "d14151"

switch -wildcard ($a)
    {
        "?14150" {"The color is red."}
        "?14151" {"The color is blue."}
        "?14152" {"The color is green."}
        "?14153" {"The color is yellow."}
        "?14154" {"The color is orange."}
        "?14155" {"The color is purple."}
        "?14156" {"The color is pink."}
        "?14157" {"The color is brown."}
        default {"The color could not be determined."}
    }

This time around we’ve configured our condition statements by using a question mark (?) followed by a 5-digit number. Again, this is standard wildcard convention: the question mark simply means, “Any one character.” In other words, the statement "?14150" {"The color is red."} says, “If $a starts off with a character, any character, followed by 14150 then the color is red.” See how that works? If $a is equal to d14151 (which it is), then our script should report back that the color is blue. Let’s see if it does:

The color is blue.

You know, the more we play around with the switch statement the more we’re beginning to think that it really is kind of cool.

Using Regular Expressions with the Switch Statement

Wildcards are nice, but they have their limitations; by contrast, there are very few things that can’t be done using regular expressions. For example, suppose a range of letters are used to represent a particular color; that is, suppose any part number beginning with the letters a, b, c, or d indicates the color red. Can you use wildcards to identify the color type? To tell you the truth, we’re not sure. But we know that you can use regular expressions to determine the color type:

$a = "r14151"

switch -regex ($a)
    {
        "[a-d]" {"The color is red."}
        "[e-g]" {"The color is blue."}
        "[h-k]" {"The color is green."}
        "[l-o]" {"The color is yellow."}
        "[p-s]" {"The color is orange."}
        "[t-v]" {"The color is purple."}
        "[w-y]" {"The color is pink."}
        "[z]" {"The color is brown."}
        default {"The color could not be determined."}
    }

So how does this script differ from our wildcard scripts? Well, for starters, we used the –regex parameter instead of the –wildcard parameter; as you can probably guess, this tells the switch statement that we’re using regular expressions in our condition statements. In addition, we, well, use regular expressions in our condition statements. Suppose we want to choose any of the letters a, b, c, or d. With a regular expression, we can do that by specifying a character range: [a-d]. Well, guess what our first condition statement looks like? You got it:

"[a-d]" {"The color is red."}

Nice, huh? If $a is set to r14151 (which it is), we’ll get back the following when we run the script:

The color is orange.

Let’s use regular expressions to illustrate another feature of the switch statement. Let’s assume that colors are now indicated by the number of digits in the part number. In other words, you can determine the color type simply by counting the number of digits in $a. One way to do that (not the best way, mind you, but a way that suits our ultimate needs) is this:

$a = "14151"

switch -regex ($a)
    {
        "\d{8}" {"The color is red."}
        "\d{7}" {"The color is blue."}
        "\d{6}" {"The color is green."}
        "\d{5}" {"The color is yellow."}
        "\d{4}" {"The color is orange."}
        "\d{3}" {"The color is purple."}
        "\d{2}" {"The color is pink."}
        "\d{1}" {"The color is brown."}
        default {"The color could not be determined."}
    }

As you can see (assuming you have a basic understanding of regular expressions), our first condition checks to see if $a contains 8 consecutive numbers (\d{8}). If it does, we echo back the fact that the color is red. In the second condition, we check to see if $a has 7 consecutive digits, and so on and so on. Because $a consists of 5 consecutive digits you might expect that that script would tell us that the color is yellow. Unfortunately, though, it tells us this:

The color is yellow.
The color is orange.
The color is purple.
The color is pink.
The color is brown.

Eep.

So what went wrong? Well, in a VBScript Select Case statement once a true condition has been encountered the script exits Select Case; it doesn’t continue checking all the other conditions. That isn’t necessarily true in Windows PowerShell. PowerShell checked to see if $a contains 5 consecutive digits; because it does, it echoes back the message that the color is yellow. That’s great.

Except that PowerShell, unlike VBScript, doesn’t stop there; instead it goes on and evaluates the next condition as well. And because $a does include 4 consecutive digits the script then echoes back that the color is orange. And PowerShell doesn’t stop there, either. In fact, it dutifully evaluates every single condition in the switch statement.

Eep indeed.

There are times when this functionality is good; especially with things like part numbers where a value could fill multiple conditions (it has 5 digits so the color is red, the part number starts with the letter d meaning it was manufacturer in Des Moines, etc.). At other times – like this one – we’d really prefer that PowerShell find the first true condition and then exit the switch statement. But how do we do that?

Actually, that’s easy: just add the break statement to the scriptblock for each condition:

$a = "14151"

switch -regex ($a)
    {
        "\d{8}" {"The color is red.”; break}
        "\d{7}" {"The color is blue.”; break}
        "\d{6}" {"The color is green.”; break}
        "\d{5}" {"The color is yellow.”; break}
        "\d{4}" {"The color is orange.”; break}
        "\d{3}" {"The color is purple.”; break}
        "\d{2}" {"The color is pink.”; break}
        "\d{1}" {"The color is brown.”; break}
        default {"The color could not be determined."}
    }

This time around PowerShell will find the first true condition – $a has 5 consecutive digits – and then exit.

Using Arrays with the Switch Statement

Let’s show you one more, just for the heck of it. Amazingly enough, the switch statement can actually evaluate arrays. In other words, suppose we have the following script:

$a = 21, 38, 6

switch ($a)
    {
        1 {"The color is red."}
        2 {"The color is blue."}
        3 {"The color is green."}
        4 {"The color is yellow."}
        5 {"The color is orange."}
        6 {"The color is purple."}
        7 {"The color is pink."}
        8 {"The color is brown."}
    }

When we run this script, PowerShell will evaluate all the items in the array $a to see if any of them meet the specified condition. For example, the first condition says, “If $a is equal to 1 then the color is red.” PowerShell will examine all three of the values in $a – 21, 38, and 6 – to see if any of them meet the criteria. (Hint: they don’t.) If and when a match is found, the script will echo back the appropriate message. In other words:

The color is purple.

You were right, Jeffrey: the switch statement is cool!

See you all next week.