On Twitter tonight I saw a link get tweeted to a video on the Switch statement in PowerShell. The video was done by MrPowerScripts who appears to have posted quite the collection of videos on PowerShell. It seems like it will be a great resource for beginners and PowerShell users in general. I’m looking forward to future posts.
The Switch video caught my eye because I really like that statement. I don’t know what it is about human nature but we (I at least) seem to use If as the go to programming flow-control construct. When more often than not the Switch serves our needs much better for anything other than the basic if/else.
The video is a great introduction to Switch in PowerShell, however it also reminded me of some of the really cool features of the Switch statement. The PowerShell Switch has some features that I do not think are common amongst other programming languages. For instance the Switch acts as a loop if the expression (the code or variable between the parenthesis) evaluates to a collection or an array. In the video the idea is that using the Switch can shorten and simplify your code, if you’ve used a bundle of if/else or nested if statements. In his example he uses a Foreach loop to drive his simplified Switch statement but really with the added benefit to Switch under PowerShell he could drop the Foreach and just utilize the Switch for comparison and looping. Something like this:
$TXT = 0 $PDF = 0 $XML = 0 $Stuff = Get-ChildItem D:\PowerShell\Temp -Recurse Switch -wildcard ($Stuff) { *.txt {$TXT = $TXT + 1} *.pdf {$PDF = $PDF + 1} *.xml {$XML = $XML + 1} } Write-Host "$TXT text files" Write-Host "$PDF pdf files" Write-Host "$XML xml files"
Or eliminate the variable and do this:
$TXT = 0 $PDF = 0 $XML = 0 Switch -wildcard (Get-ChildItem D:\PowerShell\Temp -Recurse) { *.txt {$TXT = $TXT + 1} *.pdf {$PDF = $PDF + 1} *.xml {$XML = $XML + 1} } Write-Host "$TXT text files" Write-Host "$PDF pdf files" Write-Host "$XML xml files"
Either way the output would be the same:
17 text files 7 pdf files 14 xml files
Another of the cool features of the Switch statement, whether your expression value results in a single item or a collection/array, is that the condition you test with can be an expression itself. To expand on the examples above you could do something like the following:
$Mon = $Tue = $Wed = $Thu = $Fri = $Sat = $Sun = 0 Switch (Get-ChildItem D:\PowerShell\Temp -Recurse) { {$_.LastWriteTime.DayOfWeek -eq 'Monday'} {$Mon += 1} {$_.LastWriteTime.DayOfWeek -eq 'Tuesday'} {$Tue += 1} {$_.LastWriteTime.DayOfWeek -eq 'Wednesday'} {$Wed += 1} {$_.LastWriteTime.DayOfWeek -eq 'Thursday'} {$Thu += 1} {$_.LastWriteTime.DayOfWeek -eq 'Friday'} {$Fri += 1} {$_.LastWriteTime.DayOfWeek -eq 'Saturday'} {$Sat += 1} {$_.LastWriteTime.DayOfWeek -eq 'Sunday'} {$Sun += 1} } Write-Host "Monday: $Mon" Write-Host "Tuesday: $Tue" Write-Host "Wednesday: $Wed" Write-Host "Thursday: $Thu" Write-Host "Friday: $Fri" Write-Host "Saturday: $Sat" Write-Host "Sunday: $Sun"
And evaluate the condition of specific properties, and get the following output
Monday: 14 Tuesday: 3 Wednesday: 0 Thursday: 17 Friday: 1 Saturday: 6 Sunday: 3
Lastly one of the other cool features of Switch that I have used many times before is the -File parameter. You can replace the -wildcard parameter and the expression with -regex and -file to specify a file to parse. For example reading in a log file and extracting some lines of interest. With a typical IIS log file line looking something like this:
2012-01-10 07:59:03 W3SVC2 XLM-4A52 10.127.17.4 GET ...
You could then parse using -File like the following:
[string[]]$OnePm = @() [string[]]$ThreePm = @() [string[]]$EightPm = @() Switch -regex -file D:\PowerShell\Temp\u_ex120110.log { '^2012-01-10 13:' {$OnePm += $_} '^2012-01-10 15:' {$ThreePm += $_} '^2012-01-10 20:' {$EightPm += $_} }
I’ve effectively parsed my log file and extracted, to string arrays I can further manipulate, the data I want. In this case I did 3 regular expressions to find lines that started with the date and hour (1pm, 3pm, and 8pm) that were of interest to me. As it is on the pipline the $_ is the automatic variable that contains the current item.
This logic is similar to using Get-Content in the expression (i.e. Switch -regex (Get-Content u_ex120110.log)) but the -File parameter is a little better performing because Get-Content has to read in the entire file and then do the regex evaluation. Where as the -File parameter does a line by line read and evaluate. Comes in handy when files, like logs, are bigger rather than smaller.
There you have it. The Switch is bathed in PowerShell awesomeness. It really should be ranked higher in our brains go to list of flow-control programming tools when it comes to our PowerShell scripting.