Skip to content

gtkramer/windows-setup-scripts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

windows-setup-scripts

A version-controlled, idempotent PowerShell/winget kit that provisions a clean Windows 11 IoT Enterprise LTSC 2024 dual-boot gaming + workstation install and brings it back to ~100% mostly automatically - the Windows companion to arch-linux-setup-scripts, and deliberately modeled on it (a shared common.ps1, aggregator modules, one update wrapper, checked-in config).

Host: prowsw880acese (ASUS Pro WS W880-ACE SE, RTX 5080, fTPM/PTT). Windows is kept for native HDR + ray tracing + DLSS; Arch remains the daily driver / media server / dev box.

Honest scope. A declarative config reproduces ~80-90% of a fresh box. The true 100% restore is a disk image (Macrium/wbadmin), captured once the box is dialed in. Updates are ~3 surfaces, not one: winget (apps) + Windows Update (OS) + the NVIDIA App (GPU driver). Two are automated by Update-System.ps1; the driver is reported.


Why IoT Enterprise LTSC 2024

It is the full 24H2 / build 26100 gaming stack, but feature-frozen with security-only monthly updates through 2034-10-10 (~10 years - 5 more than non-IoT Enterprise LTSC). No annual feature-update churn = no "fight the big update." Ships with no Copilot, Recall, Cortana, Widgets, Xbox app, Teams-consumer, or Microsoft Store.

Technology Verdict This kit does
Windows Update (LTSC) Trust - security-only keeps it on; scripts it via PSWindowsUpdate
Microsoft Defender Trust / keep (AV-TEST 6/6/6) keeps it; adds no 3rd-party AV
Telemetry Mitigate AllowTelemetry=0 (Security floor, Enterprise/IoT only) + O&O ShutUp10
Microsoft account Avoid local account via autounattend.xml
Recall / Copilot Absent (good) n/a - excluded from the SKU
Microsoft Store Not installed provisions winget manually; Store optional/off-path
BitLocker Use - TPM+PIN see below
GeForce Experience Replaced NVIDIA App

Encryption: BitLocker TPM+PIN (not VeraCrypt system encryption)

On a rig where Secure Boot must stay on - for kernel anti-cheat and because the Arch side already runs it (sbctl enroll-keys -m) - VeraCrypt system encryption is the wrong tool: it fights Secure Boot, and Microsoft broke VeraCrypt's boot-signing in early 2026. BitLocker TPM+PIN is the near-exact analog of the Linux systemd-cryptenroll TPM2 + PIN on PCR 7 design:

  • Seals to PCR 7 (Secure Boot state) + 11 with a startup PIN.
  • The fTPM/PTT is integrated in the CPU - no external bus to sniff. TPM+PIN defeats Bitpixie / CVE-2023-21563.
  • The recovery key is exported locally and never escrowed to a Microsoft account or AD (security/Enable-BitLocker.ps1 deliberately does not call Backup-BitLockerKeyProtector).

Want open-source crypto for specific files? Keep them on a separate VeraCrypt data volume - it never touches the bootloader, so Secure Boot is unaffected. (Not scripted here.)


Layout

windows-setup-scripts/
|-- common.ps1                    # constants + helpers - CUSTOMIZE THIS FIRST (<-> common.sh)
|-- Update-System.ps1             # one-stop update wrapper (<-> maintenance.sh)
|-- answer-file/autounattend.xml  # clean install, local account, no MS account (dual-boot safe)
|-- bootstrap/
|   |-- Install-WinGet.ps1        # provision winget on LTSC (no Store) - idempotent
|   `-- Add-MicrosoftStore.ps1    # OPTIONAL/standalone: Xbox/Game Pass (unsupported on LTSC)
|-- install/
|   |-- Install.ps1               # aggregator: winget configure -> baseline -> apps
|   |-- configuration.dsc.yaml    # declarative app manifest (<-> user/packages/install.sh)
|   |-- baseline/ (privacy, dualboot, explorer, shutup10 + .cfg)
|   `-- apps/    (git, vscode, makemkv, tresorit; standalone: emby, nvidia)
|-- security/                     # STANDALONE - run by hand (<-> tpm2-unlock.sh)
|   |-- Enable-BitLocker.ps1      # TPM+PIN, XTS-AES-256, local recovery key, NO escrow
|   `-- Confirm-Readiness.ps1     # read-only: SecureBoot/TPM/BitLocker/telemetry/anti-cheat
`-- redist/                       # downloaded, hash-pinned binaries (gitignored)

Conventions (from arch-linux-setup-scripts): every script dot-sources common.ps1 at the right relative depth; Assert-Admin <-> require_root; Set-RegistryValue/Get-Redist are the idempotent guards / verified-download; Invoke-Modules <-> run_scripts (a module is Foo.ps1 or Foo/Install.ps1; extend by dropping a script in and appending its name to the parent array).

Customize first: edit host constants at the top of common.ps1 ($UserName, $HostName, $TimeZoneId, $TrustedLanCidr, $TelemetryLevel, $RecoveryKeyDir, $KeyDbSource).


Prerequisite decision: disk topology

Recommended - a dedicated Windows NVMe with its own ESP. Independent boot chains, zero ESP contention, clean firmware boot-menu switching between "Linux Boot Manager" (systemd-boot) and "Windows Boot Manager." Confirm your M.2 population supports it before you start.

Shared-ESP fallback works but is discouraged: a Windows install/major update can overwrite \EFI\Boot\BOOTX64.EFI and reorder NVRAM. If you share the ESP, back it up first and re-assert systemd-boot afterward from Linux (bootctl set-default / efibootmgr -o); watch free space (your UKIs are large on a 512 MiB ESP).


Install runbook

Each step satisfies the next step's precondition - order matters.

  1. Back up the target Windows disk. Confirm Arch, systemd-boot, and the btrfs /data pool are healthy. (Windows can't read btrfs, so /data is never at risk - the ESP is the only shared surface.)
  2. ISO + USB. Get the IoT Enterprise LTSC 2024 ISO (90-day eval, or your VS-subscription license). Write to USB. Copy answer-file/autounattend.xml to the USB root.
  3. Firmware (confirm, don't re-enroll). Secure Boot ON - keep your sbctl keys: you enrolled with -m, so Microsoft's PCA already signs the Windows Boot Manager; no Secure Boot change is needed. PTT/fTPM ON (already on for Linux). Do not switch OS Type to "Other OS."
  4. Clean install to the dedicated Windows NVMe (interactive disk pick - the answer file does not auto-partition). Local george account is created; never sign into a Microsoft account. -> Set a login password immediately (the account ships blank).
  5. First-boot sanity. Confirm the machine still dual-boots and Arch still boots under Secure Boot. This validates key-coexistence before you invest in configuration.
  6. Open an elevated PowerShell, allow scripts for the session, and clone/copy this kit:
    Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
    cd <path-to>\windows-setup-scripts
    .\bootstrap\Install-WinGet.ps1     # provision winget (LTSC has no Store)
    If winget isn't on PATH afterward, open a new elevated terminal before continuing.
  7. Apply the declarative + baseline + apps layers:
    .\install\Install.ps1              # winget configure -> privacy/dualboot/explorer/shutup10 -> git/vscode/makemkv/tresorit
  8. NVIDIA App + driver (manual; not in winget): .\install\apps\nvidia.ps1 prints the download link (or auto-launches if you pin its hash). Install the RTX 5080 driver. Do this before the image.
  9. Verify: .\security\Confirm-Readiness.ps1 - Secure Boot True, TPM 2.0 ready (the anti-cheat
    • BitLocker preconditions).
  10. Capture the golden disk image (Macrium Reflect X / Veeam / wbadmin) to external/NTFS media - never the btrfs pool. Do this before BitLocker, so the image is decrypted/portable.
  11. Enable encryption (last):
    .\security\Enable-BitLocker.ps1    # TPM+PIN; recovery key -> $RecoveryKeyDir; MOVE IT OFFLINE
  12. Dual-boot final check. Reboot Linux<->Windows and confirm the clock agrees (the kit set RealTimeIsUniversal=1). If you shared the ESP, re-assert the systemd-boot default from Linux.

Updating the system

.\Update-System.ps1
  • (a) apps - winget upgrade --all --include-unknown (+ Chocolatey if present). The yay -Syu analog for apps; schedule it in Task Scheduler for set-and-forget.
  • (b) OS - Windows Update via PSWindowsUpdate (LTSC = security-only monthly, no feature updates); -IgnoreReboot, so you reboot deliberately.
  • (c) GPU driver - cannot be unified. The NVIDIA App self-updates; the wrapper only reports the version. DDU for a clean reinstall.

Not-in-winget apps & pinning

Four apps are not in winget and are handled out of band:

App How
Tresorit install/apps/tresorit.ps1 (vendor installer; pin its SHA256 first)
Emby Server install/apps/emby.ps1 (standalone/optional; LAN-only firewall rule)
NVIDIA App install/apps/nvidia.ps1 (driver; interactive)
Macrium Reflect manual (disk-image backstop)

The bootstrap/shutup10/tresorit/emby/nvidia scripts fetch binaries via Get-Redist, which verifies a pinned SHA256 and refuses to run un-pinned. First run: download once, Get-FileHash <file> -Algorithm SHA256, paste the hash into the script, commit. Downloads land in redist/ (gitignored).


Risks & gotchas

  1. PCR 7 is shared between both OSes. Rotating sbctl keys, re-running enroll-keys, a firmware reset, or a dbx revocation update (Windows Update or fwupd) changes PCR 7 -> breaks both Linux TPM2 unlock and Windows BitLocker (each falls back to passphrase/recovery key, then re-seal). Suspend BitLocker across firmware/dbx changes: manage-bde -protectors -disable C: -RebootCount 1. Keep both recovery secrets reachable.
  2. Secure Boot key coexistence is sound but fragile - verify at step 5; a firmware update that clears keys means re-running sbctl enroll-keys -m before Windows boots again.
  3. winget IDs drift - verify with winget show <Id> before a big rebuild. IDs here were verified against microsoft/winget-pkgs (note: Pinta = Pinta.Pinta, mpv = shinchiro.mpv).
  4. VBS/HVCI <-> Vanguard <-> VirtualBox tension - leave VBS/HVCI at default; don't run VirtualBox VMs while playing Vanguard/EAC titles (Vanguard refuses active virtualization).
  5. Declarative != 100%. winget configure ~ 80-90%; activation, game saves, per-app state, and drivers are excluded -> the Macrium image is the only true 100% restore.
  6. Execution policy / PATH. Run elevated with -ExecutionPolicy Bypass (step 6); apps winget just installed need a fresh shell to appear on PATH (Invoke-Apps.ps1 refreshes PATH in-session for git).
  7. LTSC Store re-add is unsupported - only if you want Xbox/Game Pass (Add-MicrosoftStore.ps1, off the default path).
  8. UE5 on Windows needs Visual Studio 2022 + C++ workloads (winget can't fully express workloads in a one-liner - document a .vsconfig).

References

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors