PowerShell Function to Determine the Hyper-V Host for a VM

This week, I thought I would share a PowerShell function that I wrote to determine what Hyper-V host server a VM (virtual machine) resides on. In this scenario, you have no idea which Hyper-V host a VM resides on.

 1#Requires -Version 3.0
 2function Get-MrVmHost {
 3
 4<#
 5.SYNOPSIS
 6    Determines the HyperV host virtualization server for the specified virtual machines.
 7
 8.DESCRIPTION
 9    Get-MrVmHost is an advanced function for determining the HyperV host virtualiztion server for one
10    or more VMs (virtual machines).
11
12.PARAMETER ComputerName
13    The name of the VM (virtual machine) to determine the HyperV host for.
14
15.PARAMETER Credential
16    Specifies a user account that has permission to perform this action. The default is the current user.
17
18    Type a user name, such as User01 or Domain01\User01. Or, enter a PSCredential object, such as one generated by the
19    Get-Credential cmdlet. If you type a user name, this cmdlet prompts you for a password.
20
21.EXAMPLE
22     Get-MrVmHost -ComputerName Server01, Server02, Server03
23
24.EXAMPLE
25     Get-MrVmHost -ComputerName Server01, Server02, Server03 -Credential (Get-Credential)
26
27.INPUTS
28    None
29
30.OUTPUTS
31    PSCustomObject
32
33.NOTES
34    Author:  Mike F Robbins
35    Website: http://mikefrobbins.com
36    Twitter: @mikefrobbins
37#>
38
39    [CmdletBinding()]
40    param (
41        [Parameter(Mandatory)]
42        [Alias('VMName')]
43        [string[]]$ComputerName,
44
45        [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty
46    )
47
48    $Params = @{
49        ComputerName = $ComputerName
50        ScriptBlock = {Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters'}
51        ErrorAction = 'SilentlyContinue'
52        ErrorVariable = 'Problem'
53    }
54
55    if ($PSBoundParameters.Credential) {
56        $Params.Credential = $Credential
57    }
58
59    Invoke-Command @Params |
60    Select-Object -Property VirtualMachineName, HostName
61
62    foreach ($p in $Problem) {
63        if ($p.origininfo.pscomputername) {
64            Write-Warning -Message "Unable to read registry key on $($p.origininfo.pscomputername)"
65        }
66        elseif ($p.targetobject) {
67            Write-Warning -Message "Unable to connect to $($p.targetobject)"
68        }
69    }
70
71}

First off, let me say that this function is written a bit unorthodox.

Typically you'll see functions written where each item in the ComputerName array is iterated through one at a time. Since this function uses the PowerShell remoting Invoke-Command cmdlet, it's able to perform the task in parallel so why would anyone want to constrain it to only checking one computer at a time? Most commonly, this is done for error handling to determine if a computer is unreachable, if the credentials are invalid, and if the command generates an error such as the registry key not existing.

1Get-MrVmHost -ComputerName mr101, doesnotexist, mr102 -Credential $Cred

get-mrvmhost1a.png

I started out first by using the built-in Error variable, clearing it and then iterating through it if any errors occurred. I decided that wasn't necessarily a good idea since something else could potentially pollute the built-in variable so I decided to specify my own variable by using the ErrorVariable parameter. The function uses the ErrorAction parameter with the SilentlyContinue value. Using that particular option silences the interactive errors but still populates the variable that's specified with ErrorVariable so I'm able to iterate through the errors and display warnings for systems whose results weren't returned due to some sort of error.

I thought this solution was unique and I'm interested in knowing what you think about it.

The function shown in this blog article can be downloaded from my PowerShell repository on GitHub.

µ