Friday Fun: I’m with the band.

black-guitarI like to have fun with PowerShell, as is hopefully evident with this Friday Fun serious, and today that is especially true. Perhaps you need a quick break from the end of the week grind. Or maybe you want to learn something new about PowerShell. Hopefully today’s fun will meet both requirements. Today’s fun will include XML, scope and Switch. Let’s rock.

If you haven’t figured it out, rock ‘n roll is the theme for today. I have put together a little rock and roll quiz. In many rock bands there’s at least one member is well known. If someone says “Axl Rose” you most likely will know Guns n’ Roses. But would you recognize the other members of the band? I created an XML document with a number of well known rock bands. Because band members change, I tried to use the line ups from the bands peak years. If you want to play you will need to download BandData.xml. Save as an XML file to same directory as the script, which I’ll show you in a moment. Try not to peek too much at the contents. This is the structure.

My quiz is a PowerShell script that processes the data in the XML document. It will display a list of band members, without the recognizable lead and multiple choice of possible bands. After answering the questions you will be judged, I mean graded.

Let’s look at a few key points of the script.

First, I need to load the XML document.

The [XML] type accelerator will create an XML document. When you have an XML document in PowerShell, each node can be treated like a property so it is very easy to navigate or get values, like a list of all the band names.

The script then selects a random number of band entries from the XML document. These will be the basis of the quiz. For each item I create a list of band choices and band members that will be displayed. You’ll also noticed that I initialize some counters with the $script prefix.

Here’s why. I am using a scriptblock, defined as $promptblock, to display each question and keep track of correct answers. The scriptblock runs in a new scope, or container. That means when it tries to do something with a variable like $Q it first looks in the current scope for that item. If it finds it, it uses it. Otherwise PowerShell searches up the scope hierarchy to the parent scope looking for the item. But here’s what trips people up. If you are only reading, like I am, for things like the $bandhash object, PowerShell will happily find it in the parent scope and display it. But when I try to modify a variable like $Q or $i it can only modify it in the current scope. But I need to use those variables outside of the scriptblock scope, so I preface the variable with $Script: to indicate the scope level for those variables. The general rule is to not reference out-of-scope variables, but since I’m using $script: I’m telling PowerShell I know what I’m doing.

After running through all the questions, the script can calculate how many correct answers you had and present a score card. I decided to use a Switch statement to assist.

Normally in a Switch you would use a simple value. But you can also use PowerShell expressions. In my Switch statement, if the value of $Correct is >= 90, then I assign a certain value to $quip. When using expressions, use $_. Remember that Switch will process every matching expression and since I don’t want that, I’m using the Break keyword so PowerShell knows not to keep checking the other possibilities.

When you run the quiz, you will get an item like this:
bandquiz-1

The display is from the prompt scriptblock. If you need a little help, enter 0 which re-displays the question this time with the (hopefully) more recognizable lead.

bandquiz-2

And the final snarky commentary on your rock knowledge.
bandquiz-3

Because I am of a certain age, the contents of my band data xml file might be slightly skewed. If you were born after 1985 you might have some problems.

I think XML files scare some IT Pros but they really aren’t that difficult to work with once you understand some basics. In fact, I’ll be coming back to my band xml file in future posts. In the mean time, party on and let me know if you have any questions about my quiz script.

Friday Fun: A Random PowerShell Console

crayonsThis week I thought we’d have a little fun with the PowerShell console and maybe pick up a few scripting techniques along the way. Today I have a function that changes the foreground and background colors of your PowerShell console to random values. But because you might want to go back to your original settings without completing restarting PowerShell the function allows you to reset to your original values. Oh, and it also supports -Whatif. Here’s what I came up with.

The function will not work properly in the PowerShell ISE so I’ve included some code at the beginning to see if it is running in the ISE. If so, the command displays a warning and bails out. This is a scenario where using Return is completely acceptable as I want to return out of the pipeline without doing anything. I could have used a command like this: Return “This command only works in the PowerShell console.” but that would have written a string object to the pipeline and I don’t want anything to go to the pipeline. Plus, I prefer to use Write-Warning for messages like this.

When you run the command, it tests for the existence of some variables, $savedfg and $savedbg, that are defined in the global scope. You’ll notice the use of the global: prefix. If they are not defined, then the assumption is that this is the first time the command has been run and the variables will be defined with the current values of the $host.ui.rawui.foregroundcolor and $host.ui.rawui.backgroundcolor values. Later, if you use -Reset, the command will use these values to restore your original settings.

Otherwise, the command gets a random color for the System.ConsoleColor enumeration for the background and then another random color for the foreground, that is different than the randomly selected background color.

When you look at the code, you will see that I am specifying in the cmdletbinding attribute that the function supports ShouldProcess. That could also be written [cmdletbinding(SupportsShouldProcess=$True)] but that seems redundant to me. Anyway, the command to make the change, $host.ui.rawui.backgroundcolor= $bg, by itself doesn’t know anything about ShouldProcess and -WhatIf. But I can add my own code using an If statement.

The value for the ShouldProcess() method is the text you see as part of the “…performing operation on target…” message. The text is the target.
set-randomconsol-whatif

All I’ve done is define a variable, $msg, to make the line of code easier to read. As you can see, it is not that difficult to add your own support for -WhatIf. And now, if you get a little bored, mix it up for a fresh perspective. I’ve even included an alias, src, in case you have to type in a console where you can’t see what you’re typing.

Have a terrific weekend.