wimcast: building Windows images on Linux, without Windows
The Foreman Windows provisioning path runs through WIM files: boot.wim, per-edition install.wim, bootmgr, the BCD store. Every tool that produces that tree (WIMan, GenerateWIM.ps1) assumes a Windows host with the ADK installed and an admin shell. That is an entire machine idling for one PowerShell script. wimcast
(pip install wimcast, MIT) is the replacement I wrote: Windows ISOs in, Foreman-ready HTTP tree out, unprivileged on Linux. No Windows host, no root, no mount(2), no FUSE, no ADK.
The three commands
wimcast doctor # check prerequisites, safe, installs nothing
wimcast probe sources/ # inspect your ISOs before building
wimcast build sources/ # build the finalized/ tree
doctor reports what is missing and whether it is required or conditional. probe reads the ISOs (pycdlib, no mounting) and shows editions and indexes before you commit. build produces the tree: sources/ per edition (each *.wim + images.ini + drivers/), plus wimboot, bootmgr{,.efi}, boot/{bcd,sdi} and a build.json describing what was built. The result is serve-over-HTTP ready for Foreman.
Why a rewrite and what the rewrite fixed
The “before” was my own PowerShell pipeline (wiman-builder) driving a WIMan fork on a Windows CI shell runner. Retiring it fixed four things at once:
- wimboot pinned and checksummed, not
latestdownloaded per build. The image tree becomes reproducible; a wimboot release cannot change under you. - Content-addressed cache: an unchanged ISO skips the re-export entirely. Serial builds that re-exported everything became parallel builds (scheduler with CPU semaphores) that skip most of the work.
- The drivers tree gets published:
sources/drivers/ships in the output for deploy-time DISM. The WIMan original had the drivers on disk but never published them: a production bug hiding in plain sight. - The CI runner is any Linux box. The Windows shell runner, its license and its ADK install went to the retirement home.
Under the hood it is wimtools for WIM manipulation and pycdlib for ISO reading, orchestrated in python with mypy strict, ruff and golden-file tests. Nothing exotic: the exotic part was pretending Windows was required.
Windows without Windows
- “Needs Windows” is usually “needs a Windows file format”. WIM, BCD and bootmgr are files; reading them unprivileged beats booting a host to touch them.
- Pinned inputs beat fresh downloads. The wimboot checksum is the difference between a reproducible tree and a gamble.
- A cache keyed on content beats a cache keyed on hope. ISOs are immutable; hashing them is cheaper than re-exporting them.
doctorcommands earn their keep. Telling users exactly what is missing and whether it matters, prevents half the support tickets a CLI ever generates.