Skip to content
Back to Blog
Windows Server

Hyper-V Failover Cluster: High Availability VMs

Build a Hyper-V Failover Cluster with Cluster Shared Volumes, Live Migration, and HA virtual machines on Windows Server.

Nov 2025
15 min read

Introduction

Hyper-V Failover Clustering provides high availability for virtual machines — when a Hyper-V host fails, its VMs automatically restart on surviving hosts. This is essential for production workloads where downtime is unacceptable. This guide covers building a Hyper-V cluster from physical servers to running highly available VMs.

Prerequisites

  • Minimum 2 servers (nodes) with Windows Server 2019/2022 Datacenter
  • Shared storage: iSCSI SAN, Fibre Channel, or Storage Spaces Direct (S2D)
  • Two network interfaces per node (production + cluster communication)
  • All nodes domain-joined

Installing Hyper-V and Failover Clustering

POWERSHELL
# Run on ALL nodes
Install-WindowsFeature -Name Hyper-V, Failover-Clustering -IncludeManagementTools -Restart

# After restart: validate cluster configuration
Test-Cluster -Node "hv01.company.local", "hv02.company.local" `
  -Include "Storage Spaces Direct", "Inventory", "Network", "System Configuration"
# Review the report! Fix any errors before creating cluster.

Creating the Cluster

POWERSHELL
# Create cluster with static IP
New-Cluster `
  -Name "HVCluster01" `
  -Node "hv01.company.local", "hv02.company.local" `
  -StaticAddress 192.168.1.20 `
  -NoStorage  # Add storage separately

# Configure cluster quorum
# For 2 nodes: need file share witness or Azure Cloud Witness
Set-ClusterQuorum -FileShareWitness "witness-serverhv-quorum"

# Verify cluster
Get-Cluster
Get-ClusterNode

Configuring Cluster Networks

POWERSHELL
# Rename cluster networks for clarity
(Get-ClusterNetwork | Where-Object {$_.Address -eq "192.168.1.0"}).Name = "Production"
(Get-ClusterNetwork | Where-Object {$_.Address -eq "192.168.100.0"}).Name = "Cluster"

# Production network: allow client access
(Get-ClusterNetwork "Production").Role = 3  # 3 = Client+Cluster

# Cluster network: cluster communication only (not client traffic)
(Get-ClusterNetwork "Cluster").Role = 1     # 1 = Cluster only

Adding Shared Storage

POWERSHELL
# Option A: iSCSI storage
# Connect to iSCSI target from each node first
Start-Service msiscsi
Set-Service msiscsi -StartupType Automatic
New-IscsiTargetPortal -TargetPortalAddress "192.168.100.50"
Connect-IscsiTarget -NodeAddress "iqn.2020-01.com.company:storage01"

# Initialize and format shared disk (run once, on one node)
Initialize-Disk -Number 1 -PartitionStyle GPT
New-Partition -DiskNumber 1 -UseMaximumSize -AssignDriveLetter
Format-Volume -DriveLetter E -FileSystem NTFS -NewFileSystemLabel "ClusterStorage"

# Add disk to cluster
Get-ClusterAvailableDisk | Add-ClusterDisk

# Option B: Storage Spaces Direct (S2D)
Enable-ClusterStorageSpacesDirect -CacheState Disabled

# Create virtual disk on S2D
New-Volume -StoragePoolFriendlyName "S2D on HVCluster01" `
  -FriendlyName "VMs-Volume01" `
  -FileSystem CSVFS_ReFS `
  -StorageTierFriendlyNames Performance, Capacity `
  -StorageTierSizes 100GB, 500GB

Creating Highly Available VMs

POWERSHELL
# Create VM on cluster shared volume
$VMPath = "C:ClusterStorageVMs-Volume01"

New-VM `
  -Name "WebServer01" `
  -MemoryStartupBytes 4GB `
  -VHDPath "$VMPathWebServer01WebServer01.vhdx" `
  -NewVHDSizeBytes 80GB `
  -SwitchName "Production" `
  -Path "$VMPath"

# Configure VM
Set-VM -Name "WebServer01" `
  -ProcessorCount 4 `
  -DynamicMemory $true `
  -MemoryMinimumBytes 2GB `
  -MemoryMaximumBytes 16GB

# Make VM highly available
Add-ClusterVirtualMachineRole -VMName "WebServer01"

# Verify HA status
Get-ClusterGroup "WebServer01"

Live Migration

POWERSHELL
# Move VM to specific node (no downtime)
Move-ClusterVirtualMachineRole `
  -Name "WebServer01" `
  -Node "hv02.company.local" `
  -MigrationType Live

# Drain a node for maintenance
Suspend-ClusterNode -Name "hv01.company.local" -Drain

# After maintenance: resume
Resume-ClusterNode -Name "hv01.company.local"

Monitoring Cluster Health

POWERSHELL
# Overall cluster status
Get-ClusterNode | Select-Object Name, State, NodeWeight
Get-ClusterGroup | Select-Object Name, OwnerNode, State

# Check for cluster events
Get-ClusterLog -Destination C:Logs
# VM placement report
Get-ClusterGroup | Where-Object {$_.GroupType -eq "VirtualMachine"} |
  Select-Object Name, OwnerNode, State |
  Sort-Object OwnerNode

# Disk health
Get-PhysicalDisk | Select-Object FriendlyName, HealthStatus, OperationalStatus, Size

Automated VM Balancing

POWERSHELL
# Enable VM load balancing (auto-migrate VMs for even distribution)
(Get-Cluster).AutoBalancerMode = 2     # 2 = Balance when node joins
(Get-Cluster).AutoBalancerLevel = 1   # 1 = Low aggressiveness

# Anti-affinity (keep VMs on different nodes)
# Useful to prevent all web servers landing on same host
New-ClusterAffinityRule -Name "WebServers-AntiAffinity" -Ruletype SameFaultDomain
Add-ClusterGroupToAffinityRule -Name "WebServers-AntiAffinity" -Groups "WebServer01", "WebServer02"

Hyper-V clustering transforms individual servers into a resilient platform where VMs can survive host failures. The most important skills: understanding quorum (the mechanism that prevents split-brain), mastering Live Migration for maintenance, and knowing how to drain nodes gracefully.