public/Restart-UnraidContainer.ps1

function Restart-UnraidContainer {
    <#
    .SYNOPSIS
        Restarts a container.

    .PARAMETER InputObject
        Container to restart (accepts pipeline).

    .PARAMETER Name
        Container name.

    .PARAMETER TimeoutSeconds
        Stop timeout (default 300 seconds).

    .PARAMETER Batch
        Send restart commands to all containers in the batch, then wait for completion (faster for multiple containers).

    .PARAMETER Session
        Unraid session (defaults to current session).

    .EXAMPLE
        Restart-UnraidContainer -Name "plex"

    .EXAMPLE
        Get-UnraidContainer -Name "*arr" | Restart-UnraidContainer -Batch
    #>

    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "ByName")]
    [OutputType('void')]
    param(
        [Parameter(Mandatory, ParameterSetName = "ByObject", ValueFromPipeline)]
        [UnraidContainer[]]$InputObject,

        [Parameter(Mandatory, ParameterSetName = "ByName", Position = 0)]
        [string]$Name,

        [Parameter()]
        [int]$TimeoutSeconds = 300,

        [Parameter()]
        [switch]$Batch,

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

    begin {
        if ($Batch) {
            $ContainersToRestart = [System.Collections.Generic.List[UnraidContainer]]::new()
        }
    }

    process {
        $containers = Resolve-UnraidContainer -InputObject $InputObject -Name $Name -ParameterSetName $PSCmdlet.ParameterSetName -Session $Session
        if (!$containers) { return }

        if ($Batch) {
            foreach ($container in $containers) {
                $ContainersToRestart.Add($container)
            }
        }
        else {
            foreach ($targetContainer in $containers) {
                if ($PSCmdlet.ShouldProcess($targetContainer.Name, "Restart Container")) {
                    try {
                        if ($targetContainer.State -eq "running") {
                            Write-Verbose "Stopping container: $($targetContainer.Name)"

                            $stopQuery = "mutation { docker { stop(id: `"$($targetContainer.Id)`") { id } } }"
                            Invoke-UnraidQuery -Query $stopQuery -Session $Session  | Out-Null
                            
                            $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
                            $stopped = $false
                            
                            while ($stopwatch.Elapsed.TotalSeconds -lt $TimeoutSeconds) {
                                Start-Sleep -Seconds 1
                                $statusCheck = Get-UnraidContainer -Name $targetContainer.Name -Session $Session

                                if ($statusCheck.State -eq "exited") {
                                    Write-Verbose "Container stopped successfully."
                                    $stopped = $true
                                    break
                                }
                            }
                            
                            $stopwatch.Stop()
                            
                            if (!$stopped) {
                                throw "Container '$($targetContainer.Name)' did not stop within $TimeoutSeconds seconds."
                            }
                        }

                        Write-Verbose "Starting container: $($targetContainer.Name)"

                        $startQuery = "mutation { docker { start(id: `"$($targetContainer.Id)`") { id } } }"
                        Invoke-UnraidQuery -Query $startQuery -Session $Session | Out-Null

                        Write-Information "Container restarted: $($targetContainer.Name)" -InformationAction Continue
                    }
                    catch {
                        $PSCmdlet.WriteError($_)
                    }
                }
            }
        }
    }

    end {
        if ($Batch -and $ContainersToRestart.Count -gt 0) {
            Write-Verbose "Bulk restarting $($ContainersToRestart.Count) containers"
            
            $containersToStop = @()
            
            foreach ($targetContainer in $ContainersToRestart) {
                if ($PSCmdlet.ShouldProcess($targetContainer.Name, "Restart Container")) {
                    try {
                        if ($targetContainer.State -eq "running") {
                            Write-Verbose "Stopping container: $($targetContainer.Name)"
                            $stopQuery = "mutation { docker { stop(id: `"$($targetContainer.Id)`") { id } } }"
                            Invoke-UnraidQuery -Query $stopQuery -Session $Session | Out-Null
                            $containersToStop += $targetContainer
                        }
                    }
                    catch {  $PSCmdlet.WriteError($_) }
                }
            }
            
            if ($containersToStop.Count -gt 0) {
                Write-Verbose "Waiting for $($containersToStop.Count) containers to stop..."
                $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
                $stoppedContainers = @{}
                
                while ($stopwatch.Elapsed.TotalSeconds -lt $TimeoutSeconds -and $stoppedContainers.Count -lt $containersToStop.Count) {
                    Start-Sleep -Seconds 1
                    
                    # Fetch once per iteration instead of N times to avoid hammering the API
                    $allContainers = Get-UnraidContainer -Session $Session
                    
                    # Use hashtable so we can check each container's state without repeated lookups
                    $containersByName = @{}
                    foreach ($containerToName in $allContainers) {
                        $containersByName[$containerToName.Name] = $containerToName
                    }
                    
                    foreach ($container in $containersToStop) {
                        if (!$stoppedContainers.ContainsKey($container.Name)) {
                            if ($containersByName.ContainsKey($container.Name) -and $containersByName[$container.Name].State -eq "exited") {
                                Write-Verbose "Container stopped: $($container.Name)"
                                $stoppedContainers[$container.Name] = $true
                            }
                        }
                    }
                }
                
                $stopwatch.Stop()
                
                foreach ($container in $containersToStop) {
                    if (!$stoppedContainers.ContainsKey($container.Name)) {
                        Write-Warning "Container '$($container.Name)' did not stop within $TimeoutSeconds seconds."
                    }
                }
            }
            
            foreach ($targetContainer in $ContainersToRestart) {
                if ($PSCmdlet.ShouldProcess($targetContainer.Name, "Start Container")) {
                    try {
                        Write-Verbose "Starting container: $($targetContainer.Name)"
                        $startQuery = "mutation { docker { start(id: `"$($targetContainer.Id)`") { id } } }"
                        Invoke-UnraidQuery -Query $startQuery -Session $Session | Out-Null
                        Write-Information "Container restarted: $($targetContainer.Name)" -InformationAction Continue
                    }
                    catch {  $PSCmdlet.WriteError($_) }
                }
            }
        }
    }
}