Shopfloor unattend: move Orders 4/5 logic to external PS1 scripts

FlatUnattendW10-shopfloor.xml was rejected by Windows OOBE with
"the answer file is invalid" after the earlier tower-no-WiFi fix.
Root cause: the inline PowerShell in <CommandLine> for Orders 4 and
5 exceeded the SynchronousCommand CommandLine length limit (~1024
chars) and/or contained characters the unattend schema validator
dislikes.

Fix: move the logic to two external PS1 scripts and shrink both
CommandLine entries to ~85 chars each that just invoke the scripts.

- playbook/wait-for-internet.ps1: 60s interactive prompt ("connect
  production network now"), then poll TCP 443 to login.microsoft-
  online.us for up to 10 min with a hard timeout so the loop always
  exits. Uses Test-NetConnection -Port 443 (not Test-Connection /
  ICMP) because Microsoft 365 edges do not reliably respond to ping.
- playbook/migrate-to-wifi.ps1: Gates the entire wired-disable
  migration on "does a WiFi adapter exist?" If not (tower), the
  script is a no-op. If yes, disable wired / wait for WiFi internet
  with a 5 min timeout / re-enable wired on timeout fallback.
- startnet.cmd stages both new scripts to W:\Enrollment\ next to
  run-enrollment.ps1 during the WinPE phase.
- FlatUnattendW10-shopfloor.xml Orders 4 and 5 shrunk to short
  invocations of C:\Enrollment\wait-for-internet.ps1 and
  C:\Enrollment\migrate-to-wifi.ps1.
- startnet-template.cmd kept in sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-04-11 16:50:58 -04:00
parent 3ea20b271e
commit c595d3b9cb
5 changed files with 109 additions and 4 deletions

View File

@@ -156,13 +156,13 @@
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>4</Order>
<CommandLine>powershell.exe -ExecutionPolicy Bypass -Command "Write-Host ''; Write-Host '========================================' -ForegroundColor Yellow; Write-Host ' Connect to PRODUCTION network NOW' -ForegroundColor Yellow; Write-Host ' Towers: unplug PXE, plug into production' -ForegroundColor Yellow; Write-Host ' Laptops: WiFi should already be connected' -ForegroundColor Yellow; Write-Host '========================================' -ForegroundColor Yellow; Write-Host ''; Write-Host 'Auto-continuing in 60s (press any key to skip)...' -ForegroundColor Cyan; $end=(Get-Date).AddSeconds(60); while ((Get-Date) -lt $end) { if ($Host.UI.RawUI.KeyAvailable) { $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown'); break }; Start-Sleep -Milliseconds 500 }; Write-Host 'Waiting for internet connectivity (up to 10 min)...'; $end2=(Get-Date).AddMinutes(10); $ok=$false; while ((Get-Date) -lt $end2) { if (Test-NetConnection -ComputerName login.microsoftonline.us -Port 443 -InformationLevel Quiet -WarningAction SilentlyContinue) { $ok=$true; break }; Start-Sleep -Seconds 5 }; if ($ok) { Write-Host 'Internet connected.' -ForegroundColor Green } else { Write-Host 'Internet wait timeout - proceeding anyway.' -ForegroundColor Yellow }"</CommandLine>
<Description>Prompt to connect production network, then wait for TCP 443 to login.microsoftonline.us (with 10 min timeout). Uses Test-NetConnection -Port 443 not Test-Connection because Microsoft 365 endpoints do not reliably respond to ICMP.</Description>
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\wait-for-internet.ps1"</CommandLine>
<Description>Prompt to connect production network then wait for TCP 443 connectivity</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>5</Order>
<CommandLine>powershell.exe -ExecutionPolicy Bypass -Command "$wifi = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.InterfaceDescription -match 'Wi-Fi|Wireless' }; if (-not $wifi) { Write-Host 'No WiFi adapter - staying on ethernet.' -ForegroundColor Cyan; exit 0 }; Get-NetAdapter -Physical | Where-Object { $_.InterfaceDescription -notmatch 'Wi-Fi|Wireless' } | Disable-NetAdapter -Confirm:$false; $end=(Get-Date).AddMinutes(5); $ok=$false; while ((Get-Date) -lt $end) { if (Test-NetConnection -ComputerName login.microsoftonline.us -Port 443 -InformationLevel Quiet -WarningAction SilentlyContinue) { $ok=$true; break }; Start-Sleep -Seconds 5 }; if ($ok) { Write-Host 'Internet confirmed over WiFi.' -ForegroundColor Green } else { Write-Host 'WiFi internet timeout - re-enabling ethernet.' -ForegroundColor Yellow; Get-NetAdapter -Physical | Where-Object { $_.InterfaceDescription -notmatch 'Wi-Fi|Wireless' } | Enable-NetAdapter -Confirm:$false }"</CommandLine>
<Description>If WiFi adapter exists, migrate off wired onto WiFi for enrollment. Tower/desktop with no WiFi: skip entirely and stay on wired. Fall back to re-enabling wired if WiFi fails.</Description>
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\migrate-to-wifi.ps1"</CommandLine>
<Description>Migrate from wired to WiFi if WiFi adapter present, else stay on wired</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>6</Order>

View File

@@ -0,0 +1,43 @@
# migrate-to-wifi.ps1 - Invoked by FlatUnattendW10-shopfloor.xml as Order 5
# during first logon, right after wait-for-internet.ps1 and right before
# GCCH enrollment. Moves the machine off wired onto WiFi for the rest of
# the imaging chain so the PXE ethernet cable can be safely disconnected.
#
# Gated: if there is no physical Wi-Fi adapter on the machine (tower /
# desktop case), the whole migration is a no-op. Previously this step
# disabled all wired adapters unconditionally and then waited for WiFi
# internet that could never arrive on towers, hanging first logon forever.
$wifi = Get-NetAdapter -Physical -ErrorAction SilentlyContinue |
Where-Object { $_.InterfaceDescription -match 'Wi-Fi|Wireless' }
if (-not $wifi) {
Write-Host 'No WiFi adapter - staying on ethernet.' -ForegroundColor Cyan
exit 0
}
Get-NetAdapter -Physical |
Where-Object { $_.InterfaceDescription -notmatch 'Wi-Fi|Wireless' } |
Disable-NetAdapter -Confirm:$false
$deadline = (Get-Date).AddMinutes(5)
$ok = $false
while ((Get-Date) -lt $deadline) {
try {
if (Test-NetConnection -ComputerName login.microsoftonline.us -Port 443 -InformationLevel Quiet -WarningAction SilentlyContinue) {
$ok = $true
break
}
} catch {}
Start-Sleep -Seconds 5
}
if ($ok) {
Write-Host 'Internet confirmed over WiFi.' -ForegroundColor Green
} else {
Write-Host 'WiFi internet timeout - re-enabling ethernet.' -ForegroundColor Yellow
Get-NetAdapter -Physical |
Where-Object { $_.InterfaceDescription -notmatch 'Wi-Fi|Wireless' } |
Enable-NetAdapter -Confirm:$false
}
exit 0

View File

@@ -266,6 +266,8 @@ if errorlevel 1 (
goto copy_pctype
)
copy /Y "Y:\run-enrollment.ps1" "W:\Enrollment\run-enrollment.ps1"
copy /Y "Y:\wait-for-internet.ps1" "W:\Enrollment\wait-for-internet.ps1"
copy /Y "Y:\migrate-to-wifi.ps1" "W:\Enrollment\migrate-to-wifi.ps1"
REM --- Create enroll.cmd at drive root as manual fallback ---
> W:\enroll.cmd (

View File

@@ -0,0 +1,58 @@
# wait-for-internet.ps1 - Invoked by FlatUnattendW10-shopfloor.xml as Order 4
# during first logon, right before GCCH enrollment. Previously the logic was
# inline in the unattend's CommandLine attribute but the string exceeded
# Microsoft's SynchronousCommand CommandLine length limit and Windows rejected
# the whole answer file with "the answer file is invalid". Moved here to keep
# the unattend CommandLine short.
#
# Behaviour:
# 1. Print a 60-second prompt asking the tech to connect to production
# network. Gives tower users a window to unplug PXE cable and re-cable
# to a production port; laptop users are already on WiFi and can
# press any key to skip.
# 2. Poll TCP 443 to login.microsoftonline.us for up to 10 minutes using
# Test-NetConnection (NOT Test-Connection / ICMP - Microsoft 365 edges
# do not reliably respond to ICMP, which previously caused infinite
# "Waiting for internet connectivity..." loops on towers).
# 3. Always exit 0 so the unattend chain proceeds even if detection times
# out - enrollment will retry on its own if the network is still broken.
Write-Host ''
Write-Host '========================================' -ForegroundColor Yellow
Write-Host ' Connect to PRODUCTION network NOW' -ForegroundColor Yellow
Write-Host ' Towers: unplug PXE, plug into production' -ForegroundColor Yellow
Write-Host ' Laptops: WiFi should already be connected' -ForegroundColor Yellow
Write-Host '========================================' -ForegroundColor Yellow
Write-Host ''
Write-Host 'Auto-continuing in 60s (press any key to skip)...' -ForegroundColor Cyan
$end = (Get-Date).AddSeconds(60)
while ((Get-Date) -lt $end) {
try {
if ($Host.UI.RawUI.KeyAvailable) {
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
break
}
} catch {}
Start-Sleep -Milliseconds 500
}
Write-Host 'Waiting for internet connectivity (up to 10 min)...'
$deadline = (Get-Date).AddMinutes(10)
$ok = $false
while ((Get-Date) -lt $deadline) {
try {
if (Test-NetConnection -ComputerName login.microsoftonline.us -Port 443 -InformationLevel Quiet -WarningAction SilentlyContinue) {
$ok = $true
break
}
} catch {}
Start-Sleep -Seconds 5
}
if ($ok) {
Write-Host 'Internet connected.' -ForegroundColor Green
} else {
Write-Host 'Internet wait timeout - proceeding anyway.' -ForegroundColor Yellow
}
exit 0

View File

@@ -266,6 +266,8 @@ if errorlevel 1 (
goto copy_pctype
)
copy /Y "Y:\run-enrollment.ps1" "W:\Enrollment\run-enrollment.ps1"
copy /Y "Y:\wait-for-internet.ps1" "W:\Enrollment\wait-for-internet.ps1"
copy /Y "Y:\migrate-to-wifi.ps1" "W:\Enrollment\migrate-to-wifi.ps1"
REM --- Create enroll.cmd at drive root as manual fallback ---
> W:\enroll.cmd (