How to Configure Storage Spaces on Windows Server 2019
Storage Spaces is a software-defined storage (SDS) feature in Windows Server 2019 that allows administrators to pool physical disks from multiple drives or enclosures and create virtual disks with resiliency (mirroring, parity) and thin provisioning. Storage Spaces abstracts the underlying hardware, enabling commodity disks to provide enterprise storage features. Windows Server 2019 extends Storage Spaces with Storage Spaces Direct (S2D), which pools disks across cluster nodes for hyper-converged infrastructure, but this article focuses on standalone Storage Spaces configuration.
Understanding Storage Spaces Components
Storage Spaces works with several key concepts. A Storage Pool is a collection of physical disks (primordial pool) combined into a single managed resource. Virtual Disks (Storage Spaces) are created from the pool with configurable resiliency. Simple spaces stripe data across drives (like RAID 0) with no redundancy. Mirror spaces write copies of data to multiple drives (like RAID 1 or RAID 10). Parity spaces store data with parity information distributed across drives (like RAID 5/6). Tiers allow mixing SSD and HDD in the same pool, with frequently accessed data on SSDs.
Creating a Storage Pool
# View all available physical disks
Get-PhysicalDisk | Select-Object FriendlyName, Size, BusType, MediaType, CanPool, OperationalStatus
# View disks that can be added to a pool
Get-PhysicalDisk -CanPool $true
# Create a storage pool using all available (poolable) disks
$disks = Get-PhysicalDisk -CanPool $true
$subsystem = Get-StorageSubSystem
New-StoragePool `
-FriendlyName "DataPool" `
-StorageSubSystemFriendlyName $subsystem.FriendlyName `
-PhysicalDisks $disks
# Alternatively, specify specific disks by serial number or friendly name
$disk1 = Get-PhysicalDisk -FriendlyName "PhysicalDisk1"
$disk2 = Get-PhysicalDisk -FriendlyName "PhysicalDisk2"
$disk3 = Get-PhysicalDisk -FriendlyName "PhysicalDisk3"
$disk4 = Get-PhysicalDisk -FriendlyName "PhysicalDisk4"
New-StoragePool `
-FriendlyName "DataPool" `
-StorageSubSystemFriendlyName $subsystem.FriendlyName `
-PhysicalDisks @($disk1, $disk2, $disk3, $disk4)
# Verify the pool
Get-StoragePool -FriendlyName "DataPool" | Select-Object FriendlyName, Size, AllocatedSize, IsReadOnly
Creating Virtual Disks (Storage Spaces)
Create virtual disks from the pool with the appropriate resiliency level. Choose based on your balance between performance, capacity, and redundancy:
# Create a Two-Way Mirror virtual disk (requires 2+ disks, survives 1 disk failure)
New-VirtualDisk `
-StoragePoolFriendlyName "DataPool" `
-FriendlyName "Mirror-Data" `
-ResiliencySettingName Mirror `
-NumberOfDataCopies 2 `
-Size 1TB `
-ProvisioningType Thin
# Create a Three-Way Mirror (requires 5+ disks, survives 2 disk failures)
New-VirtualDisk `
-StoragePoolFriendlyName "DataPool" `
-FriendlyName "Mirror3-Critical" `
-ResiliencySettingName Mirror `
-NumberOfDataCopies 3 `
-Size 500GB `
-ProvisioningType Fixed
# Create a Parity virtual disk (requires 3+ disks, like RAID 5, space-efficient)
New-VirtualDisk `
-StoragePoolFriendlyName "DataPool" `
-FriendlyName "Parity-Archive" `
-ResiliencySettingName Parity `
-NumberOfColumns 3 `
-Size 2TB `
-ProvisioningType Thin
# Create a Simple (striped) virtual disk (no redundancy, maximum performance)
New-VirtualDisk `
-StoragePoolFriendlyName "DataPool" `
-FriendlyName "Striped-Temp" `
-ResiliencySettingName Simple `
-NumberOfColumns 4 `
-Size 500GB `
-ProvisioningType Thin
Initializing and Formatting Virtual Disks
After creating a virtual disk, it must be initialized, partitioned, and formatted before use:
# Get the disk number of the new virtual disk
Get-VirtualDisk -FriendlyName "Mirror-Data" | Get-Disk
# Initialize the disk with GPT partition table
$disk = Get-VirtualDisk -FriendlyName "Mirror-Data" | Get-Disk
Initialize-Disk -Number $disk.Number -PartitionStyle GPT
# Create a partition
$partition = New-Partition -DiskNumber $disk.Number -UseMaximumSize -AssignDriveLetter
# Format the volume with NTFS (use ReFS for large volumes with data integrity focus)
Format-Volume `
-DriveLetter $partition.DriveLetter `
-FileSystem NTFS `
-AllocationUnitSize 65536 `
-NewFileSystemLabel "MirrorData" `
-Confirm:$false
# Verify
Get-Volume -DriveLetter $partition.DriveLetter
Configuring Storage Tiers (SSD + HDD)
Storage Tiers automatically move frequently accessed data to faster SSD storage and less-accessed data to slower HDD storage. This provides SSD-like performance for hot data at HDD cost per GB:
# Create a pool with mixed SSD and HDD disks
$ssdDisks = Get-PhysicalDisk -CanPool $true | Where-Object {$_.MediaType -eq "SSD"}
$hddDisks = Get-PhysicalDisk -CanPool $true | Where-Object {$_.MediaType -eq "HDD"}
$allDisks = $ssdDisks + $hddDisks
New-StoragePool `
-FriendlyName "TieredPool" `
-StorageSubSystemFriendlyName (Get-StorageSubSystem).FriendlyName `
-PhysicalDisks $allDisks
# Create storage tiers in the pool
New-StorageTier `
-StoragePoolFriendlyName "TieredPool" `
-FriendlyName "SSD-Tier" `
-MediaType SSD `
-ResiliencySettingName Mirror
New-StorageTier `
-StoragePoolFriendlyName "TieredPool" `
-FriendlyName "HDD-Tier" `
-MediaType HDD `
-ResiliencySettingName Mirror
# Create a tiered virtual disk
$ssdTier = Get-StorageTier -FriendlyName "SSD-Tier"
$hddTier = Get-StorageTier -FriendlyName "HDD-Tier"
New-VirtualDisk `
-StoragePoolFriendlyName "TieredPool" `
-FriendlyName "TieredVolume" `
-StorageTiers @($ssdTier, $hddTier) `
-StorageTierSizes @(50GB, 500GB) `
-ResiliencySettingName Mirror `
-WriteCacheSize 1GB
Managing Hot Spares
Hot spare disks are reserved disks that automatically replace a failed disk. Configure at least one hot spare in production storage pools:
# Add a disk to the pool as a hot spare
$sparedisk = Get-PhysicalDisk -FriendlyName "PhysicalDisk5"
Add-PhysicalDisk -StoragePoolFriendlyName "DataPool" -PhysicalDisks $sparedisk
Set-PhysicalDisk -FriendlyName "PhysicalDisk5" -Usage HotSpare
# View disk usage assignments in the pool
Get-PhysicalDisk -StoragePool (Get-StoragePool -FriendlyName "DataPool") | `
Select-Object FriendlyName, Usage, OperationalStatus, HealthStatus, Size
Adding Disks to an Existing Pool
Storage pools can be expanded by adding new physical disks. Existing virtual disks can then be extended to use the additional capacity:
# Add a new disk to an existing pool
$newDisk = Get-PhysicalDisk -FriendlyName "PhysicalDisk6"
Add-PhysicalDisk `
-StoragePoolFriendlyName "DataPool" `
-PhysicalDisks $newDisk
# Extend a virtual disk to use additional pool capacity
Resize-VirtualDisk -FriendlyName "Mirror-Data" -Size 2TB
# Extend the partition after resizing the virtual disk
$partition = Get-VirtualDisk -FriendlyName "Mirror-Data" | Get-Disk | Get-Partition | Where-Object {$_.Type -eq "Basic"}
Resize-Partition -DiskNumber $partition.DiskNumber -PartitionNumber $partition.PartitionNumber -Size (Get-PartitionSupportedSize -DiskNumber $partition.DiskNumber -PartitionNumber $partition.PartitionNumber).SizeMax
Monitoring Storage Pool Health
# Check overall health of storage pools and virtual disks
Get-StoragePool | Select-Object FriendlyName, HealthStatus, OperationalStatus, Size, AllocatedSize
Get-VirtualDisk | Select-Object FriendlyName, HealthStatus, OperationalStatus, ResiliencySettingName, Size
Get-PhysicalDisk | Select-Object FriendlyName, HealthStatus, OperationalStatus, Usage, Size
# View storage pool events
Get-WinEvent -LogName "Microsoft-Windows-StorageSpaces-Driver/Operational" -MaxEvents 30
# Check for failed or degraded disks
Get-PhysicalDisk | Where-Object {$_.HealthStatus -ne "Healthy" -or $_.OperationalStatus -ne "OK"}
# Run a repair job on a degraded virtual disk
Repair-VirtualDisk -FriendlyName "Mirror-Data"
# Get disk wear indicators for SSDs in the pool
Get-PhysicalDisk | Where-Object {$_.MediaType -eq "SSD"} | Get-StorageReliabilityCounter | `
Select-Object DeviceId, Wear, Temperature
Storage Spaces provides a flexible, cost-effective storage solution for Windows Server 2019. For business-critical workloads, use three-way mirror resiliency and implement a regular backup strategy, as Storage Spaces protects against drive failure but not against accidental deletion, ransomware, or catastrophic events affecting all disks simultaneously.