From 67845372b253c0402bd4430a6d31443d9f49b056 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Wed, 15 Apr 2026 14:22:43 -0400 Subject: [PATCH] Harvest provtool diagnostics, enable ETW channel, skip Timeclock machine# run-enrollment.ps1: - Enable Provisioning-Diagnostics-Provider/Admin event log before invoking provtool (was disabled by default; no diagnostics survived early runs). - After provtool returns, copy C:\ProgramData\Microsoft\Provisioning\* into C:\Logs\PPKG\ and snapshot HKLM\...\Sessions\* as provisioning-sessions.json, plus export the Admin event channel to Provisioning-Diagnostics-Admin.evtx. Gives us reviewable state without relying on provtool's failure-only diagnostic bundle. - provtool arg order is positional path + /quiet + /source BPRT (verified against ProvEventLog from the PS cmdlet internal call). startnet.cmd / startnet-template.cmd: - Standard-Timeclock sub-type skips the machine-number prompt. Timeclock PCs do not use a machine number so forcing a prompt wasted tech time and left MACHINENUM at the 9999 default anyway. Machine sub-type is unaffected. --- playbook/shopfloor-setup/run-enrollment.ps1 | 69 +++++++++++++++++++++ playbook/startnet.cmd | 3 +- startnet-template.cmd | 3 +- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/playbook/shopfloor-setup/run-enrollment.ps1 b/playbook/shopfloor-setup/run-enrollment.ps1 index aa189b9..428f488 100755 --- a/playbook/shopfloor-setup/run-enrollment.ps1 +++ b/playbook/shopfloor-setup/run-enrollment.ps1 @@ -59,7 +59,18 @@ $provtool = Join-Path $env:SystemRoot 'System32\provtool.exe' # internally (observed in ProvEventLog.txt): positional path, then /quiet, # then /source. No /log: or /ppkg: prefix - those are not valid provtool # flags and caused 0x80004005 E_FAIL in the first test. +# +# /source BPRT keeps us in the bulk-provisioning code path used by the +# automatic OOBE PPKG runtime. PSCmdlet would give richer ETW/event-log +# diagnostics, but may change which actions in the PPKG actually execute +# (not verified against Microsoft docs). Stay on BPRT and enable logging +# manually below. $provArgs = @("`"$($ppkgFile.FullName)`"", "/quiet", "/source", "BPRT") + +# Enable the Provisioning-Diagnostics-Provider Admin channel so events +# from the BPRT run land somewhere we can export afterward. This is +# idempotent - running each time is safe. +wevtutil.exe set-log 'Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin' /enabled:true 2>$null | Out-Null Log "Installing provisioning package via provtool.exe (no PowerShell timeout)..." Log "Command: $provtool $($provArgs -join ' ')" Log "PPKG diagnostic logs -> $ppkgLogDir (provtool writes them automatically)" @@ -74,6 +85,64 @@ try { Log "ERROR: Failed to launch provtool.exe: $_" } +# --- Harvest Windows' own provisioning diagnostics into $ppkgLogDir --- +# provtool.exe /quiet does not drop a zip bundle on success, so the real +# detail lives under C:\ProgramData\Microsoft\Provisioning\, in the +# registry under HKLM\Software\Microsoft\Provisioning\Sessions\*, and in +# the Provisioning-Diagnostics-Provider event log. Copy/export all three +# into our log dir so they ride back with the shopfloor logs bundle. +Log "Harvesting Windows provisioning diagnostics to $ppkgLogDir..." +try { + $provData = 'C:\ProgramData\Microsoft\Provisioning' + if (Test-Path $provData) { + Copy-Item -Path (Join-Path $provData '*') -Destination $ppkgLogDir ` + -Recurse -Force -ErrorAction SilentlyContinue + Log " copied $provData -> $ppkgLogDir" + } else { + Log " $provData not present (provtool may not have touched it)" + } +} catch { + Log " WARN: ProgramData copy threw: $_" +} + +try { + $sessions = Get-ChildItem 'HKLM:\Software\Microsoft\Provisioning\Sessions' -ErrorAction SilentlyContinue + if ($sessions) { + $snap = $sessions | ForEach-Object { + $props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue + if ($props) { + [pscustomobject]@{ + Session = $_.PSChildName + BeginTime = $props.BeginTime + LastRunTime = $props.LastRunTime + RebootCount = $props.RebootCount + State = $props.State + StateValue = $props.StateValue + } + } + } + $snap | ConvertTo-Json -Depth 3 | + Out-File -FilePath (Join-Path $ppkgLogDir 'provisioning-sessions.json') -Encoding UTF8 + Log " wrote provisioning-sessions.json ($($snap.Count) session(s))" + foreach ($s in $snap) { + Log " session $($s.Session): State=$($s.State) RebootCount=$($s.RebootCount)" + } + } else { + Log " no sessions under HKLM:\Software\Microsoft\Provisioning\Sessions" + } +} catch { + Log " WARN: session snapshot threw: $_" +} + +try { + $evtx = Join-Path $ppkgLogDir 'Provisioning-Diagnostics-Admin.evtx' + if (Test-Path $evtx) { Remove-Item $evtx -Force -ErrorAction SilentlyContinue } + $null = & wevtutil.exe epl 'Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin' $evtx 2>&1 + if (Test-Path $evtx) { Log " exported $evtx" } +} catch { + Log " WARN: wevtutil export threw: $_" +} + # --- Set OOBE complete (only reached if PPKG didn't trigger immediate 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 diff --git a/playbook/startnet.cmd b/playbook/startnet.cmd index a5f9cbf..00bded6 100644 --- a/playbook/startnet.cmd +++ b/playbook/startnet.cmd @@ -137,8 +137,9 @@ if "%standard_choice%"=="1" set PCSUBTYPE=Timeclock if "%standard_choice%"=="2" set PCSUBTYPE=Machine if "%PCSUBTYPE%"=="" goto standard_menu -REM --- Machine number (Standard only) --- +REM --- Machine number (Standard-Machine only; Timeclock PCs do not use one) --- set MACHINENUM=9999 +if "%PCSUBTYPE%"=="Timeclock" goto skip_standard_menu echo. set /p MACHINENUM=Enter machine number (digits, or Enter for 9999): if "%MACHINENUM%"=="" set MACHINENUM=9999 diff --git a/startnet-template.cmd b/startnet-template.cmd index a5f9cbf..00bded6 100644 --- a/startnet-template.cmd +++ b/startnet-template.cmd @@ -137,8 +137,9 @@ if "%standard_choice%"=="1" set PCSUBTYPE=Timeclock if "%standard_choice%"=="2" set PCSUBTYPE=Machine if "%PCSUBTYPE%"=="" goto standard_menu -REM --- Machine number (Standard only) --- +REM --- Machine number (Standard-Machine only; Timeclock PCs do not use one) --- set MACHINENUM=9999 +if "%PCSUBTYPE%"=="Timeclock" goto skip_standard_menu echo. set /p MACHINENUM=Enter machine number (digits, or Enter for 9999): if "%MACHINENUM%"=="" set MACHINENUM=9999