Public/VM/Stop-VergeVM.ps1
|
function Stop-VergeVM { <# .SYNOPSIS Powers off a VergeOS virtual machine. .DESCRIPTION Stop-VergeVM sends a power off command to one or more virtual machines. By default, a graceful shutdown is performed (ACPI power button). Use -Force to immediately terminate the VM without graceful shutdown. .PARAMETER Name The name of the VM to stop. Supports wildcards (* and ?). .PARAMETER Key The unique key (ID) of the VM to stop. .PARAMETER VM A VM object from Get-VergeVM. Accepts pipeline input. .PARAMETER Force Immediately terminate the VM without graceful shutdown (kill power). Use this when the guest OS is unresponsive. .PARAMETER PassThru Return the VM object after stopping. By default, no output is returned. .PARAMETER Server The VergeOS connection to use. Defaults to the current default connection. .EXAMPLE Stop-VergeVM -Name "WebServer01" Gracefully shuts down the VM named "WebServer01". .EXAMPLE Stop-VergeVM -Name "WebServer01" -Force Immediately terminates the VM without graceful shutdown. .EXAMPLE Get-VergeVM -PowerState Running | Stop-VergeVM Gracefully shuts down all running VMs. .EXAMPLE Stop-VergeVM -Name "Test*" -Force -Confirm:$false Immediately terminates all VMs starting with "Test" without confirmation. .EXAMPLE Get-VergeVM -Name "Prod-*" -PowerState Running | Stop-VergeVM -PassThru Gracefully shuts down production VMs and returns their updated state. .OUTPUTS None by default. Verge.VM when -PassThru is specified. .NOTES Use Start-VergeVM to power on VMs. Use -Force when the guest OS is unresponsive (equivalent to pulling the power cord). #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High', DefaultParameterSetName = 'ByName')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByName')] [SupportsWildcards()] [string]$Name, [Parameter(Mandatory, ParameterSetName = 'ByKey')] [int]$Key, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'ByVM')] [PSTypeName('Verge.VM')] [PSCustomObject]$VM, [Parameter()] [switch]$Force, [Parameter()] [switch]$PassThru, [Parameter()] [object]$Server ) begin { # Resolve connection if (-not $Server) { $Server = $script:DefaultConnection } if (-not $Server) { throw [System.InvalidOperationException]::new( 'Not connected to VergeOS. Use Connect-VergeOS to establish a connection.' ) } } process { # Get VMs to stop based on parameter set $vmsToStop = switch ($PSCmdlet.ParameterSetName) { 'ByName' { Get-VergeVM -Name $Name -Server $Server } 'ByKey' { Get-VergeVM -Key $Key -Server $Server } 'ByVM' { $VM } } foreach ($targetVM in $vmsToStop) { if (-not $targetVM) { continue } # Check if VM is a snapshot if ($targetVM.IsSnapshot) { Write-Error -Message "Cannot stop VM '$($targetVM.Name)': VM is a snapshot" -ErrorId 'CannotStopSnapshot' continue } # Check if already stopped if ($targetVM.PowerState -eq 'Stopped') { Write-Warning "VM '$($targetVM.Name)' is already stopped." if ($PassThru) { Write-Output $targetVM } continue } # Determine action type $action = if ($Force) { 'kill' } else { 'poweroff' } $actionVerb = if ($Force) { 'Force stop (kill)' } else { 'Gracefully stop' } # Build action body $body = @{ vm = $targetVM.Key action = $action } # Confirm action if ($PSCmdlet.ShouldProcess($targetVM.Name, "$actionVerb VM")) { try { Write-Verbose "$actionVerb VM '$($targetVM.Name)' (Key: $($targetVM.Key))" $response = Invoke-VergeAPI -Method POST -Endpoint 'vm_actions' -Body $body -Connection $Server Write-Verbose "Power off command sent for VM '$($targetVM.Name)'" if ($PassThru) { # Return refreshed VM object Start-Sleep -Milliseconds 500 Get-VergeVM -Key $targetVM.Key -Server $Server } } catch { Write-Error -Message "Failed to stop VM '$($targetVM.Name)': $($_.Exception.Message)" -ErrorId 'VMStopFailed' } } } } } |