public/Stop-UnraidArray.ps1

function Stop-UnraidArray {
    <#
    .SYNOPSIS
        Stops the Unraid array.

    .DESCRIPTION
        Initiates a stop of the Unraid array.
        Handles API reporting lag where state remains STARTED despite stop command.

    .PARAMETER Array
        An object representing the current array state.

    .PARAMETER Session
        The active Unraid session.

    .PARAMETER WaitTimeout
        Seconds to wait for the array to stop - default is 600.

    .PARAMETER Force
        Sends the stop command even if the API reports the array is already stopped.
    
    .EXAMPLE
        Stop-UnraidArray -Force
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType('void')]
    param(
        [Parameter(ValueFromPipeline)]
        [psobject]$Array,

        [Parameter()]
        [UnraidSession]$Session = $script:DefaultUnraidSession,

        [Parameter()]
        [int]$WaitTimeout = 600,

        [Parameter()]
        [switch]$Force
    )

    process {
        if (!$Array) {
            Write-Verbose "Checking status..."
            $Array = Get-UnraidArray -Session $Session
        }

        if ($Array.State -eq "STOPPED" -and !$Force) {
            Write-Warning "Array is already stopped. Use -Force to override."
            return
        }

        if ($PSCmdlet.ShouldProcess("Unraid Array", "Stop array")) {
            
            $gqlQuery = @"
            mutation SetArrayState {
                array {
                    setState(input: { desiredState: STOP }) {
                        state
                    }
                }
            }
"@

            $commandSent = $false

            try {
                Write-Verbose "Sending stop command..."
                $result = Invoke-UnraidQuery -Query $gqlQuery -Session $Session
                
                $commandSent = $true
                $currentState = $result.array.setState.state
            }
            catch {
                $ex = $_.Exception
                
                # Check for "already stopped"
                if ($ex.Message -match "already STOPPED") {
                    Write-Information "Array is already STOPPED." -InformationAction Continue
                    return
                }
                
                # The API seems to return 504 timeouts pretty often when stopping the array
                # This happenes regardless of a failure or success - so don't neccessary treat it as an error
                elseif ($ex.Message -match "504" -or ($ex.Response -and $ex.Response.StatusCode -eq 504)) {
                    Write-Warning "Server timed out (504) waiting for disks to unmount. Starting timer-based stop monitoring..."
                    $commandSent = $true
                    $currentState = "UNKNOWN"
                }
                else { $PSCmdlet.ThrowTerminatingError($_) }
            }

            if ($commandSent) {
                $timer = [System.Diagnostics.Stopwatch]::StartNew()
                
                while ($currentState -ne "STOPPED" -and $timer.Elapsed.TotalSeconds -lt $WaitTimeout) {
                    $remaining = $WaitTimeout - [int]$timer.Elapsed.TotalSeconds
                    Write-Progress -Activity "Stopping Unraid Array" -Status "Current State: $currentState" -SecondsRemaining $remaining
                    
                    Start-Sleep -Seconds 5
                    
                    try {
                        $statusCheck = Get-UnraidArray -Session $Session
                        $currentState = $statusCheck.State
                        
                        # If we see the specialized Unmounted state, it might mean the Stop worked partially?
                        if ($statusCheck.State -like "*UNMOUNTED*") {
                            $currentState = "STOPPING (API UNSYNCED)" 
                        }
                    }
                    catch {
                        Write-Verbose "Poll failed: $($_.Exception.Message)"
                    }
                }
                
                $timer.Stop()
                Write-Progress -Activity "Stopping Unraid Array" -Completed

                if ($currentState -eq "STOPPED") {
                    Write-Information "Array stopped." -InformationAction Continue
                }
                else {
                    # Likely that the command worked, but the API didn't update?
                    Write-Warning "Timed out waiting for state update. The Stop command was sent and likely succeeded, but the API is still reporting $($currentState).`nThe API is likely not synced to the current server state. You likely need to run 'Restart-UnraidApi' to reset the state, then rerun this command or Get-UnraidArray to verify status."
                }
            }
        }
    }
}