Doubts and Powershell, Hyper-V KeyValue pairs and Hash tables.

I've said a number of times that I think technical people are rarely secure in their own abilities; that they have a demon on their shoulder who whispers "You're not really, that good" ... "They'll find you out one day". I was talking to a colleague this week who seems to be racked by such doubts, and saying that it's better to the one who doubts yourself, than have everyone else doubt you (echos of Kipling there).

I do get the odd moment of doubt about what I'm doing with PowerShell and Hyper-V.  So it was just fantastic to get a mail this morning saying that some work I'd done was used in one of the top scoring sessions at Tech-ed in the US this week. Hyper-V and Virtual Machine manager were generating a lot of excitement among customers throughout the event you can get a flavour of why in this  5 minute  video from the keynote. I'm getting ready to release the library of Hyper-V bits on Codeplex. I've found one thing which has broken by changes made since the beta, but with the next build to come out being the release I'm hoping that there are no new changes required. reg-KVP

One  area I have been looking at recently is "Key value pair  exchange". One of the integration components passes these pairs between the Parent Partition and the Child Partitions. The data lives in the registry under HKLM\Software\Microsoft\VirtualMachine - data going from the child partition is under Auto and data going to it is under Guest\parameters. It allows a Guest OS to know the name of the computer hosting it what that computer calls the VM where it is running, and it allows the Host OS to know the OS and Fully Qualified domain name being used in the Guest. The data is only available when the VM is running. The "KVP Component" WMI object has a "Guest Intrinsic Exchange Items" property. Does it return something simple like "ProcessorArchitecture-9" ? No... It returns a rather nasty block of XML like this for each one.

 <INSTANCE CLASSNAME="Msvm_KvpExchangeDataItem">   
  <PROPERTY NAME="Caption" PROPAGATED="true" TYPE="string"></PROPERTY>   
  <PROPERTY NAME="Data" TYPE="string"><VALUE>9</VALUE></PROPERTY>
   <PROPERTY NAME="Description" PROPAGATED="true" TYPE="string"></PROPERTY> 
  <PROPERTY NAME="ElementName" PROPAGATED="true" TYPE="string"></PROPERTY> 
  <PROPERTY NAME="Name" TYPE="string"><VALUE>ProcessorArchitecture</VALUE></PROPERTY>

  <PROPERTY NAME="Source" TYPE="uint16"><VALUE>2</VALUE></PROPERTY> 
</INSTANCE>

Fortunately I can get my data with just two long lines of PowerShell - for readability they are split over several lines, one gets the KVP component object and one processes the XML

 $KVPComponent=(Get-WmiObject -Namespace root\virtualization `
                             -query "select * from Msvm_KvpExchangeComponent 
                                     where systemName = '$($vm.name)'") 
$KVPComponent.GuestIntrinsicExchangeItems | 
      forEach -begin { $KVPObj = New-Object -TypeName System.Object } ` 
              -process {([xml]$_).SelectNodes("/INSTANCE/PROPERTY")  | 
                         forEach  -process {if ($_.name -eq "Name") {$propName=$_.value}; 
                                           if  ($_.name -eq "Data") {$Propdata=$_.value} } 
                                  -end {Add-Member -inputObject $KvpObj -MemberType NoteProperty `
                                        -Name $PropName -Value $PropData}} 
              -end {$KvpObj}  

 

This is the basis of a Get-VMKVP function, which I can use like this:

 PS C:\Users\administrator\Documents\WindowsPowerShell> choose-vm | get-vmkvp ID VM Name             State 

-- -------             ----- 

0 SEA-DC-01           Stopped 

1 HPC DC,DNS and DHCP Running 

2 JON WDS             Suspended 

3 HPC Compute Node 2  Stopped 

4 Core                Stopped 

5 HPC Head Node       Stopped Which one ?: 1 
FullyQualifiedDomainName : CCS-DC.CCSTEST.COM 

OSName                   : Windows Server (R) 2008 Standard 

OSVersion                : 6.0.6001 

CSDVersion               : Service Pack 1 

OSMajorVersion           : 6 

OSMinorVersion           : 0 

OSBuildNumber            : 6001 

OSPlatformId             : 2 

ServicePackMajor         : 1 

ServicePackMinor         : 0 

SuiteMask                : 272 

ProductType              : 2 

ProcessorArchitecture    : 9 

With the aid of the another WMI call - (Described on MSDN) I can ping the VM. If I store it's FQDN in $VmFQDN the line is

 Get-WmiObject -query "Select * from  Win32_PingStatus where Address='$VmFQDN' and ResolveAddressNames = True and recordRoute=1"

What I really wanted to do was to check the status code returned by the ping and the MSDN page gives me a list of codes. Now one could use a switch statement to output the right text for the code - in fact  Jeffrey Snover's most recent blog post does exactly that. But I showed before that I can do the same thing with a hash table so I have

 $PingStatusCode=@{0="Success" ; 11001="Buffer Too Small" ; 11002="Destination Net Unreachable" ;
                                    [quite a few more and finally]   11050="General Failure" } 

and when the time comes to return the status information I can use

 $PingStatusCode[[int]$_.statusCode]

I mentioned Jeffrey's post,  I'd be tempted to turn his code form

 $sku = $((gwmi win32_operatingsystem).OperatingSystemSKU) 
switch ($sku) 
{ etc } 

to  @{hash-table}[Value]   format.

Now the hash table is long, but I'm probably going to paste it into my code from MSDN and it is easier to change it to the format below than the format needed in a switch statement. The [index] construction isn't the prettiest ever either.  And remember although this is typeset as 26 lines this is actually a single line to PowerShell :-)

 @{ 0 ="Undefined";

1 ="Ultimate Edition";

2 ="Home Basic Edition";

3 ="Home Basic Premium Edition";

4 ="Enterprise Edition";

5 ="Home Basic N Edition";

6 ="Business Edition";

7 ="Standard Server Edition";

8 ="Datacenter Server Edition";

9 ="Small Business Server Edition";

10 ="Enterprise Server Edition";

11 ="Starter Edition";

12 ="Datacenter Server Core Edition";

13 ="Standard Server Core Edition";

14 ="Enterprise Server Core Edition";

15 ="Enterprise Server Edition for Itanium-Based Systems";

16 ="Business N Edition";

17 ="Web Server Edition";

18 ="Cluster Server Edition";

19 ="Home Server Edition";

20 ="Storage Express Server Edition";

21 ="Storage Standard Server Edition";

22 ="Storage Workgroup Server Edition";

23 ="Storage Enterprise Server Edition";

24 ="Server For Small Business Edition";

25 ="Small Business Server Premium Edition"}[[int]((gwmi win32_operatingsystem).OperatingSystemSKU)]

Hmm, From Self-doubt to thinking I can do PowerShell better than Jeffrey in one post... life's been a bit like that recently.

Technorati Tags: PowerShell