Deploying a Hyper-V Failover Cluster on Windows Server 2022 Core

Windows Server 2022 Datacenter Core

Cluster Setting:

Object Value
Hostname HYPER-V-1, HYPER-V-2
Domain sj.com
Account hypervadmin
Node Public IP 192.168.3.211, 192.168.3.212
Public NICs LBFO, Team_Mgmt, Ethernet0/1
Node Private IP 100.100.100.211, 100.100.100.212
Private NICs LBFO, Team_Htbt, Ethernet2/3
Cluster Name MyCluster
Cluster IP 192.168.3.210
BusType iSCSI
Quorum Disk 2GB, Q
CVS Disk 1 50GB
CVS Disk 2 100GB
VMSwitch SET, vSwitch, Ethernet4/5

Account Privileges:

User DC Host Hyper-V Host VMM Host
sj\hypervadmin Domain Admins / Create Computer objects and Read All Properties of Computers container Administrators /

Deployment requirements

Installing Active Directory Domain Controller on Windows Server 2019

Create a Failover Cluster

  1. Create LBFO teaming, assign interface IP address.

    Get-NetAdapter | ft -AutoSize
    Get-NetAdapter | fl *
    Get-NetAdapter | Remove-NetIPAddress -Confirm:$false
    Get-NetAdapter | Remove-NetRoute -Confirm:$false
    Get-NetAdapter | Set-NetIPInterface -Dhcp Disabled

    # For server management
    New-NetLbfoTeam -Name "Team_Mgmt" -TeamMembers "Ethernet0","Ethernet1" -TeamingMode SwitchIndependent -LoadBalancingAlgorithm Dynamic -Confirm:$false
    Get-NetLbfoTeamMember -Team "Team_Mgmt"

    New-NetIPAddress -InterfaceAlias "Team_Mgmt" -IPAddress 192.168.3.211 -AddressFamily IPv4 -PrefixLength 24 -DefaultGateway 192.168.3.1
    New-NetIPAddress -InterfaceAlias "Team_Mgmt" -IPAddress 192.168.3.212 -AddressFamily IPv4 -PrefixLength 24 -DefaultGateway 192.168.3.1
    Set-DnsClientServerAddress -InterfaceAlias "Team_Mgmt" -ServerAddresses ("192.168.3.180")
    Get-NetIPConfiguration -InterfaceAlias "Team_Mgmt" -Detailed

    # For failover cluster heartbeat
    New-NetLbfoTeam -Name "Team_Htbt" -TeamMembers "Ethernet2","Ethernet3" -TeamingMode SwitchIndependent -LoadBalancingAlgorithm Dynamic -Confirm:$false
    Get-NetLbfoTeamMember -Team "Team_Htbt"

    New-NetIPAddress -InterfaceAlias "Team_Htbt" -IPAddress 100.100.100.211 -AddressFamily IPv4 -PrefixLength 24
    New-NetIPAddress -InterfaceAlias "Team_Htbt" -IPAddress 100.100.100.212 -AddressFamily IPv4 -PrefixLength 24
  2. Configure the Remote Desktop listening port, and enable the Remote Desktop.

    Enable Remote Desktop.

    cscript C:\Windows\System32\Scregedit.wsf /ar 0

    Change RDP Tcp Port.

    Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name 'PortNumber'
    $portValue = '3400'
    Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name 'PortNumber' -Value $portValue
    New-NetFirewallRule -DisplayName 'RDPPORTLatest-TCP-In' -Profile Domain,Public -Direction Inbound -Action Allow -Protocol TCP -LocalPort $portValue
    New-NetFirewallRule -DisplayName 'RDPPORTLatest-UDP-In' -Profile Domain,Public -Direction Inbound -Action Allow -Protocol UDP -LocalPort $portValue
    Get-Service TermService | Restart-Service -Force
  3. (Option) Enable OpenSSH Server.

    Get-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
    Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 -ErrorAction Stop

    $fileName = 'C:\ProgramData\ssh\sshd_config'
    (gc $fileName) -replace "Port 22", "$&`nPort 2222" | sc $fileName

    Start-Service sshd
    Set-Service -Name sshd -StartupType 'Automatic'

    if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue)) {
    Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
    New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 2222
    } else {
    Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
    }
  4. Set date and timezone.

    Set-TimeZone -Id "China Standard Time" -PassThru

    # w32tm /config /syncfromflags:domhier /update
    w32tm /config /manualpeerlist:"ntp.ntsc.ac.cn" /syncfromflags:manual /update
    w32tm /query /status
  5. Get driver information about PnP devices.

    Get-PnpDevice | Where-Object { $_.Status -ne "OK" } | Format-Table -AutoSize
  6. Windows Update.

    Sconfig -> 6 -> 1

    Get-Hotfix | Sort-Object InstalledOn
  7. Rename computer name and join a domain.

    Rename-Computer -NewName "HYPER-V-1" -Restart
    Rename-Computer -NewName "HYPER-V-2" -Restart
    Add-Computer -DomainName sj.com -DomainCredential 'sj\hypervadmin'

    Add-LocalGroupMember -Group "Administrators" -Member 'sj\hypervadmin'
    Get-LocalGroupMember -Group "Administrators"

    shutdown /r /t 0
  8. (Option) Disable firewall.

    Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
  9. Install Failover Clustering and Hyper-V roles.

    Install-WindowsFeature -Name "Hyper-V", "Failover-Clustering" -IncludeAllSubFeature -IncludeManagementTools
  10. Setting Multipath.

    PS C:\> Get-WindowsFeature -Name Multipath-IO | Select-Object Name, InstallState
    PS C:\> Install-WindowsFeature -Name Multipath-IO -IncludeManagementTools
    PS C:\> Enable-MSDSMAutomaticClaim -BusType iSCSI

    PS C:\> shutdown /r /t 0

    PS C:\> Set-MSDSMGlobalDefaultLoadBalancePolicy -Policy RR
    PS C:\> Get-MPIOAvailableHW
    PS C:\> Get-MSDSMGlobalDefaultLoadBalancePolicy

    PS C:\> mpclaim -e
    "Target H/W Identifier " Bus Type MPIO-ed ALUA Support
    -------------------------------------------------------------------------------
    "MSFT Virtual HD " iSCSI YES ALUA Not Supported
    "VMware Virtual disk " SAS NO ALUA Not Supported

    PS C:\> mpclaim -s -d
    For more information about a particular disk, use 'mpclaim -s -d #' where # is the MPIO disk number.
    MPIO Disk System Disk LB Policy DSM Name
    -------------------------------------------------------------------------------
    MPIO Disk2 Disk 3 RR Microsoft DSM
    MPIO Disk1 Disk 2 RR Microsoft DSM
    MPIO Disk0 Disk 1 RR Microsoft DSM

    PS C:\> mpclaim -s -d 0
    MPIO Disk0: 01 Paths, Round Robin, ALUA Not Supported
    Controlling DSM: Microsoft DSM
    SN: 60003FF44DC75ADCBE9430E8DF316318
    Supported Load Balance Policies: FOO RR RRWS LQD WP LB

    Path ID State SCSI Address Weight
    ---------------------------------------------------------------------------
    0000000077050000 Active/Optimized 005|000|000|000 0
  11. Configuring iSCSI Storage.

    Set-Service -Name MSiSCSI -StartupType Automatic
    Get-Service -Name MSiSCSI | Start-Service
    New-IscsiTargetPortal -TargetPortalAddress "192.168.3.180" -TargetPortalPortNumber 3260
    Get-IscsiTarget
    Connect-IscsiTarget -NodeAddress "iqn.1991-05.com.microsoft:remote-machine-hyper-v-target" -TargetPortalAddress "192.168.3.180" -IsPersistent $true
    # Disconnect-IscsiTarget -NodeAddress "iqn.1991-05.com.microsoft:remote-machine-hyper-v-target"

    Get-Disk | Where-Object { $_.BusType -eq "iSCSI" }

    Set-Disk 1 -ErrorAction Stop -IsOffline $false
    Set-Disk 2 -ErrorAction Stop -IsOffline $false
    Set-Disk 3 -ErrorAction Stop -IsOffline $false

    Initialize-Disk -Number 1 -PartitionStyle GPT
    Initialize-Disk -Number 2 -PartitionStyle GPT
    Initialize-Disk -Number 3 -PartitionStyle GPT

    New-Partition -DiskNumber 1 -UseMaximumSize -DriveLetter Q | Format-Volume -FileSystem NTFS -NewFileSystemLabel "quorum" -Confirm:$false
    New-Partition -DiskNumber 2 -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel "data01" -Confirm:$false
    New-Partition -DiskNumber 3 -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel "data02" -Confirm:$false
  12. Create a Failover Cluster.

    Test-Cluster -Node "HYPER-V-1", "HYPER-V-2" -Include "Storage", "Inventory", "Network", "System Configuration"
    New-Cluster -Name "MyCluster" -Node "HYPER-V-1", "HYPER-V-2" -StaticAddress "192.168.3.210" -NoStorage
    Get-ClusterAvailableDisk -Cluster "MyCluster" | Add-ClusterDisk
    Set-ClusterQuorum -Cluster "MyCluster" -NodeAndDiskMajority "Cluster Disk 1"
    Add-ClusterSharedVolume -Cluster "MyCluster" -Name "Cluster Disk 2"
    Add-ClusterSharedVolume -Cluster "MyCluster" -Name "Cluster Disk 3"
    Get-ClusterSharedVolume -Cluster "MyCluster"

Hyper-V Configuration

  1. Create a vSwitch.

    Get-NetAdapter -Physical | Format-Table Name, InterfaceDescription, Status
    New-VMSwitch -Name "vSwitch" -NetAdapterName "Ethernet4","Ethernet5" -EnableEmbeddedTeaming $true -AllowManagementOS $false
    Set-VMSwitchTeam -Name "vSwitch" -LoadBalancingAlgorithm Dynamic
    Get-VMSwitchTeam -Name "vSwitch"
  2. Enable Live Migration on Each Host.

    Enable-VMMigration

    Get-VMHost | Select-Object Name, VirtualMachineMigrationEnabled,
    VirtualMachineMigrationAuthenticationType,
    VirtualMachineMigrationPerformanceOption,
    MaximumVirtualMachineMigrations,
    UseAnyNetworkForMigration,
    VirtualMachineMigrationNetworks

    (Get-Cluster).MaximumParallelMigrations = 5
    Set-VMHost -VirtualMachineMigrationPerformanceOption TCPIP

    # Set the specified migration network
    Set-VMHost -UseAnyNetworkForMigration $false
    Set-VMMigrationNetwork 100.100.100.*

    # Set any migration network
    Set-VMHost -UseAnyNetworkForMigration $true

Optimizing Failover Delay Sensitivity

# Reduce heartbeat failure threshold from 5 to 3 (or 2 for aggressive tuning)
Get-Cluster | fl *Subnet*, *Delay*, *Timeout*

(Get-Cluster).SameSubnetThreshold = 3 # Fail after 3 missed heartbeats
(Get-Cluster).SameSubnetDelay = 1000 # 1s between heartbeats (unchanged)
(Get-Cluster).CrossSubnetThreshold = 3 # For cross-subnet clusters
(Get-Cluster).CrossSubnetDelay = 1000 # 1s between heartbeats (unchanged)

# Apply changes (no reboot needed)
Restart-Service clussvc -Force

# Force faster failure detection (registry tweak)
reg add "HKLM\Cluster\Nodes" /v AggressiveDetection /t REG_DWORD /d 1 /f

About of delete Virtaul Machine

  1. Remove virtual machine from Failover Cluster Manager, it will only unregister resource. keep all vm files.
  2. Delete virtual machine from Hyper-V Manager, it will delete vm configuration files, but keep vm virtual hard disk files.

Destroy a Failover Cluster

Get-Cluster -Name "MyCluster" | Remove-Cluster -CleanupAD
Remove-Computer -UnjoinDomaincredential (Get-Credential) -PassThru -Restart

Virutal Machine Files

PS C:\> tree C:\ClusterStorage\Volume2\aaa\ /F
Folder PATH listing
Volume serial number is 000001C9 5AB2:B5D9
C:\CLUSTERSTORAGE\VOLUME2\AAA
│ aaa_disk_1.vhdx

└───Virtual Machines
│ A5DED9A3-2F4C-4E47-B058-5EDFC130B062.vmcx
│ A5DED9A3-2F4C-4E47-B058-5EDFC130B062.vmgs
│ A5DED9A3-2F4C-4E47-B058-5EDFC130B062.VMRS

└───A5DED9A3-2F4C-4E47-B058-5EDFC130B062

virtual machine configuration (.VMCX)
virtual machine guest state (.VMGS)
virtual machine runtime state (.VMRS)

Fault Redundancy Test

Item: Test VM Protected Network.

Disconnect all physical network adapter of vSwitch on VMHost#2.

Result

Virtual machine live migration to VMHost#1.

Disconnect all physical network adapter of vSwitch on VMHost#1.

Result

The operation did not complete on resource Virtual Machine Rocky.

Cluster resource 'Virtual Machine Rocky' in clustered role 'Rocky' has received a critical state notification. For a virtual machine this indicates that a critical network of the virtual machine is in an unhealthy state. Verify the network connectivity of the virtual machine and the virtual networks that the virtual machine is configured to use.

Wait for ten minutes until the status of the virtual switch is stable, then proceed with the test.

PS C:\Users\hypervadmin.SJ> Compare-VM -Name 'Rocky' -DestinationHost 'hyper-v-2'
Compare-VM : Virtual machine migration operation failed at migration source.
Failed to establish a connection with host 'HYPER-V-2': No credentials are available in the security package
(0x8009030E).
The Virtual Machine Management Service failed to authenticate the connection for a Virtual Machine migration at the
source host: no suitable credentials available. (1) Make sure the operation is initiated on the source host of the
migration. (2) CredSSP authentication is not compatible with Credential Guard (enabled by default on supported
machines). For compatibility with Credential Guard, make sure the source host is configured to use Kerberos for the
authentication of migration connections and Constrained Delegation is enabled for the host in Active Directory. For
more information, please see: https://go.microsoft.com/fwlink/?linkid=2258829
Virtual machine migration operation for 'Rocky' failed at migration source 'HYPER-V-1'. (Virtual machine ID
6631EB12-9158-4C66-BA05-AEB49F90A378)
The Virtual Machine Management Service failed to establish a connection for a Virtual Machine migration with host
'HYPER-V-2': No credentials are available in the security package (0x8009030E).
Failed to authenticate the connection at the source host: no suitable credentials available.
At line:1 char:1
+ Compare-VM -Name 'Rocky' -DestinationHost 'hyper-v-2'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Compare-VM], VirtualizationException
+ FullyQualifiedErrorId : OperationFailed,Microsoft.HyperV.PowerShell.Commands.CompareVM

Increase the maximum failures in the specified perod. The default value is 1 times in 6 hours.

Troubleshooting

Issue: Test Hyper-V vSwitch lost connection.

Cluster resource 'SCVMM Ubuntu' in clustered role  'SCVMM Ubuntu Resources' has received a critical state notification.  For a virtual machine this indicates that a critical network of the virtual machine is in an unhealthy state. Verify the network connectivity of the virtual machine and the virtual networks that the virtual machine is configured to use.

Working normal. The VM resource will not move to other nodes or restart.


Issue: Failed to create cluster. Access is denied.

PS C:\Users\hypervadmin> New-Cluster -Name "MyCluster" -Node "HYPER-V-1" -StaticAddress "192.168.3.210" -NoStorage
The clustered role was not successfully created. For more information view the report file below.
Report file location: C:\Windows\cluster\Reports\Create Cluster Wizard MyCluster on 2025.06.20 At 11.24.10.htm
New-Cluster : An error occurred while performing the operation.
An error occurred while creating the cluster 'MyCluster'.
An error occurred creating cluster 'MyCluster'.
Access is denied
At line:1 char:1
+ New-Cluster -Name "MyCluster" -Node "HYPER-V-1" -StaticAddress "192.1 ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (:) [New-Cluster], ClusterCmdletException
+ FullyQualifiedErrorId : AccessDenied,Microsoft.FailoverClusters.PowerShell.NewClusterCommand

sj\hypervadmin 域账户添加归属组域管理员 DA,或者 Computers 容器添加读取所有属性和创建计算机对象权限。


Requires administrative permissions on the servers that will become cluster nodes. Also requires Create Computer objects and Read All Properties permissions in the container that is used for computer accounts in the domain.


Issue: Failed to enable the live migration feature.

Although creating a failover cluster no longer requires domain joining from Windows Server 2016 and later versions, enabling the Hyper-V live migration feature still requires domain joining.


Issue: Unable to create NIC teaming(LBFO) for Hyper-V vSwitch.

LBFO is deprecated, use SET feature or set -AllowNetLbfoTeams $true.


Issue: Failed to poweron virtual machine, the vhdx file access denied.


The virtual machine cannot be started. The UUID account permission of the virtual disk file is lost or incorrect.


Delete and re-add the virtual disk to automatically correct the permission issue.


Issue: WinRM fails with Kerberos 0x8009030e.

Get-Item WSMan:\localhost\Client\TrustedHosts
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*'

Issue: Hyper-V 虚拟机无法被外部访问。

Hyper-V 主机本身运行在 VMware 虚拟机(嵌套虚拟化)中,并且外部网络无法正常工作,是因为 VMware 虚拟交换机默认不转发混杂模式(Promiscuous Mode)。Hyper-V 的外部网络虚拟交换机需要物理网卡支持 混杂模式(允许所有流量通过),但 VMware 默认会阻止这种模式。

VMware 虚拟交换机启用 "混杂模式"、"MAC 地址更改" 和 "伪传输"。


Issue: Error 21502

The node HYPER-V-1 down, virtual machine MyPC failover to node HYPER-V-2. However, during failback, an error 21502 occurred.

Live migration of 'Virtual Machine MyPC' failed.

Virtual machine migration operation for 'MyPC' failed at migration destination 'HYPER-V-1'. (Virtual machine ID 602BD66D-433B-41E1-87E2-480A15205A07)

'MyPC' Failed to create Planned Virtual Machine at migration destination: The object already exists. (0x80071392). (Virtual machine ID 602BD66D-433B-41E1-87E2-480A15205A07)

The operation failed because a virtual machine with the same identifier already exists. Select a new identifier and try the operation again.

Check the virtual machine cache \192.168.3.211\c$\ProgramData\Microsoft\Windows\Hyper-V\Virtual Machines Cache.
There are remaining configuration file.

Remove the virtual machine MyPC remaining configuration file on the node HYPER-V-1.


Issue: The cluster event displays <unavailable> in the Failover Cluster Manager.

Workaround:

The failover cluster manager on windows server 2022, connect to Hyper-V cluster on windows server 2025, the reason is unknown, might be a bug.
Because 2025 connect to 2025 display normally.


Issue: The USB removable device cannot passthrough to Hyper-V VM.

PS C:\Users\hypervadmin> Get-Disk | Where-Object IsOffline -eq $false | ft -autosize

Number Friendly Name Serial Number HealthStatus OperationalStatus Total Size Partition
Style
------ ------------- ------------- ------------ ----------------- ---------- ------------
0 VMware Virtual disk 6000c29d9547c048baca75c596d05f14 Healthy Online 90 GB GPT
2 VendorCo ProductCode 5631371306467715930 Healthy Online 7.5 GB MBR
3 MSFT Virtual HD 40271301-BEE2-4852-8AA9-6D473111272C Healthy Online 50 GB GPT
4 MSFT Virtual HD 92844058-3574-485D-8D0D-672E4A8A80F2 Healthy Online 99.85 GB GPT
1 MSFT Virtual HD A1702DA2-7C96-411A-8634-5C829904E2B9 Healthy Online 2 GB GPT

PS C:\Users\hypervadmin> Get-Disk -Number 2 | fl *

DiskNumber : 2
PartitionStyle : MBR
ProvisioningType : Fixed
OperationalStatus : Online
HealthStatus : Healthy
BusType : USB
UniqueIdFormat : Vendor Specific
OfflineReason :
ObjectId : {1}\\MyCluster\root/Microsoft/Windows/Storage/Providers_v2\WSP_Disk.ObjectId="{4d8acfa8-4cf8-11
f0-8974-806e6f6e6963}:DI:\\?\usbstor#disk&ven_vendorco&prod_productcode&rev_2.00#56313713064677
15930&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}"
PassThroughClass :
PassThroughIds :
PassThroughNamespace :
PassThroughServer :
UniqueId : USBSTOR\DISK&VEN_VENDORCO&PROD_PRODUCTCODE&REV_2.00\5631371306467715930&0:HYPER-V-1
AdapterSerialNumber :
AllocatedSize : 8053063680
BootFromDisk : False
FirmwareVersion : 2.00
FriendlyName : VendorCo ProductCode
Guid :
IsBoot : False
IsClustered : False
IsHighlyAvailable : False
IsOffline : False
IsReadOnly : False
IsScaleOut : False
IsSystem : False
LargestFreeExtent : 0
Location : Integrated : Bus 0 : Device 0 : Function 6 : Adapter 0 : Port 0
LogicalSectorSize : 512
Manufacturer : VendorCo
Model : ProductCode
Number : 2
NumberOfPartitions : 1
Path : \\?\usbstor#disk&ven_vendorco&prod_productcode&rev_2.00#5631371306467715930&0#{53f56307-b6bf-11
d0-94f2-00a0c91efb8b}
PhysicalSectorSize : 512
SerialNumber : 5631371306467715930
Signature : 2245165859
Size : 8053063680
PSComputerName :
CimClass : ROOT/Microsoft/Windows/Storage:MSFT_Disk
CimInstanceProperties : {ObjectId, PassThroughClass, PassThroughIds, PassThroughNamespace...}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties

PS C:\Users\hypervadmin> Get-Disk -Number 2 | Set-Disk -IsOffline $true

Set-Disk : Not Supported

Extended information:
Removable media cannot be set to offline.

Activity ID: {35fd3335-e284-0001-1a58-0a3684e2db01}
At line:1 char:22
+ Get-Disk -Number 2 | Set-Disk -IsOffline $true
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (StorageWMI:ROOT/Microsoft/..._StorageCmdlets) [Set-Disk], CimExceptio
n
+ FullyQualifiedErrorId : StorageWMI 1,Set-Disk

Not supported.

Reference

windows-server-virtualization.pdf |