Modules/Public/Get-S2DVolumeMap.ps1
|
function Get-S2DVolumeMap { <# .SYNOPSIS Maps all S2D volumes with resiliency type, capacity footprint, and provisioning detail. .DESCRIPTION Queries VirtualDisk and ClusterSharedVolume. Returns per-volume resiliency efficiency, footprint, provisioning type, overcommit ratio for thin volumes, and auto-detects the Azure Local infrastructure volume by name/size pattern. Requires an active session established with Connect-S2DCluster, or pass -CimSession directly. .PARAMETER VolumeName Limit results to one or more specific volume friendly names. .PARAMETER CimSession Override the module session and target this CimSession directly. .EXAMPLE Get-S2DVolumeMap .EXAMPLE Get-S2DVolumeMap | Format-Table FriendlyName, ResiliencySettingName, Size, EfficiencyPercent .OUTPUTS S2DVolume[] #> [CmdletBinding()] [OutputType([S2DVolume])] param( [Parameter()] [string[]] $VolumeName, [Parameter()] [CimSession] $CimSession ) $usePSSession = -not $PSBoundParameters.ContainsKey('CimSession') -and -not $Script:S2DSession.IsLocal -and $null -ne $Script:S2DSession.PSSession $session = if ($usePSSession) { $null } else { Resolve-S2DSession -CimSession $CimSession } $nodeCount = if ($Script:S2DSession.Nodes.Count -gt 0) { $Script:S2DSession.Nodes.Count } else { 3 } # ── Collect raw virtual disks ───────────────────────────────────────────── $vdisks = @() if ($usePSSession) { $vdisks = @(Invoke-Command -Session $Script:S2DSession.PSSession -ScriptBlock { @(Get-VirtualDisk -ErrorAction SilentlyContinue) }) } else { $vdisks = @(if ($session) { Get-S2DVirtualDiskData -CimSession $session } else { Get-S2DVirtualDiskData }) } if (-not $vdisks) { Write-Warning "No virtual disks found." return } # ── Build volume objects ────────────────────────────────────────────────── $result = @($vdisks | ForEach-Object { $vd = $_ $resiliencyName = try { [string]$vd.ResiliencySettingName } catch { 'Mirror' } $dataCopies = try { [int]$vd.NumberOfDataCopies } catch { 2 } $diskRedundancy = try { [int]$vd.PhysicalDiskRedundancy } catch { 2 } $provType = try { [string]$vd.ProvisioningType } catch { 'Fixed' } $safeResiliency = if ($resiliencyName -in 'Mirror', 'Parity') { $resiliencyName } else { 'Mirror' } $effResult = Get-S2DResiliencyEfficiency ` -ResiliencySettingName $safeResiliency ` -NumberOfDataCopies $dataCopies ` -PhysicalDiskRedundancy $diskRedundancy ` -NodeCount $nodeCount $sizeBytes = [int64]$vd.Size $footprintBytes = try { [int64]$vd.FootprintOnPool } catch { [int64]0 } $allocatedBytes = try { [int64]$vd.AllocatedSize } catch { [int64]0 } $overcommitRatio = if ($footprintBytes -gt 0 -and $allocatedBytes -gt $footprintBytes) { [math]::Round($allocatedBytes / $footprintBytes, 3) } else { 1.0 } $isInfra = Get-S2DInfraVolumeFlag -FriendlyName $vd.FriendlyName -SizeBytes $sizeBytes $vol = [S2DVolume]::new() $vol.FriendlyName = $vd.FriendlyName $vol.FileSystem = try { [string]$vd.FileSystem } catch { 'Unknown' } $vol.ResiliencySettingName = $resiliencyName $vol.NumberOfDataCopies = $dataCopies $vol.PhysicalDiskRedundancy = $diskRedundancy $vol.ProvisioningType = $provType $vol.Size = if ($sizeBytes -gt 0) { [S2DCapacity]::new($sizeBytes) } else { $null } $vol.FootprintOnPool = if ($footprintBytes -gt 0) { [S2DCapacity]::new($footprintBytes) } else { $null } $vol.AllocatedSize = if ($allocatedBytes -gt 0) { [S2DCapacity]::new($allocatedBytes) } else { $null } $vol.OperationalStatus = try { [string]$vd.OperationalStatus } catch { 'Unknown' } $vol.HealthStatus = try { [string]$vd.HealthStatus } catch { 'Unknown' } $vol.IsDeduplicationEnabled = $false $vol.IsInfrastructureVolume = $isInfra $vol.EfficiencyPercent = $effResult.EfficiencyPercent $vol.OvercommitRatio = $overcommitRatio $vol }) $Script:S2DSession.CollectedData['Volumes'] = $result if ($VolumeName) { $result = @($result | Where-Object { $_.FriendlyName -in $VolumeName }) } $result } function Get-S2DInfraVolumeFlag { param([string]$FriendlyName, [int64]$SizeBytes) # Azure Local infrastructure volume name patterns $infraPatterns = @( '^Infrastructure_[0-9a-f-]+$', '^ClusterPerformanceHistory$', 'infra', 'infrastructure' ) foreach ($pattern in $infraPatterns) { if ($FriendlyName -imatch $pattern) { return $true } } # Size heuristic: < 600 GiB and non-zero is likely an infra volume if ($SizeBytes -gt 0 -and $SizeBytes -lt 644245094400) { return $true } return $false } |