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
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.
µ