free html hit counter
Posted on: Tuesday, February 13, 2007 by Rajiv Popat

Reading XML Files with PowerShell (Monad)

A couple of months ago I had to make a difficult choice. A choice between Vista and Powershell (I still need time getting used to this name:)). Vista had officially RTM'ed and Powershell for Vista wasn't available. It was a difficult choice - wait on XP/2003 and continue to use Powershell or Move to Vista and wait for Powershell to become Vista Ready. I decided to move to Vista.

Recently, after about a couple of months, exactly as promised by Jeffrey Snover, the Moand team has Vista'ed the Powershell Installer and that means I can have both Vista and Powershell now. To add to that, I can totally continue to Skin Powershell and make it look beautiful, just like my Vista. And that's very important! Right? :)

I've been playing a lot with Powershell and now I think it's time for me, to put it to some real use, in project deployments on QA / Production.

One of the problems I always had while writing anything about PowerShell is that there are just too many good things to talk about in there and almost anything that could have been written about, has been written by someone else. That's one of the reasons (excuses? :)) why I haven't been writing a lot about it. For now, I'm just going to start by talking a little bit about XML and how you can read XML files in Powershell.

Let's just assume that we have the following simple XML file which lets me run various Uninstall and Install SQL scripts on the database depending on the Application version that I am pushing to the server.

<version name="1.0.0">
<script UnInstallScript="uninstall1-1.sql" InstallScript="install1-1.sql"/>
<script UnInstallScript="uninstall1-2.sql" InstallScript="install1-2.sql"/>
<version name="2.0.0">
<script UnInstallScript="uninstall2-1.sql" InstallScript="install2-1.sql"/>
<script UnInstallScript="uninstall2-2.sql" InstallScript="install2-2.sql"/>

Typically, creating a database project, a command file and then a custom Console application in C# that reads this XML file and fires corresponding SQL Scripts might work, but it takes some time. Let's use Powershell to see how easy it is to read this XML.

Let's start with simplest approach first. XML support is pretty neatly baked into Powershell. So assuming this file was called Mockfile.xml, I can just create a XmlDocument object using the following command at my Powershell window:

PS E:\> [xml] $MyXmlDocument = Get-Content MockFile.xml

That's it. The XMLDocument is now available in this instance variable. Let's take a look at what the variable $MyXmlDocuent contains:

PS E:\> Get-Variable MyXmlDocument

NameValue Value
---- -----
MyXmlDocument #document

PS E:\> $MyXmlDocument


We're all set to read from the document now. Let's try to get to various nodes on the XML File. Because, everything returned by Powershell is an object, to get the value of the Node all I Need to do is access the attribute within the object. For Example, to get all values of version nodes inside the the DBScripts Node and store it inside a separate variable I could just do:

PS E:\> $MyVersions = $MyXmlDocument.DBScripts
PS E:\> $MyVersions

{1.0.0, 2.0.0}

Notice how I access the DBScripts Node and assign all version nodes inside the root node to a different variable. To see value value of $MyVersions variable that I just created I just type it in and Powershell confirms that it now has nodes pertaining to both versions in this newly created variable.

Now let's assume I need to reach the version node with the Name 2.0.0. and access all the script files in there. To do this let's quickly take a look at the version node collection which was returned by the above command:

PS E:\> $MyVersions.version

name script
---- ------
1.0.0 {script, script}
2.0.0 {script, script}

Now to directly access the version node where the name is 2.0.0, let's use PowerShell filtering and let's pipe the output of version nodes to the the Where-Object commandlet:

PS E:\> $SecondVersion = $MyVersions.version | where-object {$ -match '2.0.0'}
PS E:\> $SecondVersion

name script
---- ------
2.0.0 {script, script}

PS E:\> $SecondVersion.script

UnInstallScript InstallScript
-------------- -------------
uninstall2-1.sql install2-1.sql
uninstall2-2.sql install2-2.sql

Once I've piped the output of all my version attribute to the where-object commandlet and assigned the final output to another variable I inspect the attribute the variable contains by typing $SecondVersion and then peek into it's script collection by doing $SecondVersion.script. If this was a deployment script, the above command would have given me all the scripts I need to run to install the version 2.0.0 of my application. I could easily convert this to a Powershell script where the version number comes in a parameter. The script can go ahead and figure out which SQL script it needs to run and then can run them. However, the focus of this Post is to concentrate of reading XML files, so let's try to do everything we just did using just two lines of code:

PS E:\> [xml] $MyXmlDocument = Get-Content MockFile.xml
PS E:\> ($MyXmlDocument.DBScripts.version | where-object {$ -match '2.0.0'}).script

UnInstallScript InstallScript
-------------- -------------
uninstall2-1.sql install2-1.sql
uninstall2-2.sql install2-2.sql

Sweet! Don't you think? :) Wait, there's more! You could actually do this using a single command at the command prompt if you wanted to:

PS E:\> (([xml] (Get-Content MockFile.xml)).DBScripts.version | Where-Object {$ -match '2.0.0'}).script

UnInstallScript Installscript
-------------- -------------
uninstall2-1.sql install2-1.sql
uninstall2-2.sql install2-2.sql

And then of course you could iterate through this list by using the ForEach-Object commandlet if you wanted to:

PS E:\> (([xml] (Get-Content MockFile.xml)).DBScripts.version | Where-Object {$ -match '2.0.0'}).script | ForEach-
Object { "Here I Could Run : " + $_.InstallScript }

Here I Could Run : install2-1.sql
Here I Could Run : install2-2.sql

PS E:\>

Or you could just access a particular element by it's zero based index:

PS E:\> (([xml] (Get-Content MockFile.xml)).DBScripts.version | Where-Object {$ -match '2.0.0'}).script[1]

UnInstallScript InstallScript
-------------- -------------
uninstall2-2.sql install2-2.sql

PS E:\>

And did I mention that two code snippets above are just one line commands? You could of-course turn this into a script depending on what you are trying to do. But what if you were not very comfortable with this approach and wanted to use familiar XPath to access XML nodes? Don't run away! You can do that too. This MSDN article shows you how.

Here's wishing you Happy-XML with Powershell!

posted on Tuesday, February 13, 2007 1:21:20 PM UTC by Rajiv Popat  #    Comments [0]
Posted on: Tuesday, November 21, 2006 by Rajiv Popat

Skin PowerShell (Monad) to Customize it's Look and Feel

If you feel that typing "Start / Run / Notepad.exe" is faster than clicking on the Notepad icon or if you spend more than 15 minutes on the Command Prompt everyday you probably know a lot about Monad / Powershell by now. I fell in love with this one the day I saw it in it's Pre-Release versions. Of course I didn't see the light instantly, but it grew on me - slowly - over time.

I won't waste a lot of your time posting about the things that can make you fall in love with this tool - for example - the fact that it returns objects instead of strings, or the fact that it could change the world (No kidding!), or the fact that you can access .Net DLLs from within PowerShell. I won't even state the fact (ok, personal opinion :)) for example, that it's way cooler than any Linux console I've ever worked with.

I could write tons of posts on PowerShell because I've been hooked on to it, but then in all probabilities, if you're here (and are still reading this), you're hooked on to it too and you probably know all that stuff already. And if you aren't hooked and you're just the curious type, go ahead, click some of those links I mentioned above and read a little. The learning curve will be a little steep at first but I guarantee that you'll "see the light" soon. Honest!

I can go on and on about Powershell basics, for a very long time. But then, I've been busy, and now I realize that I'm a little late on posting about that. People everywhere have been doing an awesome job at writing about PowerShell and most of the basic stuff anyone wanted to find out about, is already out there.

People have been building Utility Scripts, Powershell Analyzers and some are even developing Sharepoint Providers for PowerShell (neat idea!). But being the stupid guy that I am, for the past couple of months that I've been playing around with PowerShell, there's just one thing that has been pinching me:

"Okay, All this is cool and I get-it, but on a slightly different note, How do I Skin this thing and make it look nice so that I can show-it-off to everyone else while I am working inside a Powerhsell window?"

And then there were others who were asking similar questions. On the Powershell team blog there are remarks like:

"Absolutely no improvement over the ugly looking command window. With the name change if someone in your group maybe can push for tabbed Power shell?"

And the reply is pretty much a shout to the 3rd Parties to build-this-thing that lets you Skin PowerShell:

"We share your pain. We Really do. This just fell into the 'to ship is to choose' category. We designed it so that 3rd parties could do this. (3rd parties - do you see how many people would be interested in a great PowerShell Host?)!"

That's how most of us are - aren't we? We just want to see the Dancing Banana in our Development IDEs! What the IDE or the Product does is just so irrelevant! If it can't show the dancing banana we just aren't happy! :)

And I've been looking for this thing, because this-thing-that-lets-me-customize-PowerShell-Look-and-Feel is something that "has to be developed" by someone! I mean, come on! People have written IDEs for this thing! Somebody must have written something that let's me skin Powershell!

Since Google started crawling this site I'm seeing a jump in visitor counts from around the world which is kind-of interesting and fun. So, If you've landed on this page from Google just because you were looking for a similar answer you're in luck! Yes, it's possible to skin PowerShell and make it look like the way you want it to look like.

Turns out, there is, in-fact an Uber-cool free and open source application that let's you do just that. It's called Console and even though I've used console before, for quite some time, I didn't quite figure out that Console is NOT just a Command Prompt replacement. Console works with Virtually anything - CMD.EXE, Cygwin and a host of other Shells. So basically, there's no reason what-so-ever why it shouldn't work with Monad / Powershell.

Since I like the Mac look so much - Let's make Powershell have some background-transparency so that we can see my Mac'ish wall-paper behind it. Long story short, Let's make Powershell look something like this:

The steps are pretty simple and straight-forward:

  1. Get Console.exe (Don't get the 2.0 "Demo" version because that's WIP and doesn't do much. Get the stable release instead.)
  2. Go to Control Panel / System / Advanced Tab / Environment Variables and create a new variable called "COMSPEC". Set it's Value to "Powershell.exe"  (Assuming you have PowerShell installed already. You can also do this from Console Configuration Files, but this is the easy way).

That's it. You're Done. Start Your Console and it starts up by skinning Powershell instead of the usual command prompt. You should now be able to skin it and theme it using all the rich options Console provides in it's configuration files. And if this isn't enough, go ahead, see if you can have The Dancing Banana in PowerShell! :)

posted on Tuesday, November 21, 2006 11:23:29 AM UTC by Rajiv Popat  #    Comments [2]