Get The List of All VMs in Hyper-V Cluster and Their Virtual Hard Disks

4 Min. Read

Updated – 30/01/2024 – The tool was updated to include the VLAN Access ID that is set on the network adapter for each VM in the Hyper-V Cluster.

Updated – 29/09/2023 – The tool was updated to include the disk identifier for each VM/VHDX in the Hyper-V Cluster.

Updated – 06/03/2023 – The tool was updated to include memory, CPU, and network IP addresses for each VM in the Hyper-V Cluster.

In this article, we will share with you how to get the list of all VMs in the Hyper-V Cluster and their Virtual Hard Disks with PowerShell.

Introduction

A while ago, we published a PowerShell script that will query System Center Virtual Machine Manager (SCVMM) to get all Virtual Machines including their Virtual Hard Disks, then it will calculate the size and percentage used for each VHD(X), and finally send you a nicely formatted HTML report. You can read all about it here.

In this blog post, we will share with you how to get the same report in comma-separated value (CSV) format and without SCVMM.

This comes in handy when working with a large Hyper-V cluster with many VMs, and you want to know the type of each virtual hard disk attached to every VM including their footprint size on the disk, and the remaining disk space so you know before the VM runs out of disk space.

Prerequisites

To run the function below successfully, you should note the following points:

1) You need to have Failover Cluster Module for Windows PowerShell installed on your machine:

Install-WindowsFeature -Name RSAT-Clustering-PowerShell

2) You need to have Hyper-V Module for Windows PowerShell installed on your machine:

Install-WindowsFeature -Name Hyper-V-PowerShell

3) Make sure to run (execute) the entire script first before you run it against your Cluster because this is a PowerShell function.

If you are working interactively in the console then the entire function can be copied and pasted into that session, then it will be available for the duration of that session.

I find this easier to do via the PowerShell ISE or Visual Studio Code than the standard PowerShell console.

So, you need to copy the function into the script pane, then click the Green Run Script or hit the F5 button. The function will be available for use and if using the ISE will appear interactively when you start typing the name as shown in the figure below:

Run PowerShell Function
Run PowerShell Function

Now, if the function below is something that you wish to use regularly in your interactive PowerShell sessions, then you can place it in your PowerShell Profile and it will be available every time you open your PowerShell console.

Learn more about PowerShell profiles and how to create one. Once you have created a PowerShell profile, place the function below in your profile and save it. Now every time you open your PowerShell console, the function will be available to use.

Another option is to store the function in a module. Using a PowerShell module is a more advanced significantly more structured and powerful method.

4) Last, you can run the function as follows:

 Get-VMVHDs -ClusterName "HyperV-Cluster-Name" -Verbose

Get The List of All VMs in a Hyper-V Cluster

Here is the PowerShell function that will do the job for you:

Function Get-VMVHDs {

    <#
       .Synopsis
           A script used to find all VHD(X) files for all VMs in a Hyper-V Cluster
        
       .DESCRIPTION
           A function used to find all VHD(X) files for all VMs in a Hyper-V Cluster,
           including the type of each virtual hard disk attached to every VM with their footprint size on disk,
           and the remaining disk space, so you know before the VM runs out of disk space.
           Finally, it will export the report into a CSV file.
           The report will also include the IP addresses, virtual memory and virtual CPU for each VM.
                
       .Notes
           Created   : 03-12-2018
           Updated   : 19-02-2024
           Version   : 3.3
           OS        : Windows Server 2016, 2019, 2022, 2025 Hyper-V or later
           Author    : Charbel Nemnom
           Twitter   : @CharbelNemnom
           Blog      : https://charbelnemnom.com
           Disclaimer: This script is provided "AS IS" with no warranties.
        
       .EXAMPLE
           . .\Get-VMVHDs.ps1
           Get-VMVHDs -Cluster "Cluster-Name"
    #>   
        
    [CmdletBinding(SupportsShouldProcess = $true)]
    Param(
        [string]$ClusterName
    )
        
    Get-ClusterGroup -Cluster $ClusterName | ? { $_.GroupType -eq 'VirtualMachine' } | Get-VM | ForEach-Object {
        $vhd = Get-VHD -ComputerName $_.ComputerName -VmId $_.VmId
        $networkAdapter = Get-VMNetworkAdapter -VM $_
    
        $vhd | Add-Member -NotePropertyName "Name" -NotePropertyValue $_.Name
        $vhd | Add-Member -NotePropertyName "ProcessorCount" -NotePropertyValue $_.ProcessorCount
        $vhd | Add-Member -NotePropertyName "MemoryStartup" -NotePropertyValue $_.MemoryStartup
        $vhd | Add-Member -NotePropertyName "NetworkAdapters" -NotePropertyValue $networkAdapter.IPAddresses
        $vhd | Add-Member -NotePropertyName "AccessVlanId" -NotePropertyValue ($networkAdapter | Get-VMNetworkAdapterVlan).AccessVlanId
        $vhd
    } | Select-Object @{label = 'VM Name'; expression = { $_.Name } }, @{label = 'vCPU'; expression = { $_.ProcessorCount } }, `
    @{label = 'vMem (GB)'; expression = { $_.MemoryStartup / 1gb –as [int] } }, `
    @{label = 'IP Addresses'; expression = { $_.NetworkAdapters } }, @{label = 'Host Name'; expression = { $_.ComputerName } }, `
    @{label = 'VLAN Id'; expression = { $_.AccessVlanId } }, Path, VhdFormat, VhdType, `
    @{label = 'Size On Physical Disk (GB)'; expression = { $_.FileSize / 1gb –as [int] } }, `
    @{label = 'Max Disk Size (GB)'; expression = { $_.Size / 1gb –as [int] } }, `
    @{label = 'Remaining Space (GB)'; expression = { ($_.Size / 1gb - $_.FileSize / 1gb) –as [int] } }, `
    @{label = 'Disk Identifier'; expression = { $_.DiskIdentifier } } `
    | Export-Csv -Path "C:\$($ClusterName)-VMReport.csv" -NoTypeInformation -Force
    
    Write-Verbose "The VM report is exported to C:\$($ClusterName)-VMReport.csv"
}

And here is the final report in CSV format:

List of All VMs in Hyper-V Cluster and Their Virtual Hard Disks
List of All VMs in Hyper-V Cluster and Their Virtual Hard Disks

The report will also include the VLAN Access ID that is set on the network adapter for each VM in the Hyper-V Cluster.

This is version 3.3, do you want additional features? Please feel free to leave a comment below.

Make sure to check my recent Windows Server Hyper-V Cookbook for in-depth details about Hyper-V!

Enjoy :)

__
Thank you for reading my blog.

If you have any questions or feedback, please leave a comment.

-Charbel Nemnom-

Previous

How To Be an MVP In Life Not Only In Technology #MVPBuzz #MVPInLife

How To Monitor Azure File Sync #AzureFiles #AzureMonitor #AFS

Next

41 thoughts on “Get The List of All VMs in Hyper-V Cluster and Their Virtual Hard Disks”

Leave a comment...

  1. Hello Krasimir, Thank you so much for your kind words and for taking the time to share your feedback. I’m thrilled to hear that you found the script useful!
    Adding additional fields like OS version and replication settings is a fantastic idea and could make the report even more informative.
    Below, I’ve included some guidance on how you can enhance the script to include these fields:

    1. Add the OS Version:
    You can use the Get-VM cmdlet to retrieve the operating system information. Add the following line within the `ForEach-Object` loop:
    $osVersion = $_.OperatingSystem $vhd | Add-Member -NotePropertyName "OSVersion" -NotePropertyValue $osVersion
    Then, include a new field in the Select-Object block like this:
    @{label = 'OS Version'; expression = { $_.OSVersion } }

    2. Add Replica Enabled/Disabled:
    You can use the Get-VMReplication cmdlet. Add this within the `ForEach-Object` loop:
    $replicationState = Get-VMReplication -VMName $_.Name | Select-Object -ExpandProperty ReplicationMode $vhd | Add-Member -NotePropertyName "ReplicaState" -NotePropertyValue $replicationState
    Then, add a new column in the Select-Object block like this:
    @{label = 'Replica State'; expression = { $_.ReplicaState } }

    Hope it helps! Thank you once again for your suggestion.
    Best,
    -Charbel

Let us know what you think, or ask a question...