Public/Start-AnyStackHostEvacuation.ps1

function Start-AnyStackHostEvacuation {
    <#
    .SYNOPSIS
        Safely automates host evacuations via Maintenance Mode for vSphere clusters.
 
    .DESCRIPTION
        Initiates DRS-based VM evacuation and vSAN data migration protocols for designated hosts.
        Uses Get-View for direct API execution, ensuring speed and reliability during tight maintenance windows.
 
    .PARAMETER Server
        VIServer connection object.
 
    .PARAMETER HostName
        Array of ESXi hostnames to evacuate.
 
    .PARAMETER VsanMode
        vSAN data evacuation mode: 'ensureObjectAccessibility' (default) or 'evacuateAllData'.
 
    .PARAMETER TimeoutSeconds
        Maximum time to wait for the maintenance task to complete before throwing an error.
 
    .EXAMPLE
        Start-AnyStackHostEvacuation -Server $vc -HostName "esx01.anystack.local" -VsanMode "evacuateAllData"
    #>

    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        [Parameter(Mandatory=$true)]
        $Server,

        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string[]]$HostName,

        [Parameter(Mandatory=$false)]
        [ValidateSet('ensureObjectAccessibility', 'evacuateAllData', 'noAction')]
        [string]$VsanMode = 'ensureObjectAccessibility',

        [Parameter(Mandatory=$false)]
        [int]$TimeoutSeconds = 3600
    )

    process {
        $ErrorActionPreference = 'Stop'
        foreach ($h in $HostName) {
            Write-Verbose "Evaluating Maintenance Mode for Host: $h"
            
            try {
                $hostView = Get-View -Server $Server -ViewType HostSystem -Filter @{"Name"="^$h$"} -Property Name,Runtime -ErrorAction Stop
                
                if (-not $hostView) {
                    Write-Warning "Host $h not found on server."
                    continue
                }

                if ($hostView.Runtime.InMaintenanceMode) {
                    Write-Verbose "Host $h is already in Maintenance Mode."
                    continue
                }

                if ($PSCmdlet.ShouldProcess($h, "Enter Maintenance Mode (vSAN: $VsanMode)")) {
                    
                    # Construct Maintenance Spec
                    $spec = New-Object VMware.Vim.HostMaintenanceSpec
                    $spec.VsanMode = New-Object VMware.Vim.VsanHostDecommissionMode
                    $spec.VsanMode.ObjectAction = $VsanMode

                    Write-Host "Initiating evacuation for $h..." -ForegroundColor Cyan
                    
                    # API Call: EnterMaintenanceMode_Task(timeout, evacuatePoweredOffVms, spec)
                    $taskRef = $hostView.EnterMaintenanceMode_Task($TimeoutSeconds, $true, $spec)
                    
                    # Return Task object
                    [PSCustomObject]@{
                        Host         = $h
                        Status       = "Evacuation Started"
                        VsanMode     = $VsanMode
                        TaskID       = $taskRef.Value
                        Timestamp    = (Get-Date)
                    }
                }
            }
            catch {
                Write-Error "Failed to initiate evacuation for $h : $($_.Exception.Message)"
            }
        }
    }
}