Using Alternate Credentials with WMI and PowerShell [Hyper-V]

The other day I was reading a post on Tore Lervik’s site and noticed that he had written some PowerShell scripts that would allow you to connect to a remote server using different user credentials than the ones you are logged in with.  This is something that I need to do quite often – and I have been doing it by just starting PowerShell using “runas” – but this approach is a heck of a lot more elegant.

It works by using a new command that was introduced in PowerShell 2.0: Get-Credential.  When you issue this command you will see a Windows credential dialog, like this:

image

You can then take the object returned by Get-Credential and pass it into Get-WMIObject using the –Credential parameter.

While this is quite useful – I have found that it has a couple of limitations to be aware of:

  1. You need to pass the credential object every time you use Get-WMIObject.  If you have a simple script that only calls Get-WMIObject once or twice this is not a big deal; but it can get really annoying really fast if you are getting a lot of WMI objects.
  2. PowerShell will object if you try to use alternative credentials and you are connecting to the local computer (as opposed to connecting over the network to a remote computer).  This means that you have to wrap every Get-WMIObject call in some logic to check if you are connecting to the local computer or not (at this point refer to my first issue – this becomes a real pain if you are having to do it a lot).

To try this out I decided to take my virtual machine inventory script from last week and modify it to take alternative credentials.  In order to handle the issue of alternate credentials not working for the local computer – I put in a prompt that asks if you want to use alternate credentials or not:

 # Prompt for the Hyper-V Server to use
 $HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
  
 # Setup parameters for prompt to ask if the user wants to use alternative credentials
 $message = "Do you want to use alternative user credentials?"
 $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Use alternative user credentials."
 $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Use your current user credentials."
 $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
  
 # Ask the user if they want to use alternative credentials
 $result = $host.ui.PromptForChoice($null, $message, $options, 0) 
  
 switch ($result)
     {
         0 {# Prompt for the user credentials to use
            $wmiCredentials = Get-Credential -credential $null
  
            # Get all guest KVP data objects on the server in question, using the credentials provided
            $Kvps = gwmi -namespace root\virtualization Msvm_KvpExchangeComponent -computername $HyperVServer -Credential $wmiCredentials}
            
         1 {# Get all guest KVP data objects on the server in question
            $Kvps = gwmi -namespace root\virtualization Msvm_KvpExchangeComponent -computername $HyperVServer}
     }
  
 # Create an empty hashtable
 $table = @{}
  
 # Go over each of the guest KVP data objects
 foreach ($Kvp in [array] $Kvps) 
   {
    # Get the OSName value out of the guest KVP data
    $xml = [xml]($Kvp.GuestIntrinsicExchangeItems | ? {$_ -match "OSName"})
    $entry = $xml.Instance.Property | ?{$_.Name -eq "Data"}
  
    # Filter out unknown operating systems
    if ($entry.Value) {$value = $entry.Value} else {$value = "Unknown"}
  
    # Count up the values and store it in a hashtable
    if ($table.ContainsKey($value)) 
       {$table[$value] = $table[$value] + 1 }
    else
       {$table[$value] = 1}
    }
  
 # Display the results in a nicely formated and sorted manner
 $table.GetEnumerator() | Sort-Object Name | Format-Table -Autosize

 

I have also attached a copy of this script.

Cheers,
Ben

WhatIsRunning.zip