diff --git a/playbook/FlatUnattendW10-shopfloor.xml b/playbook/FlatUnattendW10-shopfloor.xml
index 1678d8e..c387037 100644
--- a/playbook/FlatUnattendW10-shopfloor.xml
+++ b/playbook/FlatUnattendW10-shopfloor.xml
@@ -156,13 +156,13 @@
4
- 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 }"
- 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.
+ powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\wait-for-internet.ps1"
+ Prompt to connect production network then wait for TCP 443 connectivity
5
- 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 }"
- 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.
+ powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\migrate-to-wifi.ps1"
+ Migrate from wired to WiFi if WiFi adapter present, else stay on wired
6
diff --git a/playbook/migrate-to-wifi.ps1 b/playbook/migrate-to-wifi.ps1
new file mode 100644
index 0000000..4792554
--- /dev/null
+++ b/playbook/migrate-to-wifi.ps1
@@ -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
diff --git a/playbook/startnet.cmd b/playbook/startnet.cmd
index 575ca72..003c05b 100644
--- a/playbook/startnet.cmd
+++ b/playbook/startnet.cmd
@@ -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 (
diff --git a/playbook/wait-for-internet.ps1 b/playbook/wait-for-internet.ps1
new file mode 100644
index 0000000..a6519d2
--- /dev/null
+++ b/playbook/wait-for-internet.ps1
@@ -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
diff --git a/startnet-template.cmd b/startnet-template.cmd
index 575ca72..003c05b 100644
--- a/startnet-template.cmd
+++ b/startnet-template.cmd
@@ -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 (