From a57ed5fd96681ae1eaa3a10ee7fb57da9a929c2f Mon Sep 17 00:00:00 2001 From: cproudlock Date: Wed, 13 May 2026 14:05:50 -0400 Subject: [PATCH] winpe: externalize WinPE-phase status push to scripts/winpe-status-push.ps1 The inline one-liner in startnet.cmd called Get-NetAdapter, which is not available in WinPE's stripped PowerShell (no NetTCPIP module). Errors silently swallowed by the surrounding try/catch - POST never fired, dashboard never showed bays during the WIM-apply phase. Externalize to a standalone .ps1 on the enrollment share: * Uses wmic (always present in WinPE 10+) for both serial AND mac instead of Get-CimInstance / Get-NetAdapter. * Logs every step to X:\Windows\Temp\winpe-status-push.log so a future "POST didn't fire" debug is one file read away. * startnet.cmd now just runs powershell -File Y:\scripts\winpe-status- push.ps1. Future edits to the push logic do NOT require a boot.wim rebuild; just edit the .ps1 on the share. Mirror the existing pattern for run-enrollment.ps1 / wait-for-internet.ps1 / migrate-to-wifi.ps1 (all already at /srv/samba/enrollment/scripts/). Add the new file to the playbook's enrollment-scripts copy loop. Co-Authored-By: Claude Opus 4.7 (1M context) --- playbook/pxe_server_setup.yml | 1 + playbook/startnet.cmd | 12 +++--- playbook/winpe-status-push.ps1 | 75 ++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 playbook/winpe-status-push.ps1 diff --git a/playbook/pxe_server_setup.yml b/playbook/pxe_server_setup.yml index d52323e..80ad051 100644 --- a/playbook/pxe_server_setup.yml +++ b/playbook/pxe_server_setup.yml @@ -404,6 +404,7 @@ - { src: "{{ usb_mount }}/shopfloor-setup/run-enrollment.ps1", dest: "run-enrollment.ps1" } - { src: "{{ usb_mount }}/wait-for-internet.ps1", dest: "wait-for-internet.ps1" } - { src: "{{ usb_mount }}/migrate-to-wifi.ps1", dest: "migrate-to-wifi.ps1" } + - { src: "{{ usb_mount }}/winpe-status-push.ps1", dest: "winpe-status-push.ps1" } ignore_errors: yes - name: "Deploy site-config.json to config/" diff --git a/playbook/startnet.cmd b/playbook/startnet.cmd index 0ebd7b1..475b413 100644 --- a/playbook/startnet.cmd +++ b/playbook/startnet.cmd @@ -247,12 +247,12 @@ goto end echo. REM --- Push initial "WinPE staging" status to PXE webapp --- -REM Best-effort POST so the imaging dashboard shows this bay during the -REM WinPE / WIM-apply phase, BEFORE Run-ShopfloorSetup.ps1 takes over the -REM status updates post-PPKG. Identifies the session by BIOS serial. -REM Errors are swallowed - never block imaging on a status push. -for /f "tokens=2 delims==" %%S in ('wmic bios get serialnumber /value 2^>nul ^| find "="') do set BIOS_SERIAL=%%S -powershell -NoProfile -ExecutionPolicy Bypass -Command "try { $body = @{ serial=$env:BIOS_SERIAL; mac=((Get-NetAdapter -Physical | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1).MacAddress -replace '-',':'); pctype=$env:PCTYPE; current_stage='WinPE: PESetup / WIM apply'; stage_index=1; stage_total=8; status='in_progress' } | ConvertTo-Json -Compress; Invoke-WebRequest -Uri 'http://10.9.100.1:9009/imaging/status' -Method POST -Body $body -ContentType 'application/json' -UseBasicParsing -TimeoutSec 5 | Out-Null } catch { }" +REM Externalized to Y:\scripts\winpe-status-push.ps1 so future edits don't +REM require a boot.wim rebuild. Best-effort; the script logs to +REM X:\Windows\Temp\winpe-status-push.log and swallows all errors. +if exist "Y:\scripts\winpe-status-push.ps1" ( + powershell -NoProfile -ExecutionPolicy Bypass -File "Y:\scripts\winpe-status-push.ps1" +) echo Waiting for PESetup.exe to start... :wait_start diff --git a/playbook/winpe-status-push.ps1 b/playbook/winpe-status-push.ps1 new file mode 100644 index 0000000..ba7051e --- /dev/null +++ b/playbook/winpe-status-push.ps1 @@ -0,0 +1,75 @@ +# winpe-status-push.ps1 - Posts "WinPE: PESetup / WIM apply" status to the +# PXE webapp /imaging/status endpoint so the imaging dashboard reflects +# this bay BEFORE Run-ShopfloorSetup.ps1 takes over post-PPKG. +# +# Runs in WinPE's stripped PowerShell - cannot rely on Get-NetAdapter, +# Get-CimInstance, or the NetTCPIP module (none are present in stock +# WinPE). Uses wmic for both serial and MAC. +# +# Best-effort: never blocks imaging. All steps log to +# X:\Windows\Temp\winpe-status-push.log; failures are swallowed. + +param( + [string]$PxeServer = '10.9.100.1', + [int]$Port = 9009, + [int]$TimeoutSec = 5, + [string]$PCType = $env:PCTYPE +) + +$logFile = 'X:\Windows\Temp\winpe-status-push.log' +function Log { + param([string]$msg) + try { "$(Get-Date -Format s) $msg" | Out-File -FilePath $logFile -Append -Encoding utf8 } catch { } +} + +Log "=== winpe-status-push start ===" +Log "server=$PxeServer:$Port pctype=$PCType" + +# Serial via wmic. Always available in WinPE 10+. +$serial = '' +try { + $line = (& wmic bios get serialnumber /value 2>$null | Where-Object { $_ -match '=' } | Select-Object -First 1) + if ($line) { $serial = ($line -split '=', 2)[1].Trim() } +} catch { Log "serial wmic exception: $_" } +Log "serial=$serial" + +# MAC via wmic NIC enumeration. NetEnabled filter restricts to up adapters. +$mac = '' +try { + $macLines = & wmic nic where 'NetEnabled=TRUE' get MacAddress /value 2>$null | + Where-Object { $_ -match 'MacAddress=' } + if ($macLines) { + $first = ($macLines | Select-Object -First 1) + $mac = (($first -split '=', 2)[1]).Trim() -replace '-', ':' + } +} catch { Log "mac wmic exception: $_" } +Log "mac=$mac" + +if (-not $serial) { + Log "no serial captured - aborting POST" + exit 0 +} + +# Compose JSON. ConvertTo-Json works in WinPE. +$payload = @{ + serial = $serial + pctype = $PCType + current_stage = 'WinPE: PESetup / WIM apply' + stage_index = 1 + stage_total = 8 + status = 'in_progress' +} +if ($mac) { $payload.mac = $mac } +$body = $payload | ConvertTo-Json -Compress +$uri = "http://${PxeServer}:${Port}/imaging/status" +Log "POST $uri body=$body" + +try { + $resp = Invoke-WebRequest -Uri $uri -Method POST -Body $body ` + -ContentType 'application/json' -UseBasicParsing -TimeoutSec $TimeoutSec -ErrorAction Stop + Log "OK http=$($resp.StatusCode)" +} catch { + Log "ERR $($_.Exception.Message)" +} + +exit 0