PowerShell Hyper-V VM Health Check and Auto-Report Script

PowerShell Hyper-V VM Health Check and Auto-Report Script

PowerShell Tips Editor 5 min read
PowerShell Hyper-V VM Health Check and Auto-Report Script

Manual Hyper-V Checks Do Not Scale

Opening Hyper-V Manager to check VM states on three hosts is manageable. Doing it across fifteen hosts covering two hundred virtual machines is not — especially when you need consistent data about CPU pressure, memory demand, replication health, and checkpoint age. A PowerShell health check script queries every VM across all hosts in seconds, applies consistent rules, and produces an HTML dashboard that can be emailed or published to a shared drive. Run it on a schedule and you have continuous visibility without daily manual effort.

Quick Answer

Use Get-VM -ComputerName to collect VM objects from multiple hosts, check State, CPUUsage, MemoryDemand, and Get-VMCheckpoint for snapshot age, then pipe the results into a ConvertTo-Html report with color-coded rows.

Getting All VMs with Get-VM Across Multiple Hosts

The -ComputerName parameter of Hyper-V cmdlets accepts an array of host names. You get a flat list of VM objects, each stamped with a ComputerName property identifying which host it came from. The Hyper-V PowerShell module must be installed on the management machine, not just on the hosts.

# Hyper-V module required — install if missing
if (-not (Get-Module -ListAvailable -Name Hyper-V)) {
    Install-WindowsFeature -Name RSAT-Hyper-V-Tools -IncludeManagementTools
}

$hyperVHosts = @('HV01', 'HV02', 'HV03')

$allVMs = Get-VM -ComputerName $hyperVHosts -ErrorAction Stop

Write-Host "Found $($allVMs.Count) VMs across $($hyperVHosts.Count) hosts"
$allVMs | Group-Object ComputerName | Select-Object Name, Count
Found 47 VMs across 3 hosts

Name   Count
----   -----
HV01      18
HV02      16
HV03      13

Checking CPU and Memory Demand vs Assigned

Hyper-V VM objects expose CPUUsage (current percentage) and MemoryDemand vs MemoryAssigned when Dynamic Memory is enabled. Calculating demand-to-assigned ratio highlights VMs that are consistently pressured and need more memory or migration.

$vmMetrics = $allVMs | ForEach-Object {
    $memPct = if ($_.MemoryAssigned -gt 0) {
        [math]::Round(($_.MemoryDemand / $_.MemoryAssigned) * 100, 1)
    } else { 0 }

    [PSCustomObject]@{
        Host          = $_.ComputerName
        Name          = $_.Name
        State         = $_.State
        CPUPct        = $_.CPUUsage
        MemDemandGB   = [math]::Round($_.MemoryDemand / 1GB, 2)
        MemAssignedGB = [math]::Round($_.MemoryAssigned / 1GB, 2)
        MemPressurePct= $memPct
    }
}

# Flag high-pressure VMs
$vmMetrics | Where-Object { $_.MemPressurePct -gt 90 -or $_.CPUPct -gt 85 } |
    Format-Table -AutoSize

Detecting VMs with Old Checkpoints

Checkpoints (snapshots) consume disk space and can degrade VM storage performance over time. Flag any VM with a checkpoint older than 7 days as a warning, and older than 30 days as critical.

$checkpointWarnings = foreach ($vm in $allVMs) {
    $checkpoints = Get-VMCheckpoint -VMName $vm.Name -ComputerName $vm.ComputerName `
                    -ErrorAction SilentlyContinue
    foreach ($cp in $checkpoints) {
        $ageDays = ((Get-Date) - $cp.CreationTime).Days
        if ($ageDays -gt 7) {
            [PSCustomObject]@{
                Host        = $vm.ComputerName
                VM          = $vm.Name
                Checkpoint  = $cp.Name
                AgeDays     = $ageDays
                Severity    = if ($ageDays -gt 30) { 'Critical' } else { 'Warning' }
            }
        }
    }
}

$checkpointWarnings | Sort-Object AgeDays -Descending | Format-Table -AutoSize

Hyper-V Replication Health with Measure-VMReplication

Measure-VMReplication returns replication statistics for each VM with replication configured. Check the Health property — anything other than Normal warrants investigation.

$replStatus = foreach ($host in $hyperVHosts) {
    Measure-VMReplication -ComputerName $host -ErrorAction SilentlyContinue |
        Select-Object @{N='Host';E={$host}}, VMName, Health,
                      ReplicationState, LastReplicationTime,
                      AverageReplicationSize
}

$replStatus | Where-Object { $_.Health -ne 'Normal' } | Format-Table -AutoSize

Flagging VMs in Critical or Off States

VMs in Critical state indicate a resource problem or configuration error requiring immediate attention. VMs that are Off unexpectedly (i.e., not intentionally shut down) should also be surfaced. Cross-reference against an expected-state list if you maintain one; otherwise flag all non-Running, non-Saved VMs.

Generating an HTML Health Dashboard

Combine all the data collected above into a single HTML report with color-coded rows. This report can be emailed as an attachment or dropped to a web share for the operations team.

$reportRows = $vmMetrics | ForEach-Object {
    $severity = 'OK'
    if ($_.State -ne 'Running')            { $severity = 'Critical' }
    elseif ($_.CPUPct -gt 85)             { $severity = 'Warning' }
    elseif ($_.MemPressurePct -gt 90)     { $severity = 'Warning' }

    $_ | Add-Member -NotePropertyName Severity -NotePropertyValue $severity -PassThru
}

$css = '<style>
body{font-family:Arial;font-size:13px}
table{border-collapse:collapse;width:100%}
th,td{border:1px solid #ccc;padding:5px 8px}
tr.Critical{background:#ff4c4c;color:#fff}
tr.Warning{background:#fff3cd}
tr.OK{background:#d4edda}
</style>'

$reportRows |
    ConvertTo-Html -Head $css -Title 'Hyper-V VM Health Report' |
    ForEach-Object {
        $_ -replace '<tr><td>(Critical|Warning|OK)', '<tr class="$1"><td>$1'
    } |
    Out-File -FilePath 'C:\Reports\HyperV-Health.html' -Encoding UTF8

Write-Host "Report written to C:\Reports\HyperV-Health.html"

Common Errors

  • Hyper-V PowerShell module not installed on the management machine. The cmdlets are part of the RSAT Hyper-V Tools feature (RSAT-Hyper-V-Tools) on Windows Server and Hyper-V Module for Windows PowerShell on Windows 10/11. Use Install-WindowsFeature or Enable-WindowsOptionalFeature to add them.
  • Get-VM on a remote host requires CredSSP or Kerberos constrained delegation. Hyper-V cmdlets with -ComputerName use implicit remoting. If the management machine is not the Hyper-V host itself, double-hop authentication must be configured via CredSSP delegation or Kerberos constrained delegation in Active Directory.

Related Cmdlets / See Also

Wrapping Up

A scripted Hyper-V health check built on Get-VM, Get-VMCheckpoint, and Measure-VMReplication replaces hours of manual console work with a scheduled job that runs in minutes. Add the HTML report to a daily email digest and your operations team has consistent, objective visibility across the entire VM fleet.

Send-Item -To