# Register-GEEnforce.ps1 - Registers "GE Shopfloor Enforce" scheduled task. # # Idempotent: deletes an existing task with the same name first. Also # unregisters the legacy per-type enforcer tasks so they don't race. # # Triggers (all run as SYSTEM, RunLevel=Highest): # - AtLogOn for first-boot catch-up # - Repetition every 5 min for fleet auto-update (jittered start offset # in the first 5 min window to spread 200 PCs) # - Shift-change windows 05:45, 13:45, 21:45 EST (30-min window each; # handled by running the task at window start # and letting the lib run anything not yet # applied - Stage 2b will gate ApplyMode=Nightly # entries to only fire inside a window). # # Called from Run-ShopfloorSetup.ps1 at imaging time. Also usable manually # to re-register on an existing PC. param( [string]$EnforcerPath = 'C:\Program Files\GE\Shopfloor\GE-Enforce.ps1' ) $ErrorActionPreference = 'Stop' $taskName = 'GE Shopfloor Enforce' $legacyTasks = @( 'GE Common Enforce', 'GE Acrobat Enforce', 'GE Shopfloor Machine Apps Enforce', 'GE Machine Enforce', 'GE CMM Enforce', 'GE Keyence Enforce' ) function Write-RegisterLog { param([string]$m) Write-Host "[Register-GEEnforce] $m" } # Unregister legacy per-type enforcers so only GE-Enforce drives the fleet. foreach ($name in $legacyTasks) { $t = Get-ScheduledTask -TaskName $name -ErrorAction SilentlyContinue if ($t) { Write-RegisterLog "Unregistering legacy task: $name" Unregister-ScheduledTask -TaskName $name -Confirm:$false -ErrorAction SilentlyContinue } } # Drop an existing copy of our own task (re-imaging idempotency). $existing = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue if ($existing) { Write-RegisterLog "Removing existing scheduled task: $taskName" Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue } # --- Action --- $action = New-ScheduledTaskAction ` -Execute 'powershell.exe' ` -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$EnforcerPath`"" # --- Triggers --- # Per-PC random offset [0, 5) min so 200 PCs don't all fire on :00/:05/:10/... # Derived from hostname hash so the same PC always picks the same offset. $hostHash = [System.BitConverter]::ToUInt32( [System.Security.Cryptography.MD5]::Create().ComputeHash( [System.Text.Encoding]::UTF8.GetBytes($env:COMPUTERNAME)), 0) $offsetMin = $hostHash % 5 # 0..4 $startToday = (Get-Date -Hour 0 -Minute $offsetMin -Second 0).AddSeconds(0) $logonTrigger = New-ScheduledTaskTrigger -AtLogOn # Periodic every 5 minutes, repeating indefinitely, starting at the offset $periodicTrigger = New-ScheduledTaskTrigger -Once -At $startToday -RepetitionInterval (New-TimeSpan -Minutes 5) $shift1Trigger = New-ScheduledTaskTrigger -Daily -At '05:45' # 3-to-1 shift $shift2Trigger = New-ScheduledTaskTrigger -Daily -At '13:45' # 1-to-2 $shift3Trigger = New-ScheduledTaskTrigger -Daily -At '21:45' # 2-to-3 $triggers = @($logonTrigger, $periodicTrigger, $shift1Trigger, $shift2Trigger, $shift3Trigger) # --- Principal + Settings --- $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest $settings = New-ScheduledTaskSettingsSet ` -AllowStartIfOnBatteries ` -DontStopIfGoingOnBatteries ` -StartWhenAvailable ` -ExecutionTimeLimit (New-TimeSpan -Hours 1) ` -MultipleInstances IgnoreNew $description = "GE Shopfloor unified enforcer. Reads common + pc-type manifests from " + "\\tsgwp00525.wjs.geaerospace.net\shared\dt\shopfloor\, runs " + "Install-FromManifest.ps1 against each. Periodic 5-min jitter + " + "AtLogOn + 3x shift-change windows. Log: C:\Logs\Shopfloor\enforce-*.log" Register-ScheduledTask ` -TaskName $taskName ` -Action $action ` -Trigger $triggers ` -Principal $principal ` -Settings $settings ` -Description $description | Out-Null Write-RegisterLog "Registered '$taskName' (offset $offsetMin min)" Write-RegisterLog " Triggers: AtLogOn, every 5min, 05:45, 13:45, 21:45" Write-RegisterLog " Action: powershell -File $EnforcerPath"