Run-ShopfloorSetup: self-resume RunOnce + top up AutoLogonCount

Imaging chain stalled on WJF00159 after FormTracePak Setup.exe forced
a reboot: SupportUser auto-logged in fine, briefly flashed something
(an HKLM\Run logon hook), then idle - no resume of Run-ShopfloorSetup.
Confirmed via diag-dispatcher.ps1: bay had AutoLogon working, RunOnce
empty, no Stage-Dispatcher.ps1 on disk, no setup-stage.txt.

Root cause: Run-ShopfloorSetup launches once from unattend XML's
FirstLogonCommands and has no self-resume mechanism. If anything cuts
it off mid-flight (FormTracePak Setup, eDNC MSI, Oracle install with
forced reboot, etc) the chain dies and nothing brings it back.
Stage-Dispatcher.ps1 in the repo is academic infrastructure that was
never wired into the live flow - startnet.cmd does not stage it and
nothing creates setup-stage.txt.

Fix: have Run-ShopfloorSetup register ITSELF as RunOnce at the top of
the script. The script is idempotent throughout (detection checks
skip already-done work) so re-entry post-reboot picks up cleanly.
Normal completion path removes the RunOnce so it does not re-fire
after the planned end-of-script reboot.

Also top up AutoLogonCount to 10 at script start. The unattend XML's
LogonCount=7 budget gets consumed across typical imaging reboots
(Office, Oracle, FormTracePak, Run-ShopfloorSetup explicit, sync-intune)
and an unplanned FormTracePak forced reboot pushes the counter past 0,
clearing AutoAdminLogon and parking the bay at the login screen.
Restoring the budget every Run-ShopfloorSetup entry keeps SupportUser
auto-logging in across any number of forced reboots until normal
completion. Lockdown's Autologon.exe sets its own AutoAdminLogon for
the ShopFloor user when it runs, so the post-completion natural
decrement to 0 does not affect the final state.

Verified via diag-dispatcher.ps1 capture on WJF00159 today - that bay
had AutoLogonCount=4 and no Stage-Dispatcher.ps1 on disk, which both
match this root cause + fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-22 09:17:07 -04:00
parent a22d2f0313
commit b86b830568

View File

@@ -50,6 +50,35 @@ Report-Stage -Stage 'Run-ShopfloorSetup: starting' -Index 2
# Cancel any pending reboot so it doesn't interrupt setup # Cancel any pending reboot so it doesn't interrupt setup
cmd /c "shutdown /a 2>nul" *>$null cmd /c "shutdown /a 2>nul" *>$null
# Self-resume: register this script as a RunOnce so a vendor-installer-
# forced reboot mid-flight (FormTracePak Setup.exe, eDNC MSI, etc) auto-
# resumes the chain after the next SupportUser auto-login. RunOnce is
# single-shot - if we complete normally we remove this key at end of
# script. If we're killed mid-flight by a forced reboot, the key
# survives and fires after reboot.
#
# Idempotent design throughout this script: every step checks detection
# before installing, so a forced-reboot re-entry just skips the already-
# done work and continues from where it left off.
#
# Also top up AutoLogonCount so the SupportUser autologon budget
# (LogonCount=7 from unattend XML) survives extra unplanned reboots.
$selfResumeKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce'
$selfResumeName = 'ResumeRunShopfloorSetup'
$selfResumeCmd = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -File "' + $PSCommandPath + '"'
try {
Set-ItemProperty -Path $selfResumeKey -Name $selfResumeName -Value $selfResumeCmd -Type String -Force -ErrorAction Stop
Write-Host "Self-resume RunOnce registered: will re-fire $PSCommandPath if interrupted"
} catch {
Write-Warning "Failed to register self-resume RunOnce: $_"
}
try {
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name 'AutoLogonCount' -Value 10 -Type DWord -Force -ErrorAction Stop
Write-Host "AutoLogonCount topped up to 10 (vendor-forced reboot resilience)"
} catch {
Write-Warning "Failed to top up AutoLogonCount: $_"
}
# Wired NIC state handling moved to sync_intune (Monitor-IntuneProgress.ps1). # Wired NIC state handling moved to sync_intune (Monitor-IntuneProgress.ps1).
# Previously this script prompted the tech to unplug the PXE cable and # Previously this script prompted the tech to unplug the PXE cable and
# then re-enabled wired adapters interactively - that blocked the whole # then re-enabled wired adapters interactively - that blocked the whole
@@ -450,6 +479,10 @@ if (Test-Path -LiteralPath $enrollScript) {
Report-Stage -Stage 'Run-ShopfloorSetup: handoff to Monitor-IntuneProgress' -Index 6 Report-Stage -Stage 'Run-ShopfloorSetup: handoff to Monitor-IntuneProgress' -Index 6
Write-Host "=== Handing off to Monitor-IntuneProgress -PostPpkg ===" Write-Host "=== Handing off to Monitor-IntuneProgress -PostPpkg ==="
cmd /c "shutdown /a 2>nul" | Out-Null cmd /c "shutdown /a 2>nul" | Out-Null
# Made it past all the reboot-prone vendor installers. Clear the
# self-resume RunOnce so a normal completion + reboot does not re-fire
# this script post-PPKG (PPKG install owns the reboot chain from here).
try { Remove-ItemProperty -Path $selfResumeKey -Name $selfResumeName -ErrorAction SilentlyContinue } catch {}
$monitor = Join-Path $setupDir 'Shopfloor\lib\Monitor-IntuneProgress.ps1' $monitor = Join-Path $setupDir 'Shopfloor\lib\Monitor-IntuneProgress.ps1'
if (Test-Path -LiteralPath $monitor) { if (Test-Path -LiteralPath $monitor) {
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $monitor -PostPpkg & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $monitor -PostPpkg
@@ -463,6 +496,7 @@ if (Test-Path -LiteralPath $enrollScript) {
Write-Host "================================================================" Write-Host "================================================================"
Write-Host "=== Run-ShopfloorSetup.ps1 complete $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ===" Write-Host "=== Run-ShopfloorSetup.ps1 complete $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ==="
Write-Host "================================================================" Write-Host "================================================================"
try { Remove-ItemProperty -Path $selfResumeKey -Name $selfResumeName -ErrorAction SilentlyContinue } catch {}
try { Stop-Transcript | Out-Null } catch {} try { Stop-Transcript | Out-Null } catch {}
Write-Host "Rebooting in 10 seconds..." Write-Host "Rebooting in 10 seconds..."
shutdown /r /t 10 shutdown /r /t 10