Skip to main content

How to Get the Status of All Hyper-V VMs in Batch Script

Monitoring the status of virtual machines is a daily routine for Hyper-V administrators. Knowing which VMs are running, stopped, saved, or in an error state at a glance is essential for capacity planning, incident response, and ensuring that critical services are online. A quick status query replaces the need to open Hyper-V Manager and visually scan through potentially dozens of VMs.

In this guide, we will explore how to retrieve and display the status of all Hyper-V virtual machines from a Batch Script using PowerShell, from basic state summaries to comprehensive health dashboards.

Method 1: Quick Status Overview

The simplest query shows each VM's name, state, CPU usage, and memory allocation.

@echo off
setlocal

echo =============================================
echo HYPER-V VM STATUS
echo %date% %time:~0,8%
echo =============================================
echo.

powershell -NoProfile -Command ^
"Get-VM | Sort-Object State, Name | Format-Table Name, State, CPUUsage," ^
"@{Name='MemGB';Expression={[math]::Round($_.MemoryAssigned/1GB,1)}}," ^
"@{Name='Uptime';Expression={$_.Uptime.ToString('dd\.hh\:mm\:ss')}} -AutoSize"

pause

Sample Output

Name State CPUUsage MemGB Uptime
---- ----- -------- ----- ------
DomainController Running 1 2.0 05.12:30:45
WebServer-01 Running 8 4.0 05.12:30:40
SQLServer-01 Running 15 8.0 05.12:30:38
DevEnvironment Off 0 0.0 00.00:00:00
TestVM-Saved Saved 0 0.0 00.00:00:00

Method 2: Status Summary with Counts

A high-level summary showing how many VMs are in each state:

@echo off
setlocal

echo Hyper-V Status Summary:
echo =======================
echo.

powershell -NoProfile -Command ^
"$vms = Get-VM;" ^
"$total = $vms.Count;" ^
"$running = @($vms | Where-Object State -eq 'Running').Count;" ^
"$off = @($vms | Where-Object State -eq 'Off').Count;" ^
"$saved = @($vms | Where-Object State -eq 'Saved').Count;" ^
"$paused = @($vms | Where-Object State -eq 'Paused').Count;" ^
"$other = $total - $running - $off - $saved - $paused;" ^
"Write-Host (' Running: {0}' -f $running);" ^
"Write-Host (' Off: {0}' -f $off);" ^
"Write-Host (' Saved: {0}' -f $saved);" ^
"Write-Host (' Paused: {0}' -f $paused);" ^
"if ($other -gt 0) { Write-Host (' Other: {0}' -f $other) };" ^
"Write-Host ' -------';" ^
"Write-Host (' Total: {0}' -f $total)"

pause

Method 3: Detailed Health Report

A comprehensive report including CPU, memory, disk, network, and checkpoint information:

@echo off
setlocal

echo Generating detailed VM health report...
echo.

powershell -NoProfile -Command ^
"Get-VM | Sort-Object State, Name | ForEach-Object {" ^
" $icon = switch ($_.State) { 'Running' {'[*]'} 'Off' {'[ ]'} 'Saved' {'[S]'} default {'[?]'} };" ^
" $color = if ($_.State -eq 'Running') {'Green'} else {'Gray'};" ^
" Write-Host ('{0} {1}' -f $icon, $_.Name) -ForegroundColor $color;" ^
" Write-Host (' State: {0}' -f $_.State);" ^
" Write-Host (' CPUs: {0} ({1}%% usage)' -f $_.ProcessorCount, $_.CPUUsage);" ^
" Write-Host (' Memory: {0} GB assigned' -f [math]::Round($_.MemoryAssigned/1GB,2));" ^
" Write-Host (' Uptime: {0}' -f $_.Uptime);" ^
" Write-Host (' Generation: {0}' -f $_.Generation);" ^
" $cpCount = @(Get-VMCheckpoint -VMName $_.Name -ErrorAction SilentlyContinue).Count;" ^
" Write-Host (' Checkpoints: {0}' -f $cpCount);" ^
" foreach ($hd in $_.HardDrives) {" ^
" $file = Get-Item $hd.Path -ErrorAction SilentlyContinue;" ^
" $sizeGB = if ($file) { [math]::Round($file.Length/1GB,2) } else { 'N/A' };" ^
" Write-Host (' Disk: {0} ({1} GB)' -f $hd.Path, $sizeGB)" ^
" };" ^
" foreach ($nic in $_.NetworkAdapters) {" ^
" Write-Host (' Network: {0}' -f $nic.SwitchName)" ^
" };" ^
" Write-Host ''" ^
"}"

pause

Method 4: Live Monitoring Dashboard

A self-refreshing dashboard that updates every few seconds:

@echo off
title Hyper-V Status Monitor

:loop
cls
echo =============================================
echo HYPER-V LIVE MONITOR
echo %date% %time:~0,8%
echo =============================================
echo.

powershell -NoProfile -Command ^
"$vms = Get-VM | Sort-Object State, Name;" ^
"$running = @($vms | Where-Object State -eq 'Running');" ^
"$off = @($vms | Where-Object State -eq 'Off');" ^
"$totalCPU = ($running | Measure-Object CPUUsage -Sum).Sum;" ^
"$totalMem = ($running | Measure-Object MemoryAssigned -Sum).Sum / 1GB;" ^
"Write-Host (' VMs: {0} Running / {1} Off / {2} Total' -f $running.Count, $off.Count, $vms.Count);" ^
"Write-Host (' CPU: {0}%% total usage' -f $totalCPU);" ^
"Write-Host (' RAM: {0:N1} GB total assigned' -f $totalMem);" ^
"Write-Host '';" ^
"Write-Host ' Name State CPU Memory Uptime';" ^
"Write-Host ' ---- ----- --- ------ ------';" ^
"$vms | ForEach-Object {" ^
" $icon = if ($_.State -eq 'Running') {'*'} else {' '};" ^
" Write-Host (' [{0}] {1,-23} {2,-9} {3,3}%% {4,6:N1} GB {5}' -f" ^
" $icon, $_.Name, $_.State, $_.CPUUsage," ^
" [math]::Round($_.MemoryAssigned/1GB,1)," ^
" $_.Uptime.ToString('dd\.hh\:mm'))" ^
"}"

echo.
echo Refreshing in 10 seconds. Press Ctrl+C to stop.
timeout /t 10 /nobreak >nul
goto loop

Method 5: CSV Export for Reporting

Generate a CSV file for inventory management or compliance reports:

@echo off
setlocal

for /f "tokens=2 delims==" %%T in ('wmic os get LocalDateTime /value') do set "dt=%%T"
set "stamp=%dt:~0,4%%dt:~4,2%%dt:~6,2%"
set "output=%~dp0hyperv_status_%COMPUTERNAME%_%stamp%.csv"

echo Exporting VM status to CSV...

powershell -NoProfile -Command ^
"Get-VM | Select-Object Name, State," ^
"@{Name='CPUCount';Expression={$_.ProcessorCount}}," ^
"@{Name='CPUUsage';Expression={$_.CPUUsage}}," ^
"@{Name='MemoryGB';Expression={[math]::Round($_.MemoryAssigned/1GB,2)}}," ^
"@{Name='Uptime';Expression={$_.Uptime.ToString()}}," ^
"Generation," ^
"@{Name='Checkpoints';Expression={@(Get-VMCheckpoint -VMName $_.Name -ErrorAction SilentlyContinue).Count}}," ^
"@{Name='DiskPaths';Expression={($_.HardDrives.Path) -join '; '}}," ^
"@{Name='Switches';Expression={($_.NetworkAdapters.SwitchName) -join '; '}}" ^
"| Export-Csv -Path '%output%' -NoTypeInformation"

if %errorlevel%==0 (
echo [SUCCESS] Exported to: %output%
echo.
type "%output%"
) else (
echo [ERROR] Export failed.
)

echo.
pause

Host Resource Summary

Beyond individual VM status, understanding host-level resource utilization is important:

@echo off
echo.
echo =============================================
echo HOST RESOURCE SUMMARY
echo =============================================
echo.

powershell -NoProfile -Command ^
"$hi = Get-VMHost;" ^
"$vms = Get-VM;" ^
"$running = @($vms | Where-Object State -eq 'Running');" ^
"$totalAssigned = ($running | Measure-Object MemoryAssigned -Sum).Sum / 1GB;" ^
"$totalStorage = 0;" ^
"foreach ($hd in $vms.HardDrives) {" ^
" $file = Get-Item $hd.Path -ErrorAction SilentlyContinue;" ^
" if ($file) { $totalStorage += $file.Length }" ^
"};" ^
"$totalStorageGB = $totalStorage / 1GB;" ^
"Write-Host (' Logical Processors: {0}' -f $hi.LogicalProcessorCount);" ^
"Write-Host (' VM Path: {0}' -f $hi.VirtualMachinePath);" ^
"Write-Host (' VHD Default Path: {0}' -f $hi.VirtualHardDiskPath);" ^
"Write-Host (' Running VMs: {0}' -f $running.Count);" ^
"Write-Host (' Total RAM Assigned: {0:N1} GB' -f $totalAssigned);" ^
"Write-Host (' Total Disk Used: {0:N1} GB' -f $totalStorageGB)"

pause

Common Mistakes

The Wrong Way: Using WMIC for VM Status

:: WRONG - WMI queries for Hyper-V are complex and poorly documented
wmic /namespace:\\root\virtualization\v2 path Msvm_ComputerSystem get ElementName,EnabledState

Output Concern: While the WMI path works, the EnabledState values are numeric codes (2=Running, 3=Off) that must be manually decoded. Get-VM returns human-readable state names and far more information with simpler syntax.

The Wrong Way: Not Running as Administrator

:: WRONG - Returns empty or partial results without elevation
powershell -Command "Get-VM"

Get-VM requires administrator privileges. Without elevation, it may return no results or throw access denied errors. Always verify admin rights before querying.

Best Practices

  1. Use Get-VM for all status queries: It is the official, comprehensive, and human-readable interface.
  2. Sort by state: Show running VMs first for quick identification of active workloads.
  3. Include resource metrics: CPU usage and memory allocation reveal overloaded or underutilized VMs.
  4. Export regularly: CSV exports create audit trails and support capacity planning analysis.
  5. Monitor checkpoint counts: Excessive checkpoints degrade performance and consume storage.

Conclusion

Getting the status of all Hyper-V VMs from a Batch Script is powered by PowerShell's Get-VM cmdlet, which provides comprehensive information about each virtual machine's state, resource usage, and configuration. From quick one-line status checks to full health dashboards with live refresh, the patterns in this guide enable administrators to maintain continuous visibility into their virtual infrastructure. Regular CSV exports and host resource summaries complete the monitoring toolkit for professional Hyper-V management.