Add three GUI feature toggles to the bloatware step:
- standardBloatware (default on) - the bulk AppX/capability/feature list
- removeNewOutlook (default on) - new Outlook for Windows (Microsoft.OutlookForWindows)
- removeSnippingTool (default OFF) - Snipping Tool across all three lists
Each toggle is independent via Test-RemovalAllowed in 01-bloatware.ps1.
Snipping Tool (ScreenSketch + legacy capability/feature) is now kept by
default as a common productivity tool, like Calculator. Classic Outlook from
M365 is a Win32 app and was never touched; only the bundled new Outlook is.
Also fix a latent bug: the Go Config struct had no Bloatware field, so the
GUI's runtime-config regeneration silently dropped bloatware.keepPackages.
Added the field so the keep-list survives to the script.
Docs: SPEC.md, CHANGELOG.md, web/data/descriptions.json, web/spec/index.html.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Critical fixes:
- Fix resume mode: StepsByIDs returned Enabled=false, all resume steps
would be SKIPPED (deployment could never resume after reboot)
- Add reboot loop protection: per-step retry counter (max 5) prevents
infinite reboot cycles when a step always exits with code 9
- Block reboot when state.Save() fails in resumePhase (prevents state
loss leading to full restart from scratch)
- Atomic state file write (write-to-tmp + rename) prevents JSON
corruption on BSOD/power loss mid-write
- Script watchdog: kills scripts after 30 min of no output (resets on
each line, so active long-running scripts are never killed)
- Fix copyFile: check Close() error explicitly instead of deferred
close that silently drops flush errors (e.g. disk full)
High severity:
- Cleanup() now logs errors instead of silently ignoring them
- Email report: 3 retries with backoff + always saves C:\X9\report.html
- Winget parallel jobs: 10 min timeout, kill hung jobs
- UCPD stop verification: 2s wait + state check before PDF association
- Atera installer: /qn -> /qb so MFA window can appear
- GVLK activation: match by EditionID (registry, not localized) instead
of fragile OS caption string matching
Medium severity:
- Default profile hive unload: retry loop (5 attempts, increasing delay)
- LayoutModification.xml: UTF-8 without BOM (PS 5.1 Set-Content adds BOM)
- Set-Reg SYSTEM task: try/finally ensures temp file + task cleanup
- Windows Update: @($available).Count for PS 5.1 single-result edge case
- config.json: add missing kmsServer field in activation section
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause fix: runner.go passed config as unevaluated PS expression
via -File mode - scripts received a literal string instead of parsed
object. Changed to -ConfigPath; scripts load JSON themselves via
shared common.ps1 (Write-Log, Get-Feature, Load-Config).
GUI now regenerates runtime config before run so user selections
actually reach the scripts.
Merged 04-default-profile + 05-personalization into single script
(one hive load/unload, no Explorer restart, no hive contention).
Deleted Deploy-Windows.ps1 (xetup.exe is sole entry point),
06-scheduled-tasks.ps1 (tasks caused more harm than good),
07-desktop-info.ps1 (replaced by BackInfo long ago).
Step ordering: activation moved early, pcIdentity before WU
(exit 9 on rename only when rename actually happened).
Edge policies split into mandatory (telemetry, first-run) vs
recommended (UI preferences user can override).
Atera install uses Start-Process -Wait instead of fragile sleep.
Updated config.json, tests, DefaultConfig to match current state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>