Sysprep workflows A, B, C, and D
Sysprep is fine until you sysprep an image that's already been sysprepped. Then it
fails silently and you spend an afternoon reading setupact.log. This page
covers all four workflows — A (fresh install), B (capture-ready golden), C (audit
mode), D (image refresh) — and the rearm-count gotcha that bites teams whose
documentation stopped at workflow B.
Workflow overview
Sysprep is Windows System Preparation Tool. Its job is to strip machine-specific state (SID, computer name, hardware IDs, activation state) from a Windows installation so the image can be deployed to other machines or resealed for OOBE. The unattend.xml you give to sysprep tells Windows how to reconfigure itself on the next boot.
The four workflows differ in what passes get populated, what sysprep switches get used, and what the output is used for. Choosing the wrong one produces an image that either fails to deploy, double-rearmed itself to death, or leaks state from the previous build.
Are you installing Windows fresh on one machine? YES --> Workflow A (autounattend.xml on install media) Are you building a golden image for the first time? YES, will deploy to identical hardware --> Workflow B + keep_drivers ON YES, will deploy to varied hardware --> Workflow B + keep_drivers OFF Need to add/patch an existing captured golden image? YES --> Workflow D (sysprep over sysprep) Need to build an image through Audit mode with manual configuration before sealing? YES --> Workflow C (auto-boot into audit, you seal at the end)
| Axis | A — Fresh install | B — Golden image | C — Audit mode | D — Image refresh |
|---|---|---|---|---|
| Use case | Install Windows on one machine, unattended. | Build a reference image and capture it for mass deploy. | Build image, customize manually, then seal. | Sysprep over sysprep — refresh an existing golden. |
| Bootable media | Yes (autounattend.xml on USB/ISO root) | Yes (boot once, then capture) | No (you boot once, then live in audit) | No (boot existing image in a VM) |
| Passes populated | windowsPE + specialize + oobeSystem | windowsPE + specialize + generalize + oobeSystem | windowsPE + specialize + auditUser (optional) + oobeSystem (Reseal=Audit) | auditUser + generalize + oobeSystem |
| DISM capture target | No | Yes (the whole point) | Optional (audit gives you the box to customize before capture) | Yes (after the refresh re-seal) |
| Manual sysprep step | No | Required before capture | Required at end (you run sysprep from audit) | Required (the whole workflow is one sysprep run) |
| Rearm count | 0 (no generalize) | 1 per generalize (use SkipRearm=1) | 1 per generalize at the end (use SkipRearm=1) | 1 per refresh — the rearm trap lives here |
| Drivers | Inject via DriverPaths in windowsPE | DriverPaths + PersistAllDeviceInstalls | DriverPaths at install, plus pnputil at audit time | PersistAllDeviceInstalls + pnputil /delete-driver |
| Output destination | \autounattend.xml (media root) | C:\Windows\Panther\unattend.xml | \autounattend.xml (media root) | C:\Windows\Panther\unattend.xml |
Workflow A — Fresh install (boot-from-media)
The 80% case. You have a Windows ISO or USB key. You want Windows to install itself unattended on a clean machine — language, locale, disk partitioning, user account, OOBE skipped — without a human touching a keyboard.
The file is named autounattend.xml and lives at the root of the install
media. Windows Setup finds it automatically during the windowsPE phase,
before any disk formatting happens.
Pass sequence
[Boot from media]
|
v
windowsPE pass <-- disk layout, image selection, driver injection
|
v
specialize pass <-- computer name, domain join, network config
|
v
oobeSystem pass <-- user account creation, OOBE page skips, first-run commands
|
v
[Windows desktop]File placement
USB root or ISO root:
\autounattend.xml <-- Setup finds this automatically
\sources\install.wim <-- standard Windows install image What the builder generates
Selecting Workflow A populates all three passes. The windowsPE pass handles
disk configuration (wipe + GPT layout or install-to-existing-partition). The specialize pass sets computer name and optionally joins a domain or workgroup.
The oobeSystem pass creates the local admin account, applies OOBE bypass
settings (Section 6), any Win 11 hardware bypasses (Section 7), and runs FirstLogonCommands.
generalize, auditUser) are irrelevant here.Workflow B — Capture-ready golden image (first build)
You are building a reference image that will be captured with dism /Capture-Image or imagex /capture and deployed to many
machines. This workflow prepares the image for capture by running sysprep with /generalize /oobe /shutdown before the capture step.
Pass sequence
[Install Windows fresh -- Workflow A or manual install]
|
v
[Boot into Windows, install software, configure settings]
|
v
[Run: sysprep /generalize /oobe /shutdown /unattend:unattend.xml]
|
v
generalize pass <-- strips SID, hardware IDs, activation state
|
v
[Machine powered off -- ready to capture]
|
v
[dism /Capture-Image ...]
|
v
[Deploy to target machines -- triggers oobeSystem pass on first boot]Key fields: SkipRearm and PersistAllDeviceInstalls
The generalize pass in Workflow B carries two settings that matter:
| Setting | Default in builder | What it does | When to change it |
|---|---|---|---|
SkipRearm=1 | ON | Does not consume one of the three activation rearm counts during generalize | Leave ON unless you specifically need rearm to fire |
PersistAllDeviceInstalls=true | ON | Keeps all currently installed drivers in the captured image | Turn OFF when deploying to hardware with different driver requirements |
These are the same two settings that become critical in Workflow D. For a first-build Workflow B, leaving both ON is correct for most environments. The rearm trap (described below) is primarily a Workflow D problem, but understanding it here makes Workflow D easier to reason about.
What the builder generates
Workflow B adds a generalize pass to the Workflow A pass set.
The generated file goes to C:\Windows\Panther\unattend.xml before you
run sysprep — or you pass its path explicitly with /unattend:.
sysprep /generalize /oobe /shutdown /unattend:"C:\Windows\Panther\unattend.xml"Workflow C — Audit-mode build
You want to install Windows, log in as Administrator in audit mode, manually install
software and configure the box, then sysprep to seal it for capture or deployment.
Workflow C is the unattend for that — Setup boots into audit mode automatically; the
rest is human time. Pre-staging auditUser commands is optional. When
you're done customizing, you run sysprep from the audit-mode desktop to
seal the image.
When to use Workflow C
Each workflow exists because the others can't do this one thing. Here's where C sits:
- Use C over A when you need to install GUI software, register licenses, or click through vendor installers that can't be scripted silently. A lands you on the end-user desktop with no built-in Administrator; C lands you in audit as Administrator with no user profile baggage to clean up later.
- Use C over B when "build the image" requires manual steps. B assumes you can fully script the build (FirstLogonCommands, SetupComplete.cmd, etc.) and just sysprep at the end. C is the answer when scripting everything isn't realistic — proprietary installers, GPO snap-in tools, weird OEM utilities.
- Use C, not D, for the first build. D is for refreshing an image that has already been captured at least once. If you don't have a golden yet, C is how you make one with human-in-the-loop customization.
- Don't use C if everything you do is scriptable. B is faster, reproducible, and doesn't depend on a human remembering to click "Next" the same way next time.
Anatomy of the emitted unattend.xml (Workflow C)
The builder writes the file to \autounattend.xml at the root of your
install media. The pass set:
- windowsPE — disk layout, image selection, locale, driver injection. Same shape as Workflow A.
- specialize — computer name and time zone. Domain join is deliberately deferred to after sealing; you don't want the build VM joined.
- auditUser (optional) — pre-staged commands that run the first time Administrator logs into audit. Useful for things you always do at the start of a build: copy in a tools share, pre-install your AV, mount a script volume. Leave it empty if you'd rather start from a clean desktop.
- oobeSystem — carries the
Reseal=Auditdirective in the<Reseal>component. That's what tells Setup "skip OOBE, drop the user into audit mode" instead of running the user-account wizard.
Manual sealing step
When you've finished customizing in audit mode, you seal the image yourself. From an elevated command prompt on the audit-mode desktop:
sysprep /generalize /oobe /shutdown Pick the right reseal switch for what comes next:
/oobe— next boot runs OOBE. Use this when you're done customizing and want the captured image to land end users on the welcome screen. This is the normal "I'm finished, capture me" case./audit— next boot goes straight back to audit mode. Use this when you want to capture mid-build (e.g., snapshot a "base + apps" checkpoint) and keep customizing. The image you capture here is not end-user-ready./quit— sysprep exits without rebooting. Useful for chained automation where another script runs immediately after. Rare in the C workflow.
sysprep /generalize burns one of the three activation rearms on retail
and MAK images. If you reseal twice during a single C build (e.g., audit checkpoint
then final seal), that's two rearms gone. See The 3-rearm-count
trap for the full breakdown — and set SkipRearm=1 in the generalize
pass if your channel supports it.auto_reseal_after_audit
Section 11 of the builder exposes an auto_reseal_after_audit toggle.
When ON, the emitted unattend chains sysprep /generalize /oobe /shutdown into the audit pass so the box seals itself the moment your pre-staged commands
finish. When OFF (the default and the recommendation), Setup parks at the audit
desktop and waits for you to seal manually.
Leave it OFF in most cases. The whole point of Workflow C is the human-in-the-loop
window between install and seal — auto-resealing collapses that window to zero and
turns C into a slower Workflow B. Only turn it ON if your auditUser commands do every single customization and you want a fully hands-off build.
Administrator account — no local user gets created during
the build, and the OOBE pass doesn't run a user wizard. Anything you configured in
the Accounts section will not appear in the emitted file. Create end-user accounts
at deploy time via the post-sysprep OOBE, or pre-stage them with a FirstLogonCommand
in a Workflow B re-seal of the captured C image.Related docs
- Adding drivers — C often pairs with offline
driver injection during the windowsPE pass, plus
pnputilat audit time for vendor packages that need a running OS. - First-run snippets — audit_commands take
the same shape as
RunSynchronousCommandentries. The patterns there drop in directly. - Command reference — PowerShell invocation
rules (always wrap with
powershell -ExecutionPolicy Bypass -File, never bare.ps1) apply the same way in audit as in OOBE.
Workflow D — Image refresh (sysprep over sysprep)
You have a golden image in production. A new CVE drops, or a vendor pushes a mandatory update, or you need to change the default browser. You do not want to rebuild the image from scratch — that takes hours or days and risks introducing regressions. You want to boot the existing image, make the change, and re-seal it.
This is "sysprep over sysprep": running sysprep on a machine that has already been generalized and deployed. It works, but it has four failure modes that will silently corrupt your image if you are not aware of them.
Pass sequence
[Deploy previous golden image to a build VM]
|
v
[Boot into Windows -- OOBE runs, creates local admin account]
|
v
[Log in, make changes: patch Firefox, apply GPO, update registry]
|
v
[Run: sysprep /generalize /oobe /shutdown /unattend:"...\unattend.xml"]
^
This is the "sysprep over sysprep" step.
The Workflow D unattend.xml controls what happens here.
|
v
auditUser pass <-- triggers cleanup: clear SetupComplete, clean event logs
generalize pass <-- SkipRearm=1 critical here (see below), strip SID
|
v
[Machine powered off -- ready to capture]
|
v
[dism /Capture-Image -- new version of the golden image]
|
v
[Deploy updated image -- oobeSystem runs on target machines]Why this is the hard case
The documentation for sysprep nearly always covers Workflow B (first build) and stops. Workflow D involves the same tools and the same commands, but four things break silently if you don't know to look for them:
- The activation rearm counter decrements — three refreshes and activation breaks on retail/MAK-keyed images (see qualification below).
- Drivers installed in the previous build persist and can conflict.
SetupComplete.cmdfrom the previous build runs again on deployed targets.- Office activation state carries forward in ways that require a reset.
Each of these is covered in its own section below. The builder surfaces all four as explicit toggles with inline warnings. The defaults are set to the safe values.
Workflow D fields in the builder
| Field | Default | Purpose |
|---|---|---|
SkipRearm=1 | ON | Prevents rearm counter decrement. Leave ON. |
Keep drivers (PersistAllDeviceInstalls=true) | ON | Preserves installed drivers. Turn OFF for cross-hardware deploys. |
| Reseal action | OOBE + shutdown | What sysprep does after generalize: shut down ready for capture, or restart to run OOBE. |
| Clear SetupComplete.cmd | ON | Removes leftover setup script before re-seal to prevent double execution. |
| Clear Windows.old | ON | Frees disk space before capture. |
| Clean event logs | ON | Wipes the previous install's audit trail before redistribution. |
| Reset Office activation | OFF | Only turn ON if Office was activated in the previous build. See below. |
The 3-rearm-count trap
Windows activation has a rearm counter. Each time sysprep's generalize pass
runs without SkipRearm=1, it decrements that counter. The counter starts
at 3. When it hits 0, the machine will not activate — not with KMS, not with a MAK key,
not with a volume license.
Teams who do Workflow B once (first build) never hit this. Their counter goes from 3 to 2. Teams who do Workflow D quarterly hit 0 within the first year and spend two weeks puzzling over why new deployments from their golden image fail activation.
- Retail and MAK keys: every
sysprep /generalizewithoutSkipRearm=1consumes one rearm. Hits 0 fastest. This is the case the "three strikes" warning is written for. - KMS-activated machines:
/generalizedoes NOT consume a rearm. The 180-day KMS activation timer resets on re-activation against the KMS host, but the rearm counter itself is not decremented. - Active Directory-Based Activation (ADBA): volume activation via ADBA also does not decrement the rearm counter on generalize. Safe by design for domain-joined volume-licensed images.
SkipRearm=1 is still the right default for Workflow D regardless of channel —
it is a no-op on KMS/ADBA and prevents the trap on retail/MAK.The fix: SkipRearm=1
Set SkipRearm=1 in the <generalize> pass of your
unattend.xml. This tells sysprep to skip the rearm step — the SID and hardware IDs are
still generalized, but the activation timer is not reset and the counter is not
decremented.
<settings pass="generalize">
<component name="Microsoft-Windows-Security-SPP-UX"
processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35"
language="neutral"
versionScope="nonSxS">
<SkipRearm>1</SkipRearm>
</component>
</settings> The builder sets this to 1 by default in both Workflow B and Workflow D.
If you turn it OFF in the builder, you get an inline red banner reminding you of the
consequences.
How to check your current rearm count
slmgr /dlv Look for the "Remaining Windows rearm count" line. If it shows 0, you need to rebuild from a clean install (not from a Workflow D refresh) to reset the count.
Driver leakage across cycles
When sysprep runs generalize without PersistAllDeviceInstalls=false,
all currently installed drivers are kept in the image. For Workflow B on identical
hardware, this is correct — drivers are already right for the target. For Workflow D,
it depends on your environment.
When to keep drivers (default)
Leave PersistAllDeviceInstalls=true (the default) if:
- All your target machines are the same hardware model (or very close).
- You are deploying to VMs with consistent virtual hardware.
- You deliberately injected specific drivers into the image and want them in the next version.
When to strip drivers
Set PersistAllDeviceInstalls=false if:
- You deploy to a mix of hardware (different NIC, GPU, or storage controllers).
- A driver from a previous build is causing problems on new hardware.
- You want the cleanest possible generalized image and Windows to re-detect hardware on deployment.
The XML
<settings pass="generalize">
<component name="Microsoft-Windows-PnpSysprep"
processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35"
language="neutral"
versionScope="nonSxS">
<PersistAllDeviceInstalls>true</PersistAllDeviceInstalls>
</component>
</settings> Set the value to false to release the driver-to-device bindings.
The builder exposes this as the "Keep drivers" toggle in Workflow B and D sections.
PersistAllDeviceInstalls=false does NOT strip drivers from
the image. This is the single most common misconception about Microsoft-Windows-PnpSysprep. Setting it to false releases the bindings between installed devices and their driver packages — so
Windows re-runs PnP detection on next boot — but the driver .inf files themselves remain in C:\Windows\System32\DriverStore\FileRepository\. If a driver from
the previous build is causing problems on new hardware, =false alone will not remove it; the driver is still in the store and PnP can still
pick it on a matching hardware ID. To actually remove a driver, run pnputil /delete-driver oemNN.inf /force before generalize.
Use =false for what it is: a clean rebind on next boot, not a
driver wipe.SetupComplete.cmd ghosting
SetupComplete.cmd lives at C:\Windows\Setup\Scripts\SetupComplete.cmd.
Windows runs it once after the initial install finishes, in SYSTEM context, before the
first user logon. It is a common place to run post-install configuration: installing
software, applying registry settings, joining domains.
The problem with Workflow D: if your first golden image (Workflow B) had a SetupComplete.cmd, that file is still present in the image after the initial
deployment. When you boot the deployed image to do your Workflow D refresh, that script
has already run. But when you re-seal with sysprep and deploy the updated image to new
machines, Windows will run it again on each new deployment. That is usually the correct
behavior for the commands you put there.
Where it goes wrong: if your Workflow D refresh adds a new SetupComplete.cmd through the unattend, and there is already a file at that path from the previous build,
the content can get merged unexpectedly depending on how your scripts write the file.
More commonly, you end up with duplicate commands running.
The fix: clear the file before re-sealing
The builder's "Clear SetupComplete.cmd" toggle (default ON in Workflow D) adds a command
to the auditUser pass that deletes the existing file before sysprep
generalizes. Your Workflow D unattend.xml then writes a fresh one in the oobeSystem pass.
<!-- In the auditUser pass, before generalize -->
<RunSynchronousCommand>
<Order>1</Order>
<Description>Clear previous SetupComplete.cmd</Description>
<Path>cmd /c del /f /q "%SystemRoot%\Setup\Scripts\SetupComplete.cmd"</Path>
</RunSynchronousCommand> cmd.exe's for /f loop: for /f "tokens=*" %L in ('wevtutil el') do wevtutil cl "%L".Office activation across refreshes
If the machine you are refreshing had Microsoft 365 or Office activated during the previous deployment period, that activation state is embedded in the image. When you re-seal and deploy the updated image to a new machine, Office may present a stale or conflicting activation state on first run.
The symptom is typically an activation error or a prompt to sign in with a different account on the first user logon on a freshly deployed machine.
The fix: ospprearm.exe
:: OSPPREARM.EXE is a native binary -- invoke it directly (no cscript).
"C:\Program Files\Microsoft Office\Office16\OSPPREARM.EXE"
:: Equivalent VBS path (this is what the builder emits):
cscript //nologo "C:\Program Files\Microsoft Office\Office16\ospp.vbs" /rearm This resets the Office activation grace period so the deployed image activates cleanly
on first run. Run it in the auditUser pass, before sysprep generalizes.
The builder's "Reset Office activation" toggle (default OFF) adds this command when enabled, with an inline yellow warning: "Required only if Office 365 was activated in the previous build. Resets activation grace; users re-activate on first run."
Office16. Office 2013 uses Office15. Office 2021 and 2024 also
use Office16. Check the path on the build machine before including this
command.Worked example: CVE patch cycle
The scenario: you deployed a golden image last quarter. A CVE drops affecting Firefox. You need to update Firefox in the image and redeploy. Here is the exact sequence.
Prerequisites
- A VM hypervisor (Hyper-V, VMware, or Proxmox) with your current golden image available as a WIM or VHD.
- The previous Workflow B or D unattend.xml — or generate a new Workflow D one from the builder.
- Firefox updated installer (from your software repository).
Step 1: Boot the image in a VM
# If you have the WIM, apply it to a VHD and boot it:
dism /Apply-Image /ImageFile:"D:\images\golden-current.wim" ^
/Index:1 /ApplyDir:"V:\"
# Or if the image is a VHD/VHDX, attach and boot directly in Hyper-V.
# The OOBE will run. Complete it to get to the desktop. Step 2: Install the update
# Run as Administrator in the VM:
# Uninstall old Firefox
"C:\Program Files\Mozilla Firefox\uninstall\helper.exe" /S
# Install new Firefox (silent)
"\\fileserver\software\Firefox-Setup-125.0.1.exe" -ms
# Verify
"C:\Program Files\Mozilla Firefox\firefox.exe" --version Make any other changes you need: registry edits, Group Policy updates, additional software. This is your only window before re-sealing.
Step 3: Generate a Workflow D unattend.xml from the builder
Open the builder, select Workflow D, and configure:
- SkipRearm: ON (critical — leave it on)
- Keep drivers: ON (unless you are changing hardware targets)
- Reseal action: OOBE + shutdown
- Clear SetupComplete.cmd: ON
- Clear Windows.old: ON
- Clean event logs: ON
- Reset Office activation: only if Office was activated in the previous build
Download the file. Copy it to C:\Windows\Panther\unattend.xml in the VM.
Step 4: Run sysprep
sysprep /generalize /oobe /shutdown /unattend:"C:\Windows\Panther\unattend.xml" Expected output in C:\Windows\System32\Sysprep\Panther\setupact.log:
SYSPREP: Sysprep will generalize the machine.
SYSPREP: Calling SysprepGeneralize...
...
SYSPREP: Sysprep operation completed successfully.
SYSPREP: Shutting down. If you see errors, check C:\Windows\System32\Sysprep\Panther\setuperr.log.
The most common failure is a third-party antivirus or DRM component that blocks
generalize — check the Microsoft sysprep generalize documentation for the list of known incompatible components.
Step 5: Capture the updated image
# Boot into WinPE (from a separate USB or network boot)
# Then capture:
dism /Capture-Image ^
/ImageFile:"D:\images\golden-2026-q2.wim" ^
/CaptureDir:"C:\" ^
/Name:"Golden Image Q2-2026" ^
/Description:"Firefox 125 + Q2 patches" ^
/Compress:fast Step 6: Verify before wide deployment
# Apply the new image to a test VM:
dism /Apply-Image /ImageFile:"D:\images\golden-2026-q2.wim" ^
/Index:1 /ApplyDir:"V:\"
# Boot it. OOBE should run. Complete it.
# Verify:
# - Firefox 125 is installed
# - Windows activation succeeds (slmgr /ato)
# - SetupComplete.cmd ran once and only once (check event log Application source: SetupHost)
# - No duplicate first-run commands Once the test deployment looks correct, push the new WIM to your deployment share.