Public/Update-GreenroomInstance.ps1
|
# SPDX-License-Identifier: AGPL-3.0-or-later # Copyright (C) 2026 Tyler Vigario <# .SYNOPSIS Move registered instances onto the module version loaded in this session. .DESCRIPTION Installing a new module version does not move an instance to it, and this is the command that does. The scheduled task records the VERSIONED asset path -- Register-GreenroomTask builds it from the module root -- and module versions install side by side, so Import-Module resolves the newest while the task keeps launching the old one. Restart-GreenroomSession does not help: it re-runs the task, and the task is what still names the old path. Nothing errors, which is what makes it worth a command. So an upgrade is two steps, and only the first is anybody else's job: Update-PSResource Greenroom # however the module got here Update-GreenroomInstance Each instance is re-registered with Install-GreenroomInstance -NoStart, which rewrites the task and config.json TOGETHER -- they must move as one, or a new watchdog reads an old config -- and which inherits every parameter it is not given, so the original arguments are not needed here. Then it is restarted, because until it is, the running supervisor is still the old one. Only instances whose assets differ from this module are touched. An instance whose task path carries no version is left alone: that is a module installed somewhere unversioned, where new files land in place and there is nothing to move. .PARAMETER Name Only update instances with this name. Wildcards supported. Default: every registered instance on the host. .PARAMETER Force Re-register even when the version already matches. Also the way to repair a task pointing at a version that has since been deleted from disk. .PARAMETER NoRestart Re-register without restarting. The new assets take effect at the next start; until then the running session keeps the old ones, so the drift warning stays accurate. .OUTPUTS Greenroom.Instance for each restarted instance. Nothing under -NoRestart. .EXAMPLE Update-GreenroomInstance .EXAMPLE Update-GreenroomInstance -WhatIf Which instances are behind, and what they would move from and to, without touching them. .EXAMPLE Update-GreenroomInstance -Name render-* -NoRestart #> function Update-GreenroomInstance { [CmdletBinding(SupportsShouldProcess)] [OutputType('Greenroom.Instance')] param( # Pipeline-bound like the other state-changing commands, with the Instance alias, # so `Get-GreenroomInstance | Where-Object AssetVersion | Update-GreenroomInstance` # binds. Module.Tests asserts this across the whole public surface. [Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('Instance')] [SupportsWildcards()] [string]$Name, [switch]$Force, [switch]$NoRestart ) process { # Registration IS the scheduled task, so that is what is enumerated -- a state # directory without a task is a half-uninstalled remnant, not something to restart. $tasks = @(Get-ScheduledTask -TaskName 'greenroom-*' -ErrorAction SilentlyContinue) $names = @($tasks | ForEach-Object { $_.TaskName -replace '^greenroom-', '' }) if ($Name) { $names = @($names | Where-Object { $_ -like $Name }) } if ($names.Count -eq 0) { if ($Name) { Write-Warning "no registered instance matches '$Name'" } else { Write-Warning 'no greenroom instances are registered on this host' } return } $targets = @() foreach ($n in ($names | Sort-Object)) { $asset = Get-InstanceAssetVersion -Name $n if ($Force) { $targets += [PSCustomObject]@{ Instance = $n; From = $asset } } elseif (-not $asset) { Write-Verbose "$n runs assets from a path carrying no version -- nothing to move (-Force re-registers anyway)" } elseif ($asset -ne $script:GreenroomModuleVersion) { $targets += [PSCustomObject]@{ Instance = $n; From = $asset } } else { Write-Verbose "$n already runs $asset" } } if ($targets.Count -eq 0) { Write-Verbose "every matching instance already runs $script:GreenroomModuleVersion" return } foreach ($t in $targets) { $from = if ($t.From) { $t.From } else { 'an unversioned path' } # ONE ShouldProcess for the whole per-instance update, for the same reason # Restart-GreenroomSession gates its three kills with one: re-registering and # restarting are a single decision, and prompting twice for it is noise. The inner # calls are told not to ask again. if (-not $PSCmdlet.ShouldProcess($t.Instance, "re-register $from -> $script:GreenroomModuleVersion$(if ($NoRestart) { '' } else { ' and restart' })")) { continue } try { Install-GreenroomInstance -Name $t.Instance -NoStart -Confirm:$false | Out-Null } catch { # -ErrorAction Continue ON THE Write-Error ITSELF, and it is load-bearing. The # module sets $ErrorActionPreference = 'Stop', which functions here inherit, so # a bare Write-Error is TERMINATING and would abort the loop at the first # failure -- stranding every later instance on the old version, which is the # opposite of the intent. Measured: without this, a throw on the first instance # stopped the second from being re-registered at all. Write-Error -ErrorAction Continue -Message ( "re-registering '$($t.Instance)' failed, it stays on $from -- $($_.Exception.Message)") continue } if ($NoRestart) { Write-Verbose "$($t.Instance) re-registered; the new assets start with the next session" continue } Restart-GreenroomSession -Name $t.Instance -Confirm:$false } } } |