Functions/Public/AutomationOverrides.ps1
|
$script:HvDRSDefaultAutomationOverridesPath = Join-Path (Get-HvDRSDataRoot) 'HvDRS\automation-overrides.json' function Set-HvDRSVMAutomationLevel { <# .SYNOPSIS Pins a specific VM to Manual automation, or restores it to FullyAutomated — the per-VM automation-level override vSphere DRS exposes, applied to both Invoke-HvDRS and Invoke-HvStorageDRS (automation level isn't a compute-vs- storage distinction in vSphere either — it's one setting per VM). .DESCRIPTION FullyAutomated (the default for every VM with no override) means HVDRS may execute a migration it recommends for this VM, same as today. Manual means HVDRS still scores this VM and includes it in the printed/ -PassThru recommendation list — it just never calls Move-ClusterVirtualMachineRole / Move-VMStorage for it. The recommendation is annotated as pinned so an operator knows to review and act on it by hand. .PARAMETER ClusterName Failover Cluster this override applies to. Defaults to the local cluster if omitted. .PARAMETER VMName The VM to pin. .PARAMETER AutomationLevel FullyAutomated or Manual. .PARAMETER Reason Optional free-text reason stored with the override. .PARAMETER OverridesPath Path to the JSON override store. Defaults to $env:ProgramData\HvDRS\automation-overrides.json. .EXAMPLE Set-HvDRSVMAutomationLevel -ClusterName 'PROD-CLUSTER' -VMName 'SQL-PROD-01' -AutomationLevel Manual -Reason 'Change-managed workload' #> [CmdletBinding(SupportsShouldProcess)] param( [string]$ClusterName = '', [Parameter(Mandatory)] [string]$VMName, [Parameter(Mandatory)] [ValidateSet('FullyAutomated', 'Manual')] [string]$AutomationLevel, [string]$Reason = '', [string]$OverridesPath = $script:HvDRSDefaultAutomationOverridesPath ) if (-not $ClusterName) { try { $ClusterName = (Get-Cluster -ErrorAction Stop).Name } catch { throw "No -ClusterName specified and no local cluster detected. $_" } } if (-not $PSCmdlet.ShouldProcess($VMName, "Set HvDRS automation level to '$AutomationLevel' for cluster '$ClusterName'")) { return } $overrides = [System.Collections.Generic.List[PSCustomObject]](Get-HvDRSAutomationOverrideSet -Path $OverridesPath) $existing = $overrides | Where-Object { $_.ClusterName -eq $ClusterName -and $_.VMName -eq $VMName } if ($existing) { $existing.AutomationLevel = $AutomationLevel $existing.Reason = $Reason Write-Host "Automation level for '$VMName' on cluster '$ClusterName' updated to '$AutomationLevel'." } else { $overrides.Add([PSCustomObject]@{ ClusterName = $ClusterName VMName = $VMName AutomationLevel = $AutomationLevel Reason = $Reason CreatedAt = (Get-Date -Format 'o') }) Write-Host "Automation level for '$VMName' on cluster '$ClusterName' set to '$AutomationLevel'." } Save-HvDRSAutomationOverrideSet -Overrides $overrides.ToArray() -Path $OverridesPath } function Get-HvDRSVMAutomationLevel { <# .SYNOPSIS Lists per-VM automation-level overrides, with optional filtering. .PARAMETER ClusterName When specified, returns only overrides for this cluster. .PARAMETER VMName Return only the override for this VM. .PARAMETER OverridesPath Path to the JSON override store. #> [CmdletBinding()] param( [string]$ClusterName = '', [string]$VMName, [string]$OverridesPath = $script:HvDRSDefaultAutomationOverridesPath ) $overrides = Get-HvDRSAutomationOverrideSet -Path $OverridesPath -ClusterName $ClusterName if ($VMName) { $matched = @($overrides | Where-Object { $_.VMName -eq $VMName }) if ($matched.Count -eq 0) { return ,@() } return $matched } # Same leading-comma-on-empty-only protection as Get-AffinityRuleSet — see # its comments for why this must not be applied unconditionally. if (@($overrides).Count -eq 0) { return ,@() } return $overrides } function Remove-HvDRSVMAutomationLevel { <# .SYNOPSIS Removes a VM's automation-level override, reverting it to FullyAutomated (the default for any VM with no override). .PARAMETER ClusterName Failover Cluster the override applies to. Defaults to the local cluster if omitted. .PARAMETER VMName The VM whose override should be removed. .PARAMETER OverridesPath Path to the JSON override store. #> [CmdletBinding(SupportsShouldProcess)] param( [string]$ClusterName = '', [Parameter(Mandatory)] [string]$VMName, [string]$OverridesPath = $script:HvDRSDefaultAutomationOverridesPath ) if (-not $ClusterName) { try { $ClusterName = (Get-Cluster -ErrorAction Stop).Name } catch { throw "No -ClusterName specified and no local cluster detected. $_" } } $overrides = [System.Collections.Generic.List[PSCustomObject]](Get-HvDRSAutomationOverrideSet -Path $OverridesPath) $target = $overrides | Where-Object { $_.ClusterName -eq $ClusterName -and $_.VMName -eq $VMName } if (-not $target) { Write-Warning "No automation override found for '$VMName' on cluster '$ClusterName'." return } if (-not $PSCmdlet.ShouldProcess($VMName, 'Remove HvDRS automation-level override')) { return } [void]$overrides.Remove($target) Save-HvDRSAutomationOverrideSet -Overrides $overrides.ToArray() -Path $OverridesPath Write-Host "Automation-level override for '$VMName' removed — it now inherits the default (FullyAutomated)." } |