How to Configure Storage for Hyper-V on Windows Server 2022

Storage configuration is one of the most consequential decisions when deploying Hyper-V on Windows Server 2022. The wrong storage format, controller type, or placement strategy can throttle VM performance, limit scalability, and complicate disaster recovery. This guide covers all storage options available in Hyper-V on Windows Server 2022 with practical PowerShell commands for each configuration scenario.

VHD vs VHDX: Understanding the Difference

Hyper-V supports two virtual disk formats: VHD (legacy) and VHDX (current). The differences are significant enough that you should always use VHDX for new deployments on Server 2022.

VHD limitations: maximum size of 2040 GB, no built-in data corruption protection, no sector size alignment for modern 4K native disks, and limited metadata. VHDX advantages: maximum size of 64 TB, built-in data corruption protection via journal logging, support for 4K logical sectors, larger block sizes (up to 256 MB), and custom metadata blocks for tooling.

VHDX also supports online resize without VM downtime (for expansion) and provides better performance on modern storage hardware due to proper 4K sector alignment.

Check the format of existing virtual disks:

Get-VHD -Path "D:VMsWebServer01WebServer01.vhdx" | Select-Object Path, VhdFormat, VhdType, FileSize, Size, MinimumSize

Creating VHDX Disks with New-VHD

The New-VHD cmdlet creates virtual hard disks. There are three primary types to understand: Fixed, Dynamic, and Differencing.

Fixed VHDX — allocates all space immediately on the host file system. Best for production workloads where predictable I/O performance matters:

New-VHD -Path "D:VMsProdDB01OS.vhdx" -SizeBytes 80GB -Fixed

Dynamic VHDX — starts small and expands as data is written. The file only occupies the actual data written, not the full provisioned size. Useful for dev/test environments or when storage capacity is tight:

New-VHD -Path "D:VMsDevBox01OS.vhdx" -SizeBytes 80GB -Dynamic

You can also specify the block size (512 bytes for VHD compat mode, or larger for better VHDX performance):

New-VHD -Path "D:VMsProdDB01Data.vhdx" -SizeBytes 500GB -Fixed -BlockSizeBytes 32MB -LogicalSectorSizeBytes 4096

Differencing VHDX — stores only the changes relative to a parent disk. Used in VDI scenarios and for rapid cloning from a golden image:

New-VHD -Path "D:VMsVDI-User01OS.vhdx" -ParentPath "D:TemplatesWS2022-Gold.vhdx" -Differencing

Differencing disks should not be used for production VMs that modify their OS disk heavily, as the differencing chain grows over time and can become a performance bottleneck.

VHDX Maximum Size: Working with 64TB Disks

VHDX supports a maximum virtual size of 64 TB, making it suitable for large database workloads. Create a 20 TB data disk for a large SQL Server workload:

New-VHD -Path "E:VMsSQLServer01DataDisk.vhdx" -SizeBytes 20TB -Fixed

Note that a 20 TB Fixed VHDX will immediately consume 20 TB on the host file system. Ensure the underlying volume has adequate free space before creating fixed disks at this scale. Get the actual file size versus virtual size:

$vhd = Get-VHD -Path "E:VMsSQLServer01DataDisk.vhdx"
Write-Host "Virtual Size: $([math]::Round($vhd.Size/1TB, 2)) TB"
Write-Host "Actual File Size: $([math]::Round($vhd.FileSize/1TB, 2)) TB"

Shared VHDX for Guest Clustering

Shared VHDX allows multiple VMs to simultaneously access the same VHDX file. This enables Windows Server Failover Clustering at the guest level without needing iSCSI or Fibre Channel access inside the VMs. This is distinct from Hyper-V clustering at the host level.

Create a shared VHDX:

New-VHD -Path "D:SharedStorageClusterDisk01.vhdx" -SizeBytes 500GB -Fixed -Shared

The shared VHDX must be placed on a volume accessible to all Hyper-V hosts in the cluster (SMB share, CSV, etc.). Add the shared VHDX to the first cluster node VM:

Add-VMHardDiskDrive -VMName "SQLNode01" `
    -Path "D:SharedStorageClusterDisk01.vhdx" `
    -ControllerType SCSI `
    -SupportPersistentReservations

The -SupportPersistentReservations flag is required for shared VHDX. Add the same disk to the second cluster node:

Add-VMHardDiskDrive -VMName "SQLNode02" `
    -Path "D:SharedStorageClusterDisk01.vhdx" `
    -ControllerType SCSI `
    -SupportPersistentReservations

Pass-Through Disks

Pass-through disks give a VM direct access to a physical disk on the host, bypassing the VHDX layer entirely. This provides the lowest possible storage latency for VMs and is sometimes used for high-performance database scenarios.

To configure a pass-through disk, first the physical disk on the host must be offline. Take the disk offline on the host:

Set-Disk -Number 2 -IsOffline $true

Add the pass-through disk to a VM:

Add-VMHardDiskDrive -VMName "SQLServer01" -ControllerType SCSI -DiskNumber 2

Pass-through disks have important limitations: they cannot be snapshotted (checkpoints will fail or exclude the disk), they cannot be easily migrated without shared storage access, and they are harder to manage at scale. In most cases, a fixed VHDX on fast NVMe storage provides comparable performance with greater flexibility.

Configuring iSCSI Targets for Hyper-V Storage

iSCSI provides block storage over standard Ethernet, making it a popular choice for Hyper-V shared storage. Windows Server 2022 includes a built-in iSCSI Target role. Install the iSCSI Target Server feature:

Install-WindowsFeature -Name FS-iSCSITarget-Server -IncludeManagementTools

Create an iSCSI target for Hyper-V use:

New-IscsiServerTarget -TargetName "HyperV-Cluster-Storage" `
    -InitiatorIds "IPAddress:192.168.1.10","IPAddress:192.168.1.11"

Create a virtual disk to back the iSCSI LUN:

New-IscsiVirtualDisk -Path "E:iSCSIClusterLUN01.vhdx" -SizeBytes 2TB

Associate the virtual disk with the target:

Add-IscsiVirtualDiskTargetMapping -TargetName "HyperV-Cluster-Storage" -Path "E:iSCSIClusterLUN01.vhdx"

On the Hyper-V host side, connect to the iSCSI target:

New-IscsiTargetPortal -TargetPortalAddress "192.168.2.100"
Get-IscsiTarget | Connect-IscsiTarget -IsPersistent $true

Storage Spaces for Hyper-V

Storage Spaces allows you to pool physical disks and create resilient virtual disks (storage tiers) directly on a Hyper-V host. This is suitable for standalone hosts. For clustered Hyper-V, use Storage Spaces Direct (S2D).

Create a storage pool from available physical disks:

$disks = Get-PhysicalDisk -CanPool $true
New-StoragePool -FriendlyName "HyperV-Pool" `
    -StorageSubSystemFriendlyName (Get-StorageSubSystem).FriendlyName `
    -PhysicalDisks $disks

Create a two-way mirror virtual disk from the pool (recommended for Hyper-V — tolerates one disk failure):

New-VirtualDisk -StoragePoolFriendlyName "HyperV-Pool" `
    -FriendlyName "VM-Volume" `
    -ResiliencySettingName Mirror `
    -NumberOfDataCopies 2 `
    -ProvisioningType Fixed `
    -Size 4TB

Initialize, partition, and format the virtual disk:

Get-VirtualDisk -FriendlyName "VM-Volume" | Get-Disk | `
    Initialize-Disk -PartitionStyle GPT -PassThru | `
    New-Partition -DriveLetter V -UseMaximumSize | `
    Format-Volume -FileSystem NTFS -AllocationUnitSize 65536 -NewFileSystemLabel "Hyper-V VMs" -Confirm:$false

The 64KB allocation unit size (65536 bytes) is recommended for NTFS volumes hosting VHDX files to reduce fragmentation and improve I/O patterns.

Online VHDX Resize

One of the key advantages of VHDX over VHD is the ability to expand a disk while the VM is running. The VM’s SCSI controller supports hot-add and online resize. Expand a VHDX while the VM is running:

Resize-VHD -Path "D:VMsWebServer01DataDisk.vhdx" -SizeBytes 400GB

After the Hyper-V resize, the guest OS still sees the old partition size. Connect to the VM and extend the volume:

Invoke-Command -VMName "WebServer01" -Credential (Get-Credential) -ScriptBlock {
    $disk = Get-Disk | Where-Object { $_.OperationalStatus -eq 'Online' -and $_.PartitionStyle -eq 'GPT' } | Select-Object -Last 1
    $partition = $disk | Get-Partition | Where-Object { $_.Type -eq 'Basic' }
    $maxSize = ($partition | Get-PartitionSupportedSize).SizeMax
    Resize-Partition -DiskNumber $disk.Number -PartitionNumber $partition.PartitionNumber -Size $maxSize
}

You cannot shrink a VHDX online. Shrinking requires the VM to be offline, and you must first shrink the partition inside the VM before shrinking the VHDX container.

SCSI vs IDE Controllers

Generation 1 VMs support both IDE and SCSI controllers. Generation 2 VMs use only SCSI (with a virtual SCSI controller that supports boot). The distinctions that matter in practice:

IDE controller (Gen 1 only): maximum 4 disks (2 controllers x 2 drives each), required for OS boot disk in Gen 1, does not support online add/remove. SCSI controller: up to 64 disks per controller, up to 4 controllers per VM (256 disks total), supports hot-add and removal while VM is running, supports online resize.

Add a SCSI controller to a Gen 1 VM:

Add-VMScsiController -VMName "LegacyServer01"

List all disk controllers on a VM:

Get-VMScsiController -VMName "WebServer01"
Get-VMIdeController -VMName "LegacyServer01"

Check which controller slot a disk is attached to:

Get-VMHardDiskDrive -VMName "WebServer01" | Select-Object VMName, Path, ControllerType, ControllerNumber, ControllerLocation

Storage QoS for Virtual Machines

Storage Quality of Service (QoS) lets you set minimum and maximum IOPS limits for individual VM disks. This prevents a single busy VM from monopolizing storage bandwidth and starving other VMs. Configure storage QoS directly on a VM’s hard disk drive:

Set-VMHardDiskDrive -VMName "WebServer01" `
    -Path "D:VMsWebServer01OS.vhdx" `
    -MinimumIOPS 100 `
    -MaximumIOPS 2000

Check current QoS settings for all VM disks:

Get-VMHardDiskDrive -VMName * | Where-Object { $_.MaximumIOPS -gt 0 } | `
    Select-Object VMName, Path, MinimumIOPS, MaximumIOPS | Format-Table -AutoSize

For more advanced QoS policies managed centrally (especially useful in clustered environments), use Storage QoS policies via SCVMM or the cluster storage manager. Create a policy-based QoS approach using the storage subsystem:

New-StorageQosPolicy -Name "Production-VM-Tier" -MinimumIops 200 -MaximumIops 5000 -PolicyType Dedicated

Storage Live Migration

Storage live migration moves a VM’s virtual disks to a different location while the VM is running, with no downtime. This is useful for rebalancing storage load or evacuating a failing disk array.

Move all storage for a VM to a new path:

Move-VMStorage -VMName "WebServer01" -DestinationStoragePath "E:VMsWebServer01"

Move only a specific VHD to a different location:

Move-VMStorage -VMName "WebServer01" -VHDs @{
    SourceFilePath = "D:VMsWebServer01DataDisk.vhdx"
    DestinationFilePath = "F:HighPerfWebServer01DataDisk.vhdx"
}

Monitor storage migration progress:

Get-VMStorageMigrationStatus -VMName "WebServer01"

Storage live migration uses the host network (or a dedicated migration network if configured) and typically runs at near line speed. For a 200 GB VHDX over a 10 Gbps network, expect approximately 3-5 minutes per 100 GB depending on disk read speed and change rate.

Best Practices Summary for Hyper-V Storage on Server 2022

Always use VHDX over VHD for new deployments. Use fixed-size VHDX for production workloads to avoid performance overhead from dynamic expansion. Format NTFS volumes hosting VHDX files with 64KB allocation units. Place VM disks on SCSI controllers (not IDE) to enable hot-add and online resize. Implement Storage QoS on production hosts with mixed workloads to prevent IOPS contention. For high-availability requirements, choose between Shared VHDX (guest clustering) or Hyper-V clustering with shared storage at the host level, depending on your architecture. Use Storage Spaces on standalone hosts or Storage Spaces Direct for hyperconverged clustering scenarios.