PESETUP-INTERNALS.md was written from a decompiled 4.0.0.17. The media in production reports 4.0.0.20 in its own log. Rather than restate the document as 4.0.0.20, which would claim a re-derivation that has not happened, it now names both: line-level claims are 4.0.0.17, and the behaviour re-observed on bay 579C144 on 2026-08-06 is listed so a reader knows which parts are confirmed current - media drive Z:, W: created by PrepareDisk and used for every copy destination, the fallback Deploy\FlatUnattendW10.xml being the unattend that loads, and driver selection by model. FlatUnattendW10-shopfloor.xml carried LogonCount 7 while the live shopfloor unattend has 12, and Run-ShopfloorSetup.ps1's comment about topping up the autologon budget already said 12. The live value is the real one, so the repo follows it. Both files still lint clean under scripts/lint-unattend.py.
12 KiB
PESetup.exe internals
What GE Image Setup actually does, start to finish. Written from the decompiled assembly, not from observation, because several long-standing beliefs about this tool turned out to be wrong and cost weeks of debugging.
Version documented: 4.0.0.17 (Sources/PESetup.exe, PE32+ native apphost
wrapping a .NET 6 single-file bundle, 468 embedded files).
Version in production: 4.0.0.20, as of 2026-08-06 — the media reports it in
its own log (AppVersion: 4.0.0.20). Everything in this document was verified
against a 4.0.0.20 run on bay 579C144 that day: the media drive resolved to Z:\,
W: was created by PrepareDisk and used for every copy destination, the fallback
unattend at Deploy\FlatUnattendW10.xml was the one loaded, and driver selection
matched win11_optiplexd13mlk7020_a09.zip by model. The decompiled detail below has
not been re-derived from the 4.0.0.20 binary, so treat exact line-level claims as
4.0.0.17 and the observed behaviour as current.
How to re-derive this
The managed code is not directly readable - the outer PE has no managed
metadata, so ILSpy refuses it. Extract PESetup.dll from the bundle first:
# .NET single-file bundle: signature is SHA-256 of ".net core bundle";
# the int64 EIGHT BYTES BEFORE it is the bundle header offset.
SIG = bytes([0x8b,0x12,0x02,0xb9,0x6a,0x61,0x20,0x38,
0x72,0x7b,0x93,0x02,0x14,0xd7,0xa0,0x32])
i = data.find(SIG)
header = struct.unpack_from('<q', data, i - 8)[0]
# header: uint32 major, uint32 minor, int32 count, 7-bit-prefixed bundle id,
# then (v2+) 4 x int64 deps/runtimeconfig, then uint64 flags.
# each entry: int64 offset, int64 size, (v6+) int64 compressedSize,
# byte type, 7-bit-prefixed path. Compressed entries are raw
# deflate (zlib.decompress(raw, -15)).
Then ilspycmd -t <TypeName> PESetup.dll.
Paths it hardcodes
From PESetup.Models.GlobalSettings. All are relative to the MEDIA drive
(Z:\, whichever winpeapps share startnet mapped) unless stated.
ControlDir \Deploy\Control
ToolsDir \Deploy\Tools\GE
SoftwarePackagesDir \Deploy\Applications
HWPackagesDir \Deploy\HW_Apps
UnattendFile \Deploy\Tools\GE\XML\FlatUnattendW10.xml
UnattendFile2 \Deploy\FlatUnattendW10.xml (fallback)
DiskPartDir <exe dir>\DiskPart
ConfigSkipPackagesFile skip.json
ConfigDisableAutoStartFile disableauto.json
ExpirationDuration 30 days
AutoStartCountDown 31
MinRequiredSpaceWithoutCompression 128849018880 (120 GB)
W: IS HARDCODED, EVERYWHERE. Not derived, not configurable, not a
convention this project invented:
CopyPackages destDir = "W:\\" + SoftwarePackagesDir
CopyHWPackages destDir = "W:\\" + HWPackagesDir
CopyTools destDir = "W:\\GE"
CopyDrivers destinationPath = "W:\\Drivers\\" + <zip name without extension>
ApplyImage destination = "W:\\"
CreateBCD "W:\\Windows\\System32\\bcdboot.exe", "W:\\Windows /l en-US"
ApplyPackages DismApi.OpenOfflineSession("W:\\")
CopyLogs tags -> "w:\\windows\\system32\\"
PESetup's own disk preparation is what makes W: exist. Any downstream script
that hunts for "the applied volume" is solving a problem this tool does not
have. diskpart list volume on a machine mid-image shows Volume 0 W Windows NTFS 237GB Healthy.
The five working steps
Keys as they appear in the log: workingstep_gatherdata, workingstep_selectos,
workingstep_prepare, workingstep_copy, workingstep_apply,
workingstep_finalize, workingstep_reboot.
1. GATHER DATA
Four operations, all automatic:
| Operation | What it establishes |
|---|---|
GatherDataMediaDrive |
ImageInfo.MediaDrive, e.g. Z:\ |
GatherDataBootDrive |
ImageInfo.BootDrive, always X:\ (WinPE RAM disk) |
GatherDataSelection |
BIOS version/type, serial, secure boot, OS, languages, model, driver |
GatherDataImageDisk |
picks the physical disk and logs its partitions |
GatherDataSelection is where most decisions are made:
- Secure boot is mandatory.
SecurebootEnabled != 1fails the step outright. - Reads
Control\LanguagePacks.json. SystemHelpers.GetModel()andGetManufacturer()off WMI.- Reads
Control\HardwareDriver.jsonandControl\hw_applications.json. NOTE: it reads HardwareDriver.json, not thehw_drivers.jsonthat also sits in that folder. Editing the wrong one changes nothing. - Virtual platform check. If ANY driver entry has a manufacturer containing
"virtual platform", the tool goes into virtual-only mode: it takes
list[0]as the driver and then REQUIRES the machine to look virtual (model/serial/BIOS containing VIRTUAL, VMWARE, XEN, QEMU, VirtualBox, vmw). On real hardware that is a hard failure. A stray "virtual platform" entry in the catalogue therefore breaks imaging for every physical machine. - Otherwise
GetDriverByModel(below). - If
Control\skip.jsonexists, package installation is skipped.
2. SELECT OS
Operator-facing. Warns when the media holds an LTSC image ("99% of the time only
for ShopFloor"). Also shows days-to-expiry - the media expires 30 days after
build (ExpirationDuration).
3. PREPARE
| Operation | What it does |
|---|---|
PrepareDoDisking |
copies <exedir>\DiskPart\diskpartEFI.txt to X:\diskpartEFI<n>.txt, then cmd /c DISKPART /S X:\diskpartEFI<n>.txt |
PrepareUnattend |
loads the unattend, substitutes, saves to X:\Unattend.xml |
PrepareUnattend in detail:
text = MediaDrive + UnattendFile; // \Deploy\Tools\GE\XML\FlatUnattendW10.xml
if (!File.Exists(text)) text = MediaDrive + UnattendFile2; // \Deploy\FlatUnattendW10.xml
xml.Load(text);
xml.InnerXml = xml.InnerXml.Replace("%serialnumber%", imageinfo.Serialnumber);
xml.InnerXml = xml.InnerXml.Replace("*arch*", arch);
SetPackages(arch, xml, imageinfo); // needs Control\Packages.xml
xml.Save("X:\\Unattend.xml");
Two tokens are substituted: %serialnumber% and *arch*. SetPackages merges
in servicing packages from Control\Packages.xml and Control\PackageGroups.xml.
The unattend that is USED is the one on the media at Tools\GE\XML\ if present,
otherwise Deploy\FlatUnattendW10.xml. A shopfloor variant only takes effect if
it occupies one of those two paths.
4. COPY
Four operations. None of them filters, and none of them reads the unattend.
| Operation | Source | Destination | Rule |
|---|---|---|---|
CopyTools |
Z:\Deploy\Tools\GE |
W:\GE |
whole directory, recursive |
CopyPackages |
Z:\Deploy\Applications |
W:\Deploy\Applications |
whole directory, recursive |
CopyHWPackages |
Z:\Deploy\HW_Apps |
W:\Deploy\HW_Apps |
whole directory; skipped if IsVirtual or HWApps == null |
CopyDrivers |
one .zip chosen by model |
W:\Drivers\<zipname> |
unzipped, not copied |
ExecuteInternalCopy walks GetDirectoriesRecursive(source, includeSubDirs: true) then Directory.GetFiles(item, "*"). Every file, every subdirectory. It
clears the read-only attribute on each copy.
Consequences worth designing around:
- Anything dropped into
Deploy\Applicationson the media lands on the target. No manifest, no registration, no unattend reference required. - The copy is FAIL-FAST. One exception on one file returns false and fails the
whole step with
copy_packages_error. A locked or unreadable file inApplicationsfails imaging, it does not get skipped. - Progress is computed from total directory size up front, so bulky additions visibly lengthen this phase.
5. APPLY
| Operation | What it does |
|---|---|
ApplyImage |
install.wim from OperatingSystem.json's destinationDir, at wimindex, applied to W:\ |
ApplyPackages |
DISM offline session on W:\, adds servicing packages; logs to X:\ApplyOSPatch_<n>.log |
ApplyLanguagePacks |
same pattern, X:\ApplyLanguagePack_<n>.log |
ApplyUnattend |
DISM offline session on W:\, applies X:\Unattend.xml; logs to X:\ApplyUnattend.log |
CreateBCD |
W:\Windows\System32\bcdboot.exe W:\Windows /l en-US |
CopyWinRE |
reagentc /setreimage /path T:\Recovery\WindowsRE /target W:\Windows |
All DISM work uses W:\imagetemp as scratch and deletes it afterwards.
6. FINALIZE
CopyLogs:
CopyTagFiles(ToolsDir)- every*.tagfrom the tools dir tow:\windows\system32\. This is how build/media tags reach the OS.CopyLogFiles("X:\\")andCopyXMLFile("X:\\")- the PESetup log and the generated unattend are preserved.
Driver selection, in full
This is the part most worth understanding, because a miss is nearly silent.
// GatherDataSelection
List<HardwareDriversRootObject> list =
JSONHelpers.ReadJSON_Driver(MediaDrive + ControlDir + "\\HardwareDriver.json");
...
imageinfo.HWDriver = GetDriverByModel(list, imageinfo.Model);
if (imageinfo.HWDriver == null) {
// status = Warning, message "driver for [MODEL] not found"
return operationResult;
}
private static HardwareDriversRootObject? GetDriverByModel(List<...> drivers, string model)
{
string modelFamily = "";
if (model.ToUpper().Contains("LATITUDE")) modelFamily = "Latitude";
if (model.ToUpper().Contains("OPTIPLEX")) modelFamily = "Optiplex";
if (model.ToUpper().Contains("PRECISION")) modelFamily = "Precision";
return drivers.Where(d => {
if (!string.IsNullOrEmpty(modelFamily) &&
!d.family.ToLower().Contains(modelFamily.ToLower())) return false;
foreach (string token in d.modelswminame.Split(','))
if (model.ToLower().Contains(token.ToLower())) return true; // SUBSTRING
return false;
}).ToList()?.FirstOrDefault();
}
Then:
sourceFilePath = MediaDrive + HWDriver.destinationDir.Replace("*destinationdir*","")
+ "\\" + HWDriver.fileName;
destinationPath = "W:\\Drivers\\" + Path.GetFileNameWithoutExtension(sourceFilePath);
StartUnzipAsync(...)
Four traps in that logic
- A miss is a WARNING, not a failure. Imaging continues and the machine comes up with no drivers - no NIC, no WiFi, so DNS fails and anything network-dependent at first boot fails with it. Symptoms appear far from the cause.
- Matching is substring, first match wins. A token like
7020matches any model string containing 7020. Order in the JSON decides ties. - The family filter knows only three Dell lines. Anything else - MicroPCs,
NUCs, non-Dell - skips the filter and depends entirely on
modelswminamesubstrings being right. - One "virtual platform" entry hijacks the whole catalogue (see GATHER DATA step 5) and fails every physical machine.
What this means for startnet.cmd
Three beliefs encoded in startnet.cmd do not survive contact with the source:
- "The applied volume might not be W:." PESetup hardcodes W: in nine places
and creates it during disk prep. The volume finder, the diskpart
reassignment and the
W:wait loop are machinery around a non-problem. - "We must copy our payload from the enrollment share after imaging." Anything
in
Deploy\Applicationson the media is copied toW:\Deploy\Applicationsby PESetup itself, and is readable atC:\Deploy\Applicationsat first boot. - "Display MicroPCs failed because the applied volume was not W:." Worth
re-testing. A missing
HardwareDriver.jsonmatch produces the same end-state - no drivers, no network - via a completely different route, and that route only logs a warning.
Files PESetup reads from the media
Deploy\Control\HardwareDriver.json driver catalogue (NOT hw_drivers.json)
Deploy\Control\hw_applications.json per-model applications
Deploy\Control\OperatingSystem.json OS list, wim path, wimindex
Deploy\Control\LanguagePacks.json language packs
Deploy\Control\packages.json servicing packages
Deploy\Control\Packages.xml unattend package merge
Deploy\Control\PackageGroups.xml package grouping
Deploy\Control\Media.tag media identity
Deploy\Control\skip.json presence = skip package install
Deploy\Control\disableauto.json presence = disable autostart
Deploy\Tools\GE\XML\FlatUnattendW10.xml preferred unattend
Deploy\FlatUnattendW10.xml fallback unattend