Register sync task BEFORE enrollment (PPKG reboot kills run-enrollment)
Install-ProvisioningPackage triggers an immediate reboot that kills
run-enrollment.ps1 before it can register the sync_intune task or do
any post-install work. BPRT app installs happen on the NEXT boot, not
before the reboot.
Fix: move sync task registration into Run-ShopfloorSetup.ps1, executed
BEFORE calling run-enrollment.ps1. The task is safely registered while
we still have control. Then enrollment installs the PPKG and lets it
reboot. After reboot, BPRT finishes in background, sync task fires at
logon, monitors Intune enrollment (which is independent of BPRT).
Run-ShopfloorSetup.ps1:
- Registers "Shopfloor Intune Sync" @logon task after desktop tool
copies but BEFORE enrollment
- Flushes transcript before calling enrollment (since PPKG reboot
will kill us, ensures log is complete)
- Enrollment is the absolute last call
run-enrollment.ps1:
- Stripped to essentials: find PPKG, rename computer, set OOBE,
Install-ProvisioningPackage
- No BPRT polling (irrelevant - happens after reboot)
- No task registration (already done by caller)
- No shutdown call (PPKG handles it)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -180,23 +180,53 @@ if ($pcType -eq "Standard") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Run enrollment (PPKG install) ---
|
# --- Register sync_intune as persistent @logon scheduled task ---
|
||||||
# Enrollment runs AFTER all our apps are installed. The PPKG installs
|
# Must be registered BEFORE enrollment because Install-ProvisioningPackage
|
||||||
# Chrome, Office, CyberArk, Tanium, etc. and needs a reboot for file
|
# triggers an immediate reboot that kills run-enrollment.ps1. The task
|
||||||
# operations (Zscaler rename, PPKG cleanup). run-enrollment.ps1 waits
|
# registration must survive the PPKG reboot, so we do it here while
|
||||||
# for all PPKG steps to complete, registers sync_intune as a persistent
|
# Run-ShopfloorSetup.ps1 is still running.
|
||||||
# @logon scheduled task, then reboots.
|
#
|
||||||
$enrollScript = Join-Path $enrollDir 'run-enrollment.ps1'
|
# The task fires at every logon until sync_intune detects completion and
|
||||||
if (Test-Path -LiteralPath $enrollScript) {
|
# unregisters itself. It monitors Intune enrollment (Phase 1-5), NOT BPRT
|
||||||
Write-Host ""
|
# app installs -- BPRT finishes on its own in the background after the
|
||||||
Write-Host "=== Running enrollment (PPKG install) ==="
|
# PPKG reboot, and is irrelevant to the Intune lifecycle.
|
||||||
|
$taskName = 'Shopfloor Intune Sync'
|
||||||
|
$monitorScript = Join-Path $setupDir 'Shopfloor\lib\Monitor-IntuneProgress.ps1'
|
||||||
|
$configureScript = Join-Path $setupDir 'Shopfloor\Configure-PC.ps1'
|
||||||
|
|
||||||
|
if (Test-Path -LiteralPath $monitorScript) {
|
||||||
try {
|
try {
|
||||||
& $enrollScript
|
$action = New-ScheduledTaskAction `
|
||||||
|
-Execute 'powershell.exe' `
|
||||||
|
-Argument "-NoProfile -NoExit -ExecutionPolicy Bypass -File `"$monitorScript`" -AsTask -ConfigureScript `"$configureScript`""
|
||||||
|
|
||||||
|
$trigger = New-ScheduledTaskTrigger -AtLogOn
|
||||||
|
|
||||||
|
$principal = New-ScheduledTaskPrincipal `
|
||||||
|
-GroupId 'S-1-5-32-545' `
|
||||||
|
-RunLevel Limited
|
||||||
|
|
||||||
|
$settings = New-ScheduledTaskSettingsSet `
|
||||||
|
-AllowStartIfOnBatteries `
|
||||||
|
-DontStopIfGoingOnBatteries `
|
||||||
|
-StartWhenAvailable `
|
||||||
|
-ExecutionTimeLimit (New-TimeSpan -Hours 2)
|
||||||
|
|
||||||
|
Register-ScheduledTask `
|
||||||
|
-TaskName $taskName `
|
||||||
|
-Action $action `
|
||||||
|
-Trigger $trigger `
|
||||||
|
-Principal $principal `
|
||||||
|
-Settings $settings `
|
||||||
|
-Force `
|
||||||
|
-ErrorAction Stop | Out-Null
|
||||||
|
|
||||||
|
Write-Host "Registered '$taskName' logon task."
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning "run-enrollment.ps1 failed: $_"
|
Write-Warning "Failed to register sync task: $_"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Write-Host "run-enrollment.ps1 not found - skipping enrollment."
|
Write-Warning "Monitor-IntuneProgress.ps1 not found at $monitorScript"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set auto-logon to expire after 4 more logins (2 needed for sync_intune
|
# Set auto-logon to expire after 4 more logins (2 needed for sync_intune
|
||||||
@@ -205,17 +235,28 @@ if (Test-Path -LiteralPath $enrollScript) {
|
|||||||
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoLogonCount /t REG_DWORD /d 4 /f | Out-Null
|
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoLogonCount /t REG_DWORD /d 4 /f | Out-Null
|
||||||
Write-Host "Auto-logon set to 4 remaining logins."
|
Write-Host "Auto-logon set to 4 remaining logins."
|
||||||
|
|
||||||
Write-Host ""
|
# --- Run enrollment (PPKG install) ---
|
||||||
Write-Host "================================================================"
|
# Enrollment is the LAST thing we do. Install-ProvisioningPackage triggers
|
||||||
Write-Host "=== Run-ShopfloorSetup.ps1 complete $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ==="
|
# an immediate reboot -- everything after this call is unlikely to execute.
|
||||||
Write-Host "================================================================"
|
# The sync_intune task is already registered above, so the PPKG reboot
|
||||||
|
# can kill us and the chain continues on the next boot.
|
||||||
# Flush transcript before shutdown so the log file is complete on next boot
|
$enrollScript = Join-Path $enrollDir 'run-enrollment.ps1'
|
||||||
try { Stop-Transcript | Out-Null } catch {}
|
if (Test-Path -LiteralPath $enrollScript) {
|
||||||
|
Write-Host ""
|
||||||
# run-enrollment.ps1 already initiated the reboot. If it didn't run
|
Write-Host "=== Running enrollment (PPKG install) ==="
|
||||||
# (no PPKG), reboot now.
|
Write-Host "NOTE: PPKG will trigger an immediate reboot. This is expected."
|
||||||
if (-not (Test-Path -LiteralPath $enrollScript)) {
|
try { Stop-Transcript | Out-Null } catch {}
|
||||||
|
& $enrollScript
|
||||||
|
# If we get here, the PPKG didn't reboot (maybe no PPKG file found).
|
||||||
|
Write-Host "Enrollment returned without rebooting. Rebooting now..."
|
||||||
|
shutdown /r /t 10
|
||||||
|
} else {
|
||||||
|
Write-Host "run-enrollment.ps1 not found - skipping enrollment."
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "================================================================"
|
||||||
|
Write-Host "=== Run-ShopfloorSetup.ps1 complete $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ==="
|
||||||
|
Write-Host "================================================================"
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
# run-enrollment.ps1
|
# run-enrollment.ps1
|
||||||
# Installs GCCH enrollment provisioning package, waits for all PPKG apps
|
# Installs GCCH enrollment provisioning package. That's it.
|
||||||
# to finish installing, registers sync_intune as a persistent @logon task,
|
|
||||||
# then reboots.
|
|
||||||
#
|
#
|
||||||
# Called by Run-ShopfloorSetup.ps1 AFTER all PreInstall + type-specific
|
# Install-ProvisioningPackage triggers an immediate reboot -- nothing after
|
||||||
# apps are already installed (not as a FirstLogonCommand -- that was the
|
# that call executes. The sync_intune task and all other post-enrollment
|
||||||
# old flow).
|
# setup are registered by Run-ShopfloorSetup.ps1 BEFORE calling this script.
|
||||||
|
|
||||||
$ErrorActionPreference = 'Continue'
|
$ErrorActionPreference = 'Continue'
|
||||||
$logFile = "C:\Logs\enrollment.log"
|
$logFile = "C:\Logs\enrollment.log"
|
||||||
@@ -35,107 +33,30 @@ $newName = "E$serial"
|
|||||||
Log "Setting computer name to $newName"
|
Log "Setting computer name to $newName"
|
||||||
Rename-Computer -NewName $newName -Force -ErrorAction SilentlyContinue
|
Rename-Computer -NewName $newName -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
# --- Set OOBE complete (must happen before PPKG reboot) ---
|
||||||
|
Log "Setting OOBE as complete..."
|
||||||
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OOBE" /v OOBEComplete /t REG_DWORD /d 1 /f | Out-Null
|
||||||
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OOBE" /v SetupDisplayedEula /t REG_DWORD /d 1 /f | Out-Null
|
||||||
|
|
||||||
# --- Install provisioning package ---
|
# --- Install provisioning package ---
|
||||||
Log "Installing provisioning package..."
|
# This triggers an IMMEDIATE reboot. Nothing below this line executes.
|
||||||
|
# BPRT app installs (Chrome, Office, Tanium, etc.) happen on the next boot.
|
||||||
|
# The sync_intune scheduled task (registered by Run-ShopfloorSetup.ps1
|
||||||
|
# before calling us) fires at the next logon to monitor Intune enrollment.
|
||||||
|
Log "Installing provisioning package (PPKG will reboot immediately)..."
|
||||||
try {
|
try {
|
||||||
Install-ProvisioningPackage -PackagePath $ppkgFile.FullName -ForceInstall -QuietInstall
|
Install-ProvisioningPackage -PackagePath $ppkgFile.FullName -ForceInstall -QuietInstall
|
||||||
Log "Provisioning package installed successfully."
|
Log "Install-ProvisioningPackage returned (reboot may be imminent)."
|
||||||
} catch {
|
} catch {
|
||||||
Log "ERROR: Install-ProvisioningPackage failed: $_"
|
Log "ERROR: Install-ProvisioningPackage failed: $_"
|
||||||
Log "Attempting fallback with Add-ProvisioningPackage..."
|
Log "Attempting fallback with Add-ProvisioningPackage..."
|
||||||
try {
|
try {
|
||||||
Add-ProvisioningPackage -PackagePath $ppkgFile.FullName -ForceInstall -QuietInstall
|
Add-ProvisioningPackage -PackagePath $ppkgFile.FullName -ForceInstall -QuietInstall
|
||||||
Log "Provisioning package added successfully (fallback)."
|
Log "Add-ProvisioningPackage returned."
|
||||||
} catch {
|
} catch {
|
||||||
Log "ERROR: Fallback also failed: $_"
|
Log "ERROR: Fallback also failed: $_"
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Wait for PPKG provisioning to finish ---
|
# If we get here, the PPKG didn't reboot immediately. Unlikely but handle it.
|
||||||
# Install-ProvisioningPackage is async -- it queues the provisioning engine
|
Log "PPKG did not trigger immediate reboot. Returning to caller."
|
||||||
# and returns immediately. The actual app installs (Chrome, Office, Tanium,
|
|
||||||
# CyberArk, etc.) run in the background as BPRT steps. "Remove Staging
|
|
||||||
# Locations" is the LAST step -- when its Log.txt exists, all provisioning
|
|
||||||
# is done.
|
|
||||||
$bprtMarker = 'C:\Logs\BPRT\Remove Staging Locations\Log.txt'
|
|
||||||
$maxWait = 900 # 15 minutes (Office install can be slow)
|
|
||||||
$pollInterval = 10
|
|
||||||
$elapsed = 0
|
|
||||||
|
|
||||||
Log "Waiting for PPKG provisioning to complete..."
|
|
||||||
while (-not (Test-Path -LiteralPath $bprtMarker) -and $elapsed -lt $maxWait) {
|
|
||||||
Start-Sleep -Seconds $pollInterval
|
|
||||||
$elapsed += $pollInterval
|
|
||||||
if ($elapsed % 30 -eq 0) {
|
|
||||||
$completedSteps = @(Get-ChildItem 'C:\Logs\BPRT' -Directory -ErrorAction SilentlyContinue |
|
|
||||||
Where-Object { Test-Path (Join-Path $_.FullName 'Log.txt') } |
|
|
||||||
Select-Object -ExpandProperty Name)
|
|
||||||
Log " $elapsed s elapsed, $($completedSteps.Count) BPRT steps done: $($completedSteps -join ', ')"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path -LiteralPath $bprtMarker) {
|
|
||||||
Log "PPKG provisioning complete after $elapsed s."
|
|
||||||
} else {
|
|
||||||
Log "WARNING: PPKG provisioning timeout after $maxWait s."
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Set OOBE complete ---
|
|
||||||
Log "Setting OOBE as complete..."
|
|
||||||
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OOBE" /v OOBEComplete /t REG_DWORD /d 1 /f | Out-Null
|
|
||||||
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OOBE" /v SetupDisplayedEula /t REG_DWORD /d 1 /f | Out-Null
|
|
||||||
|
|
||||||
# --- Register sync_intune as persistent @logon scheduled task ---
|
|
||||||
# sync_intune monitors the Intune enrollment lifecycle (5-phase status
|
|
||||||
# table). It stays registered as a logon task until:
|
|
||||||
# - Pre-reboot: monitors until Phase 1+2+3 done -> reboots
|
|
||||||
# - Post-reboot: monitors until DSC install complete -> unregisters
|
|
||||||
# itself, launches Configure-PC
|
|
||||||
#
|
|
||||||
# Runs as BUILTIN\Users (logged-in user) so it can show GUI (QR code,
|
|
||||||
# status table). Needs the interactive session, NOT SYSTEM.
|
|
||||||
$taskName = 'Shopfloor Intune Sync'
|
|
||||||
$monitorScript = 'C:\Enrollment\shopfloor-setup\Shopfloor\lib\Monitor-IntuneProgress.ps1'
|
|
||||||
$configureScript = 'C:\Enrollment\shopfloor-setup\Shopfloor\Configure-PC.ps1'
|
|
||||||
|
|
||||||
if (Test-Path -LiteralPath $monitorScript) {
|
|
||||||
try {
|
|
||||||
$action = New-ScheduledTaskAction `
|
|
||||||
-Execute 'powershell.exe' `
|
|
||||||
-Argument "-NoProfile -NoExit -ExecutionPolicy Bypass -File `"$monitorScript`" -AsTask -ConfigureScript `"$configureScript`""
|
|
||||||
|
|
||||||
$trigger = New-ScheduledTaskTrigger -AtLogOn
|
|
||||||
|
|
||||||
$principal = New-ScheduledTaskPrincipal `
|
|
||||||
-GroupId 'S-1-5-32-545' `
|
|
||||||
-RunLevel Limited
|
|
||||||
|
|
||||||
$settings = New-ScheduledTaskSettingsSet `
|
|
||||||
-AllowStartIfOnBatteries `
|
|
||||||
-DontStopIfGoingOnBatteries `
|
|
||||||
-StartWhenAvailable `
|
|
||||||
-ExecutionTimeLimit (New-TimeSpan -Hours 2)
|
|
||||||
|
|
||||||
Register-ScheduledTask `
|
|
||||||
-TaskName $taskName `
|
|
||||||
-Action $action `
|
|
||||||
-Trigger $trigger `
|
|
||||||
-Principal $principal `
|
|
||||||
-Settings $settings `
|
|
||||||
-Force `
|
|
||||||
-ErrorAction Stop | Out-Null
|
|
||||||
|
|
||||||
Log "Registered '$taskName' logon task (persists until sync complete)."
|
|
||||||
} catch {
|
|
||||||
Log "WARNING: Failed to register sync task: $_"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log "WARNING: Monitor-IntuneProgress.ps1 not found at $monitorScript"
|
|
||||||
}
|
|
||||||
|
|
||||||
Log "=== Enrollment complete. Rebooting... ==="
|
|
||||||
|
|
||||||
# Reboot -- PPKG file operations (Zscaler rename, cleanup) happen on next boot.
|
|
||||||
# sync_intune fires at next logon via the scheduled task.
|
|
||||||
shutdown /r /t 10
|
|
||||||
|
|||||||
Reference in New Issue
Block a user