Engineer builds left the employee without "Configure my Engineering
Layer". First logon ran C:\Deploy\Applications\extra_engineering\
Install-EngineeringLayer.ps1, and the script itself lived in C:\Deploy:
std/eng have no autologon, so a PC that rebooted before the employee
signed in had lost C:\Deploy to the orchestrator's DeleteDeployDir task,
and nothing installed, silently.
- engineer unattend, specialize Order 37 (free slot): run the script with
-StageOnly, copying the payload and the script to C:\PreInstall\engineering
while C:\Deploy exists (Path 119 chars)
- first logon Order 11: run it from C:\PreInstall\engineering, falling back
to C:\Deploy if staging did not happen
- the script (now in the repo, playbook/engineering/; it lived only on the
server): after the install, restore the Public desktop icon if it is
missing and the PC is not configured yet (no C:\TMP\DUU_Complete.log), and
register Active Setup so each later user gets the icon on their own
desktop when the Public one is gone. v3.1 puts the icon on the Public
desktop; clicking it (configure, from GE's V: share) deletes it for all
- playbook deploys the script to gea-engineer extra_engineering; the 650 MB
payload stays site content (documented in SITE-CUSTOMIZATION.md)
Tested in the win11 VM with the exact unattend strings and a stand-in
installer that skips the icon: specialize staged payload and script;
C:\Deploy deleted; first logon installed from the staged copy, restored the
icon and registered Active Setup. The per-user step as a new user: icon on
their desktop when the PC is unconfigured and the Public icon is gone; none
when configured or when the Public icon is there. Lint clean. Not deployed:
unattends go out only through scripts/deploy-unattend.sh.
Everything after OOBE needs the employee to log in, which happens off the
PXE network, so the floor waited forever at step 3 of 5. Now 3 steps:
WinPE, Windows setup installing apps, ready at OOBE (succeeded).
- both unattends: specialize Order 49 posts step 3 as succeeded
(Path 182 chars; lint clean). Only that line changed.
- Send-ImagingStage.ps1: StageTotal 3; steps above the total (the old
first-logon steps 4 and 5 still in the unattends) are logged and not
posted, so they cannot reopen a finished build
- winpe-status-push.ps1: total 3 for gea-standard / gea-engineer
- floor tile step 3: "Ready at OOBE"
Tested in the win11 VM against the test server: steps 2 and 3 post,
step 3 shows succeeded, step 4 is skipped. Not deployed: the unattends
go out only through scripts/deploy-unattend.sh.
a94c203 added a RunSynchronous Path of 417 chars to both std/eng answer
files. Windows caps it at 259 and then rejects the WHOLE answer file, so
an Engineer build stopped at 'Windows could not parse or process unattend
answer file'. The live files were restored to their pre-a94c203 versions
the same day.
- The status steps now fit: Send-ImagingStage.ps1 -Persist copies itself
out of C:\Deploy (no cmd copy chain), short PowerShell switches, default
arguments left out. Longest Path is 168 chars; lint-unattend passes.
NOT deployed: these files must go live only through deploy-unattend.sh.
- scripts/deploy-unattend.sh: the only route for an answer file to a PXE
server. Lints first and refuses on any error, backs up, swaps
atomically, lints the live copy and restores the backup if that fails.
- .githooks/pre-commit (git config core.hooksPath .githooks): refuses a
commit whose staged unattend fails the linter. Verified by planting a
352-char Path (blocked) and against the exact a94c203 file (rejected).
- Boot menu: also accept SecureBoot read as hex 01, and show the raw values
in the warning so a wrong read can be diagnosed from the screen.
The floor's 8 stages are the shopfloor pipeline, and only shopfloor-setup
reports after WinPE, so every gea-standard / gea-engineer build sat at
1/8 forever with no type.
- winpe-status-push.ps1 reads the image from the Z: share mapping when no
PCTYPE is set and reports those builds as 5 steps.
- Send-ImagingStage.ps1 (deployed to _shared\Applications\extra\pxe-status)
posts steps 2-5 from the unattend: start and end of specialize, first
logon, and setup complete (succeeded). It is copied to
C:\ProgramData\PxeStatus first, because the bulk-enrollment task deletes
C:\Deploy before first logon. Best-effort: always exits 0.
- Floor rows use Standard/Engineer labels and show the image as the kind.
Tested as SYSTEM in the win11 VM (PowerShell 5.1): the exact unattend
command line, stages 3-5 against a test server, a dead port (exit 0), and
the image regex.
The EAP-PEAP and Office comments outlived the entries they labelled, which
would send the next reader looking for commands that are not there. The
surviving wireless comment said 'Wi-Fi profiles' plural when only
INTERNETACCESS remains; it now records why the other two went and that
wlansvc has to be started first.
INTERNETACCESS has never been deployed. wlansvc ships Manual/Stopped on
Windows 11, nothing in the unattend started it, and `netsh wlan add profile`
refuses to run without it:
The Wireless AutoConfig Service (wlansvc) is not running.
exit=1
Reproduced in the win11 VM. So specialize was adding no wireless profile at
all, and every bay reached OOBE with no known network - which is exactly the
wifi/network selection the tech has been clicking through.
Fixed by starting the service first. `net start`, NOT `sc start`: sc is
asynchronous and returns START_PENDING, and the VM showed netsh losing that
race and still reporting the service as not running. The command is idempotent
and always exits 0, so a machine with no wireless hardware is unaffected.
With the profile genuinely landing, HideWirelessSetupInOOBE is now true.
Dropped EAP-PEAP and BLUESSO from specialize while here. Both are installed by
the MCL ppkg - Install-GEWirelessSettings.ps1, with byte-identical EAP-PEAP.msi
(sha d90f2489045b6fdb) and BLUESSO.xml (sha d8d886db37a40054) - and BLUESSO
could never have bootstrapped anything: hidden SSID, connectionMode=manual,
eapGtc with passwordFromUser. INTERNETACCESS is the bootstrap path and it is
WPA2PSK with connectionMode=auto, so it needs no EAP module and no certificate.
The eight GE certificates at Orders 4-11 are also duplicated by the ppkg (as
Certificates_*.provxml runtime entries) and are left in place for now: that is
a separate cut, and the case for removing them rests on the pre-ppkg token
fetch being publicly signed, which is true today (mcl.dwcdn.geaerospace.com is
issued by Google Trust Services) but is not ours to depend on.
lint-unattend.py passes clean on all three live files and all three repo copies.
Zscaler: Install-Zscaler.ps1 ships in all three MCL packages with
Zscaler-windows-4.7.0.317-installer-x64.msi bundled. It is tenant-aware
(geaerospace.com for GCCH, geaerospaceglobal.com for RoW, gegovdev.us for QA)
and passes enableFips=1.
Our FirstLogonCommands entry installed 4.5.0.337, two minor versions older,
without enableFips, and with userDomain hardcoded to geaerospace.com - wrong
for a RoW bay, which startnet's tenant sub-menu can produce. Two msiexec runs
against the same product at one logon also risk 1618. Removed, same reasoning
as Office.
THE BIGGER FIND, while removing it: this repo template was badly out of date
with the share, and the playbook deploys it with force: yes.
Missing here but present live: specialize Orders 39-48 - the bulk-enrollment
orchestrator registration (Order 39, Register-BulkEnrollTask-Standard.ps1), the
Default User startup-delay and Start-menu tweaks, the two NoAutoUpdate keys,
the 'vanilla' Shift+F10 fallback alias, and the removable-media block that stops
the PPKG being auto-detected at OOBE. Also missing: FirstLogonCommands Orders
4-10 (wuauserv disable, Default User hive edits, removable-media unblock).
A playbook run would therefore have stripped enrollment from every gea-standard
and gea-engineer bay. Both templates are now reconciled against the live share.
Engineer gets its own template. The two files differ only by FirstLogonCommands
Order 11, which installs the Engineering Layer - so deploying one shared file to
both, as the playbook did, silently removed that entry from gea-engineer on
every run. Split into FlatUnattendW10.xml and FlatUnattendW10-engineer.xml with
an explicit per-type loop.
lint-unattend.py passes clean on all three live files and all three repo copies.