Listing your XML product keys from MSDN – Part 2

In the last post we we’re playing around with how to extract a Product Key from an MSDN exported XML document. We’ll take this a step further today and see if we turn it into something a little more useful.

Building on the previous script, we want to list the products that match our search criteria and then select the one we want the Product Key for. As well as displaying this information on screen, it would be useful if the key could be put into the clipboard, ready for use.

[xml]$msdn = Get-Content MSDN-Sample-ProdKeys.xml
$msdn.Your_Product_Keys.Product_Key.Count
# Initialise the Hash Table
$lookup = @{}

$product = read-host “what product are you using?”
$i = 0
foreach ($item in $msdn.Your_Product_Keys.Product_Key)
{
if ($item.name -like “*$product*”)
{
$lookup = $lookup + @{$i=$item.name}
write-host $i “:” $item.name
}
$i ++
}
$ID = read-host “Please enter the number of the product you want”
$msdn.Your_Product_Keys.Product_Key[$ID].Key | clip
write-host ($msdn.Your_Product_Keys.Product_Key[$ID].Name) “(“($msdn.Your_Product_Keys.Product_Key[$ID].Key)”)” -foregroundcolor “cyan”

The first thing, was to change where we increment the $i variable. I found during testing that we were returning the incorrect number to retrieve the details from the XML document. Incrementing at the end of the foreach corrected this oversight. We’ve also removed displaying the Product Key until the end of the script, to make things neater.

The main new feature has been to use an associative array, or hash table, to store our ID number and Product Name. The ID number identifies which node in the XML document our product is stored in.

Once, the hash table has been built with a list of potential products, the user is prompted to enter the ID number of the specific product. The ID is then used to lookup the Product’s Name and Key form the XML document, which is then displayed on screen and put in the clipboard buffer by using the clip.exe utility available on Windows 2003 Server and Vista.

show-msdnkey.ps1 Part 2

Listing your XML product keys from MSDN

I’m lucky enough to have an MSDN subscription at work. If you’re familiar with this service, you will know that when you request a Product Key, there is an option to download it in XML format.
Sample MSDN Product Key Export to XML

One of my favourite things with PowerShell, is how it handles XML.


[xml]$msdn = Get-Content MSDN-Sample-ProdKeys.xml
$msdn.Your_Product_Keys.Product_Key.Count

$product = read-host “what product are you using?”
$i = 0
foreach ($item in $msdn.Your_Product_Keys.Product_Key)
{
$i ++
if ($item.name -like “*$product*”)
{
write-host $i “:” $item.name “(” $item.key “)”
}
}

A quick look through the code shows how simple it really is. we define $msdn as an XML type and get the contents of our MSDN exported keys. As a quick sanity check we output how many nodes are under Product_Key.

We then prompt the user for some guidance on what product is of interest. Looping through the nodes any item that is like our supplied product is returned, along with the node number, and product key.
show-msdnkey.ps1

As you can see in the example above, the first time the script is run we provided no input, which returned us all the contents of the file. The second time we searched on the term xp.

If you’re wondering why we kept track of the node number, we’ll expand on this example next time to see if we can improve on the script to make it a bit more useful.

PowerShell and XML

By far, for me, the most useful feature I’ve found in PowerShell is how easy it is to manipulate XML documents. I’ve written VBScripts in the past that extracted data from XML, performed a task, and then updated the XML document when it was done.

Now, personally I found this quite a tricky task. Let me give you an example, we have the following XML document:


A
B


The aim is to extract the PartitionType for the W2K3 package.

In PowerShell, this is really easy:

[xml]$payload = get-content -path d:\coding\ps\payload.xml
foreach ($package in $payload.section.package)
{
if ($package.id -eq “w2k3″)
{
write-host $package.partitiontype
}
}

As you can see it’s easy to navigate to attributes or nodes within the XML document. So what happens if you want to add another package?

$newPkg = $payload.CreateElement(“Package”)
$newPkg.SetAttribute(“ID”, “Vista”)

Now the only really hassle I’ve experienced when trying to add new nodes, is when it’s the first node at that level. Adrian Milliner over at Soapy Frog provided a work around for this (bug?) in the comments of the Microsoft PowerShell Team blog.

With this in mind I use the following the syntax to add the node:

$payload["section"].AppendChild($newPkg)

Now we have the new package node, we still need to add the child node under it for the partitiontype.

$partition = $payload.CreateElement(“partitiontype”)
$partition.set_InnerText(“C”)

$nodecount = $payload.section.package.count
if ($nodecount -ne $null)
{
$I = ($nodecount -1)
$payload.section.package[$I].AppendChild($partition)
}
$payload.save(“D:\coding\ps\payload.xml”)

So now we’ve covered some basic XML manipulations. Our end result in this example woud be:


A
B C


If we take some of our earlier AD examples you can see how easy it would be to add in nodes for ou’s, groups, and accounts and it suddenly looks a whole lot easier to build an Active Directory ;)

Of course one application could be to write some script to read your live AD structure, save it into an XML document, and then use it to build Active Directory for a test environment. Though this would take some effort it has some excellent portability advantages. If you’re careful on your coding you can write your scripts so that the domain name isn’t hard-coded.