- Bound every installer wait with WaitForExit and a timeout instead of Start-Process -Wait, which in Windows PowerShell also waits for any process the installer leaves running and can block forever. This covers the VirtIO step in the answer files and the guest tools, Mesh agent and Winget installs in the scripts. - specialize pass (SYSTEM) sets ConsentPromptBehaviorAdmin=0 so nothing at first logon can stall on a UAC prompt. - Step 4 now logs to C:\ProgramData\OOBE\firstlogon.log, saves the script to C:\ProgramData\OOBE and starts it elevated in its own window. - Scripts start their transcript before the admin check, so an early stop still leaves a log. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| unattend | ||
| .gitignore | ||
| README.md | ||
| build-isos.sh | ||
| oobe-desktop.ps1 | ||
| oobe-vms.ps1 | ||
README.md
Windows OOBE Scripts
Unattended setup for Windows 10 Enterprise LTSC 2021: an answer file installs Windows, then a PowerShell script configures the machine on first logon and restarts it.
| Variant | Answer file | OOBE script | Disk | ISO |
|---|---|---|---|---|
| VMs (Unraid/KVM, VirtIO) | unattend/vms-WIPE-DISK.xml |
oobe-vms.ps1 |
Wipes Disk 0 without asking | build/virtio-vms.iso |
| Desktops, laptops, any VM | unattend/desktop-PROMPT-DISK.xml |
oobe-desktop.ps1 |
Prompts you to pick the disk/partition | build/desktop.iso |
Run a script by hand
From an elevated PowerShell:
irm https://url.isworking.fyi/oobe-vms | iex
irm https://url.isworking.fyi/oobe-desktop | iex
The short links point at the raw files on master, so pushing a change updates what new installs run. Logs go to C:\ProgramData\OOBE\oobe-<name>.log.
What the scripts do
Both:
- Install the MeshCentral agent silently as a service
- Enable RDP, ping, the
C$admin share, and OpenSSH Server (PowerShell as the default shell) - Set the network to Private, turn off the UAC prompt, and turn on dark mode with no mouse acceleration (current user and default profile)
- Install Winget
- Restart when finished
oobe-vms.ps1 also:
- Installs the VirtIO drivers, QEMU guest agent and SPICE agent from the mounted virtio-win ISO (downloads them if it isn't mounted)
- Never sleeps or hibernates (enforced by policy), never turns off the display or disks, and stops Windows powering down the network adapter
- Enables WinRM and keeps the clock synced
oobe-desktop.ps1 also:
- Uses the Balanced plan: dims the display after 5 minutes (only works on screens Windows controls the brightness of) and sleeps after 30 minutes
Build the ISOs
Requires curl and xorriso:
./build-isos.sh
This downloads the latest virtio-win ISO (only when a new release is out) and writes to build/, which git ignores:
virtio-vms.iso: virtio-win plusautounattend.xml(the VM answer file) andoobe-vms.ps1desktop.iso:autounattend.xml(the desktop answer file) andoobe-desktop.ps1
Rerun it after changing an answer file. Changes to the scripts reach new installs through the short links without a rebuild. The copy on the ISO is only used if the download fails.
Install
VM (Unraid): put the LTSC ISO in "OS Install ISO" and virtio-vms.iso in "VirtIO Drivers ISO", then boot. Everything is automatic, and Disk 0 is erased.
Desktop: copy autounattend.xml and oobe-desktop.ps1 from desktop.iso to the root of the LTSC install USB. For a VM, attach desktop.iso as a second CD instead. Setup stops once to ask where to install; everything else is automatic.
Setup only reads a file named exactly autounattend.xml at the root of a disc or USB drive.
Accounts
Both answer files create a local administrator silviodante with the placeholder password mdwelcome, stored in plain text. VMs log in automatically every boot; desktops only on the first logon, then show the sign-in screen. Change the password in the answer file before using this for anything that matters.