# Invoke-ShopdbShadow.ps1 -- run one shopdb SHADOW cycle, from the manifest. # # Shadow = fetch the shopdb manifest, diff it against the share manifest, report # the cycle to shopdb. The engine still installs FROM THE SHARE, so behaviour is # unchanged. It is the observable step before any cutover. # # WHY THIS RUNS AS A MANIFEST ENTRY AND NOT A SCHEDULED TASK # # The first version registered a separate 15-minute task. That cannot work: # GE-Enforce.ps1 mounts the SFLD share for the length of its own cycle and # unmounts it at the end (mounted 12:10:02, unmounted 12:10:27). A task on its # own schedule therefore wakes up with the drive gone, hands the engine a path # that no longer resolves, and reports 0 installed / 0 skipped / 0 failed - a # silent nothing indistinguishable from a healthy no-op. It also meant two # cadences that could drift apart, and a registration that had to be healed. # # Running here removes all of it: the share is mounted because the enforce cycle # is what invoked us, the cadence is the fleet's own, and there is no task. # # Runs as SYSTEM under GE-Enforce, from an entry gated to the test bays. # Fail-safe: exits 0 on every path - shadowing must never stop a bay enforcing. $ErrorActionPreference = 'Continue' $InstallDir = 'C:\Program Files\GE\Shopfloor' $BaseUrl = 'https://tsgwp00525.wjs.geaerospace.net/shopdb' $LegacyTask = 'ShopDB GE-Enforce (shadow)' function Write-ShadowLog { # To a file as well as the host: the engine records only "ps1: " and # an exit code for a PS1 entry, so Write-Host reaches nothing, and with the # fail-safe exit 0 a silent early-out looks exactly like success. param([string]$Message) $line = "[{0}] [shadow] {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-{0}.log' -f (Get-Date -Format yyyyMMdd))) -Value $line } catch { } } try { # Retire the scheduled task the earlier version left behind. Bays that got # it would otherwise keep firing a run that cannot see the share, reporting # 0/0/0 over the top of the real result from this one. $stale = Get-ScheduledTask -TaskName $LegacyTask -ErrorAction SilentlyContinue if ($stale) { Unregister-ScheduledTask -TaskName $LegacyTask -Confirm:$false -ErrorAction SilentlyContinue Write-ShadowLog "removed the superseded '$LegacyTask' task (it ran outside the share mount)." } # Scope is this script's own directory name, never hardcoded: the same file # ships from more than one scope and a wrong value would shadow the wrong # manifest silently. $scopeDir = Split-Path -Parent $PSScriptRoot $scope = Split-Path -Leaf $scopeDir $shareManifest = Join-Path $scopeDir 'manifest.json' $runner = Join-Path $InstallDir 'Invoke-ShopdbEnforce.ps1' $engine = Join-Path $InstallDir 'lib\Install-FromManifest.ps1' foreach ($required in @($runner, $engine, $shareManifest)) { if (-not (Test-Path -LiteralPath $required)) { Write-ShadowLog "MISSING $required - skipping this cycle." exit 0 } } # BaseUrl only when it differs, so a hand-set value is not churned. $regPath = 'HKLM:\SOFTWARE\GE\ShopDB' if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force | Out-Null } if ((Get-ItemProperty -Path $regPath -Name BaseUrl -ErrorAction SilentlyContinue).BaseUrl -ne $BaseUrl) { Set-ItemProperty -Path $regPath -Name BaseUrl -Value $BaseUrl Write-ShadowLog "BaseUrl set to $BaseUrl" } Write-ShadowLog "shadowing $scope against $shareManifest" & $runner -Scope $scope -EnginePath $engine -ShadowMode -ShareManifestPath $shareManifest Write-ShadowLog "cycle complete (runner exit $LASTEXITCODE)." exit 0 } catch { Write-ShadowLog "FAILED: $_" exit 0 }