Private/SKU/Test-SkuCompatibility.ps1
|
function Test-SkuCompatibility { <# .SYNOPSIS Tests whether a candidate SKU can fully replace a target SKU. .DESCRIPTION Performs hard compatibility checks across critical VM dimensions: vCPU, memory, NICs, accelerated networking, premium IO, disk interface (NVMe/SCSI), ephemeral OS disk, and Ultra SSD. Returns pass/fail with a list of failures. This is a pre-filter before similarity scoring — only candidates that pass all checks should be scored and recommended. #> param( [Parameter(Mandatory)][hashtable]$Target, [Parameter(Mandatory)][hashtable]$Candidate ) $failures = [System.Collections.Generic.List[string]]::new() # Category gate: burstable (B-series) candidates cannot replace non-burstable targets $targetFamily = if ($Target.Family) { $Target.Family } elseif ($Target.Name) { if ($Target.Name -match 'Standard_([A-Z]+)\d') { $matches[1] } else { '' } } else { '' } $candidateFamily = if ($Candidate.Family) { $Candidate.Family } elseif ($Candidate.Name) { if ($Candidate.Name -match 'Standard_([A-Z]+)\d') { $matches[1] } else { '' } } else { '' } if ($candidateFamily -eq 'B' -and $targetFamily -ne 'B') { $failures.Add("Category: burstable (B-series) cannot replace non-burstable ($targetFamily-series)") } # vCPU: candidate must meet or exceed target if ($Candidate.vCPU -gt 0 -and $Target.vCPU -gt 0 -and $Candidate.vCPU -lt $Target.vCPU) { $failures.Add("vCPU: candidate $($Candidate.vCPU) < target $($Target.vCPU)") } # vCPU ceiling: candidate must not exceed 2x target (prevents licensing-impacting core count jumps) if ($Candidate.vCPU -gt 0 -and $Target.vCPU -gt 0 -and $Candidate.vCPU -gt ($Target.vCPU * 2)) { $failures.Add("vCPU: candidate $($Candidate.vCPU) exceeds 2x target $($Target.vCPU) (licensing risk)") } # Memory: candidate must meet or exceed target if ($Candidate.MemoryGB -gt 0 -and $Target.MemoryGB -gt 0 -and $Candidate.MemoryGB -lt $Target.MemoryGB) { $failures.Add("MemoryGB: candidate $($Candidate.MemoryGB) < target $($Target.MemoryGB)") } # Max NICs: candidate must support at least as many if ($Target.MaxNetworkInterfaces -gt 1 -and $Candidate.MaxNetworkInterfaces -lt $Target.MaxNetworkInterfaces) { $failures.Add("MaxNICs: candidate $($Candidate.MaxNetworkInterfaces) < target $($Target.MaxNetworkInterfaces)") } # Accelerated networking: if target has it, candidate must too if ($Target.AccelNet -eq $true -and $Candidate.AccelNet -ne $true) { $failures.Add("AcceleratedNetworking: target requires it, candidate lacks it") } # Premium IO: if target requires premium, candidate must support it if ($Target.PremiumIO -eq $true -and $Candidate.PremiumIO -ne $true) { $failures.Add("PremiumIO: target requires it, candidate lacks it") } # Disk interface: NVMe target requires NVMe candidate if ($Target.DiskCode -match 'NV' -and $Candidate.DiskCode -notmatch 'NV') { $failures.Add("DiskInterface: target uses NVMe, candidate only has SCSI") } # Ephemeral OS disk: if target uses it, candidate must support it if ($Target.EphemeralOSDiskSupported -eq $true -and $Candidate.EphemeralOSDiskSupported -ne $true) { $failures.Add("EphemeralOSDisk: target requires it, candidate lacks it") } # Ultra SSD: if target uses it, candidate must support it if ($Target.UltraSSDAvailable -eq $true -and $Candidate.UltraSSDAvailable -ne $true) { $failures.Add("UltraSSD: target requires it, candidate lacks it") } return @{ Compatible = ($failures.Count -eq 0) Failures = @($failures) } } |