Save to My DOJO
Table of contents
I recently had a need to locate a specific VM in a cluster. Turns out, there’s no truly direct way to do it. Therefore, I have developed a simple script that will allow you to find one, many, or all VMs in a cluster.
This script isn’t entirely necessary. You can fairly easily retrieve all these VMs with the following:
Get-VM –Name VMNAME –ComputerName (Get-ClusterNode –Cluster CLUSTER)
That works, and works pretty well. But then, I came up with another need: I only wanted to look at highly available VMs. That changes things. You could do this:
Get-VM –ComputerName (Get-ClusterNode –Cluster CLUSTER) | where { $_.IsClustered –eq $true }
There’s nothing wrong with this, but it’s a bit much for regular use. Of course, the-powers-that-be in the PowerShell world would likely tell me to just stick that in a .ps1 and make sure it’s accessible. But it’s still less flexible than I would like. So, I started working on something more elegant. The more I worked on it, the more complicated it got. The end result is actually a one-liner, although I broke it out into multiple lines because legibility trumps cleverness in a saved script. The best part of this is that it’s pretty simple to use. You can just run Get-ClusterVM without any parameters from a cluster node and it will retrieve all the highly available VMs on the entire cluster. You can use the –VMName parameter to select one or more specific VMs. You can also use –Cluster to remotely target a cluster. Another nice thing about this is, in my unscientific testing, it seems to be a little quicker than the Get-VM run. I’m assuming that’s because once it gets to the point of querying for VMs, it queries for them with very specific parameters instead of using open-ended wildcards. There is a potential shorter path that would work for most situations. You could just query cluster groups, as the name is usually matched to the VM. However, it is entirely possible to have a VM name that is different from its cluster resource name, especially if you’re using VMM. The only guaranteed option they match on is the VmID. The complete script is below. It works on 2012 and above. Just save it as Get-ClusterVM.ps1 and execute from PowerShell. Use Get-Help to view the parameters.
<# .SYNOPSIS Retrieves clustered virtual machines. .DESCRIPTION Enumerates the virtual machine resources on a cluster and retrieves the related virtual machine object. If specific VM names are supplied, only those objects are retrieved. .PARAMETER VMName A string array that specifies the names of VMs to look for. .PARAMETER Cluster The cluster to scan for virtual machines. Accepts a string that contains the cluster or any node name. Accepts a Cluster object (from Get-Cluster). Accepts a VMHost object (from Get-VMHost). .OUTPUTS Microsoft.Virtualization.Powershell.VirtualMachine .EXAMPLE C:PS> .Get-ClusterVM Description ----------- Retrieves all VMs on the cluster that this computer is a member of. .EXAMPLE C:PS> .Get-ClusterVM svMail1 Description ----------- Retrieves the VM named "svMail1" on the cluster that this computer is a member of. .EXAMPLE C:PS> .Get-ClusterVM svMail1, svSQL1 hvcluster1 Description ----------- Retrieves the virtual machines named "svMail1" and "svSQL1" from the cluster named "hvcluster1" .EXAMPLE C:PS> .Get-ClusterVM -VMName svMail1, svSQL1 -Cluster hvcluster1 Description ----------- Exactly like the previous example, using named parameters. .LINKFree PowerShell Script for Hyper-V: Get-ClusterVM#> #requires -Version 3 #requires -Modules Hyper-V, FailoverClusters [CmdletBinding()] param( [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$true)] [Alias("Name", "VM")] [String[]]$VMName = @(), [Parameter(Position=1, ValueFromPipeline=$true, ValueFromPipelinebyPropertyName=$true)] [Alias("ComputerName", "ClusterName" , "HostName", "VMHost")] [PSObject]$Cluster = $env:COMPUTERNAME ) BEGIN {} PROCESS { Set-StrictMode -Version Latest # Convert input to a string switch( $Cluster.GetType().Name) { "Cluster" { $Cluster = $Cluster.Name } "VMHost" { $Cluster = $Cluster.Name } default { $Cluster = [String]$Cluster } } <# Legend for following script # 1. Retrieve a list of cluster resources of type "Virtual Machine" 2. Extract the computer name of the owner node and the VMId from 1. 3. Use each node and ID set from 2. as Get-VM parameters 4. Did the user specify one or more VMs? 4yes. Retrieve only those from 3. 4no. Allow all VMs to be retrieved from 3. 5. Leave the VMs retrieved in 4. in the pipeline #> Get-ClusterResource -Cluster $Cluster | where { $_.ResourceType -like "Virtual Machine" } | #1. select -Property OwnerNode, @{ Name ="VmID";Expression ={ (Get-ClusterParameter -InputObject $_ | where { $_.Name -eq "VmID" } | select -Property Value).Value } # 2. } | foreach { Get-VM -ID $_.VmID -ComputerName $_.OwnerNode } | # 3. Where-Object { if($VMName.Count -gt 0) # 4. { $VMName -contains $_.Name # 4yes. } else { 1 } # 4No. } # 5. } END {}
Not a DOJO Member yet?
Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!
5 thoughts on "Free PowerShell Script for Hyper-V: Get-ClusterVM"
Great job! Thanks Eric,
You have experienced on coding. Can you share me some books to learn?
Thank again
Are you looking to learn how to code or how to script? The lines are blurring, but they are not the same.
If scripting in PowerShell is what you’re after, I would start with Learn PowerShell in a Month of Lunches.
Great job! Thanks Eric,
You have experienced on coding. Can you share me some books to learn?
Thank again
Hi. Excelent script!
Is it possible to add IP Address (v4) information?
Thanks,
Paulo Gomes