run-enrollment: switch provtool /source from BPRT to PSCmdlet

BPRT was stopping after the first RestartRequired=true command (DotNet35).
Test image captured 2026-04-15 showed 3 of 21 PPKG commands ran (PPKG
Version Check, Lock Screen, DotNet35) before provtool exited 0 leaving
Office / Chrome / Tanium / Activate-Windows / Enable-DeviceLockdown /
Hide-SupportUser / 12 more scripts unexecuted. Symptom: criticalChecks
said EntraID NOT joined (wrong -- it was), sessions.json showed a
'LogonIdleTask' session perpetually 'Not started', and the resulting PC
was missing most of its fleet software.

BPRT is the OOBE runtime source -- it expects the OOBE engine to own the
post-DotNet35 reboot + resume. In our post-autounattend context there is
no OOBE engine, so restart-required commands stall the pipeline. PSCmdlet
is the source Install-ProvisioningPackage uses internally and has the
correct resume semantics for post-OOBE application.

The original motivation for BPRT (avoiding the 180s PowerShell timeout)
does not apply because we invoke provtool.exe directly, not via the
Install-ProvisioningPackage cmdlet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-04-15 17:07:12 -04:00
parent 8528a1bcae
commit 14d103a248

View File

@@ -60,12 +60,18 @@ $provtool = Join-Path $env:SystemRoot 'System32\provtool.exe'
# then /source. No /log: or /ppkg: prefix - those are not valid provtool # then /source. No /log: or /ppkg: prefix - those are not valid provtool
# flags and caused 0x80004005 E_FAIL in the first test. # flags and caused 0x80004005 E_FAIL in the first test.
# #
# /source BPRT keeps us in the bulk-provisioning code path used by the # /source PSCmdlet matches what Install-ProvisioningPackage invokes
# automatic OOBE PPKG runtime. PSCmdlet would give richer ETW/event-log # internally and is the correct post-OOBE context. BPRT was tried first
# diagnostics, but may change which actions in the PPKG actually execute # and verified to stop after the first RestartRequired command (DotNet35):
# (not verified against Microsoft docs). Stay on BPRT and enable logging # only 3 of 21 commands ran (PPKG Version Check, Lock Screen, DotNet35),
# manually below. # leaving Office/Chrome/Tanium/Activate-Windows etc never executed
$provArgs = @("`"$($ppkgFile.FullName)`"", "/quiet", "/source", "BPRT") # because BPRT expects the OOBE runtime to own the reboot-and-resume
# loop, and there is no OOBE runtime here. PSCmdlet registers a
# RunOnce-style resume handler so the remaining commands continue after
# the reboot Run-ShopfloorSetup issues. Timeout concerns that previously
# motivated BPRT don't apply here because we invoke provtool.exe
# directly, not via the 180s-capped Install-ProvisioningPackage cmdlet.
$provArgs = @("`"$($ppkgFile.FullName)`"", "/quiet", "/source", "PSCmdlet")
# Enable the Provisioning-Diagnostics-Provider Admin channel so events # Enable the Provisioning-Diagnostics-Provider Admin channel so events
# from the BPRT run land somewhere we can export afterward. This is # from the BPRT run land somewhere we can export afterward. This is