diff --git a/plugins/geenforce/client/Register-ShopdbShadow.ps1 b/plugins/geenforce/client/Register-ShopdbShadow.ps1 index e970128..0f3ad96 100644 --- a/plugins/geenforce/client/Register-ShopdbShadow.ps1 +++ b/plugins/geenforce/client/Register-ShopdbShadow.ps1 @@ -20,12 +20,28 @@ $ErrorActionPreference = 'Continue' $TaskName = 'ShopDB GE-Enforce (shadow)' $InstallDir = 'C:\Program Files\GE\Shopfloor' $BaseUrl = 'https://tsgwp00525.wjs.geaerospace.net/shopdb' -$Scope = 'gea-shopfloor-nocollections' +# Scope is NOT hardcoded: this script is shipped by more than one scope +# (collections and nocollections today), and a wrong value here would shadow the +# wrong manifest silently. It runs from :\\shopdb-client, so the +# directory it sits under IS the scope name - the same derivation used below for +# the share manifest, so the two cannot disagree. +$Scope = Split-Path -Leaf (Split-Path -Parent $PSScriptRoot) function Write-ShadowLog { + # Write-Host ALONE is not enough: the engine records only "ps1: " and + # the exit code for a PS1 entry, so nothing this script says reaches the + # enforce log. Combined with the fail-safe `exit 0` on every path, a silent + # early-out was indistinguishable from success - which is exactly how the + # never-firing task went unnoticed. Write to a file as well so the next + # failure is answerable from disk. param([string]$Message) $line = "[{0}] [shadow-setup] {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Message Write-Host $line + try { + $dir = 'C:\Logs\Shopfloor' + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + Add-Content -LiteralPath (Join-Path $dir ('shadow-setup-{0}.log' -f (Get-Date -Format yyyyMMdd))) -Value $line + } catch { } } try { @@ -60,6 +76,37 @@ try { $arguments = '-NoProfile -ExecutionPolicy Bypass -File "{0}" -Scope "{1}" -EnginePath "{2}" -ShadowMode -ShareManifestPath "{3}"' ` -f $runner, $Scope, $engine, $shareManifest + # ONLY register when it is missing or its arguments changed. + # + # Registering unconditionally is what stopped this working the first time. + # A `-Once -At (Get-Date)` trigger does NOT fire immediately: the first run + # is start-boundary PLUS the repetition interval, so 15 minutes out. This + # entry is DetectionMethod=Always and runs every enforce cycle, 5 minutes + # apart, and each Register-ScheduledTask -Force reset the start boundary to + # "now" - pushing the first run back to +15 before the previous +15 could + # elapse. 5 < 15, so the task sat at Ready with LastTaskResult 267011 + # (SCHED_S_TASK_HAS_NOT_RUN) indefinitely. Measured on the win11 VM. + $existing = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue + if ($existing) { + $currentArgs = ($existing.Actions | Select-Object -First 1).Arguments + if ($currentArgs -eq $arguments) { + # Correct arguments, but a bay provisioned by the BROKEN version of + # this script carries a task that was reset every cycle and so has + # never run. Leaving it alone would strand exactly the bays that hit + # the bug. Kick it once; after that LastRunTime is set and this is a + # no-op forever. + $info = $existing | Get-ScheduledTaskInfo + $neverran = ($null -eq $info.LastRunTime) -or + ($info.LastRunTime -lt (Get-Date '2000-01-01')) + if ($neverran) { + Write-ShadowLog ("task exists but has never run (LastTaskResult $($info.LastTaskResult)) - starting it once.") + Start-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue + } + return # schedule is correct; do not reset the start boundary + } + Write-ShadowLog 'task arguments changed - re-registering.' + } + $action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $arguments # RepetitionInterval ALONE - passing RepetitionDuration serializes to a # Duration the Task Scheduler schema rejects. @@ -69,6 +116,9 @@ try { Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger $trigger ` -Principal $principal -Settings $settings -Force | Out-Null + # Kick it once rather than waiting out the first 15-minute interval, so a + # freshly provisioned bay reports on this cycle instead of the next. + Start-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue Write-ShadowLog "registered '$TaskName' (every 15 min), shadowing $shareManifest" exit 0 }