Previous history: -c359054daku working! -8de5cfffix integer overflow in vmix network lib -9c25a66daku on 25.05. with ollama -385a3bfvmix enables relaxed sandbox -c363da1restructure vmixLib into linux/windows subattrs with OS-specific customizeImage -edd4dc2vmix: port namespace model and module improvements from conf.nix -6666ecfvmix: add SPICE support, install virtio guest tools with SPICE agent -46f5671vmix: add QEMU guest agent channel for Windows VMs -e1fea34vmix: add Win11 LTSC 2024 image, refactor VirtIO driver selection -c27ae68vmix: make customizeImage chroot-sandboxed by default, opt-in impure -305fbacvirt customize needs chroot for now due to usr bin env things. could be fixed later -264d30fvmix: add win10 VM on desk, disable SMB signing for guest Samba access -9b64f51vmix: split Windows templates into per-category files, add comprehensive debloat -ef91bf8vmix: fix missing parent registry keys in Windows templates -f87f340win10 VM on panda with AMD GPU + USB passthrough -38e474fvmix: split Windows build into Audit Mode install + composable templates -a6a8db3vmix: win11 support, remove build VNC, switch VMs to SPICE -6cf5a21generalize stage sets bg color, accent color and sets visual effects to performance -a84849fremove rdp template since it doesn't even work -5245263vmix: best performance template + generalize cleanup -ab12dd3vmix: use CopyProfile for best performance visual effects -bce3326vmix: CopyProfile for best performance visual effects -2496107vmix: add app templates (7zip, VLC, ImageGlass, Edge WebView, VC++ runtimes) -29a6123wip: debug default associations xml -2a2e5f5vmix: fix DefaultAssociations.xml cmd.exe escaping -cc6ff9dvmix: move DefaultAssociations.xml to template only -a4a78ecvmix: add removeWMP template to remove Windows Media Player -3fe56devmix: improved Edge removal (files, shortcuts, scheduled tasks) -a491767vmix: fully remove Edge via post-oobe AppxPackage removal -6ca1619vmix: remove Edge DevToolsClient SystemApps + AppxPackage -0c1ec35vmix: sandboxie windows app template -628bbd2vmix: add Sandboxie-Plus template -f055a41vmix: reorganize templates, add file associations, remove Paint -34326f4vmix: set Thorium as default browser via PS-SFTA in post-oobe -86af258vmix: Active Setup for default browser (all users, no post-oobe needed) -35b8cb0remove vnc display from thorium template -c7e0af6vmix: fix Win11 generalize timeout + UCPD disable for URL associations -43a1345vmix: add Office 2024 template + Ohook activation in generalize -03bbce0vmix: updated office installation xml. more privacy options enabled -790a0eevmix: thorium installation - hide SFTA window -a0e5c18vmix: fix office install.bat call + add privacy registry policies -3df38cavmix: fix Ohook activation + suppress Office theme dialog -df39ba3vmix: remove sandboxie shortcut from desktop -50d5972vmix: skip Sandboxie desktop shortcut via installer flag -ee2fa0fvmix: fix win10 default browser -938315bvmix: windows: set accent color to automatic. remove accent color from unnecessary elements -beceda8vmix: allow ISO-only VMs without OS disk, add WinPE VM to panda Flake outputs: overlays.default, nixosModules.default, lib, apps.toDisk Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
168 lines
7.1 KiB
Nix
168 lines
7.1 KiB
Nix
# Generalize image via sysprep + OOBE in two phases.
|
|
# Phase 1 (sysprep): runs sysprep /generalize /oobe /shutdown in Audit Mode
|
|
# Phase 2 (oobe): boots through OOBE, creates user, activates Windows, shuts down
|
|
# Between phases, NTUSER.DAT can be modified offline.
|
|
# Usage: (templates.generalize { username = "User"; password = ""; })
|
|
{ pkgs, lib, makeFilesISO, ... }:
|
|
let
|
|
masScript = pkgs.fetchurl {
|
|
url = "https://raw.githubusercontent.com/massgravel/Microsoft-Activation-Scripts/97602941e5724316aa31b6ca1da5c70245d234d5/MAS/All-In-One-Version-KL/MAS_AIO.cmd";
|
|
hash = "sha256-1hl89jQf2p+RtE3ue/+cZevSoz7Ra3p3u350aE/Xy74=";
|
|
};
|
|
in
|
|
{
|
|
username ? "User",
|
|
password ? "",
|
|
autoLogon ? true,
|
|
hostname ? "WIN-VM",
|
|
locale ? "en-US",
|
|
timezone ? "UTC",
|
|
# Desktop background solid color as hex string (e.g. "8e8cd8")
|
|
bgColor ? null,
|
|
}: let
|
|
# Convert "8e8cd8" hex to "142 140 216" decimal RGB for Windows registry
|
|
hexToRgbStr = hex: let
|
|
hexChars = lib.stringToCharacters hex;
|
|
hexToDec = h: let
|
|
c = lib.toLower h;
|
|
m = { "0"=0; "1"=1; "2"=2; "3"=3; "4"=4; "5"=5; "6"=6; "7"=7; "8"=8; "9"=9; "a"=10; "b"=11; "c"=12; "d"=13; "e"=14; "f"=15; };
|
|
in m.${c};
|
|
r = hexToDec (builtins.elemAt hexChars 0) * 16 + hexToDec (builtins.elemAt hexChars 1);
|
|
g = hexToDec (builtins.elemAt hexChars 2) * 16 + hexToDec (builtins.elemAt hexChars 3);
|
|
b = hexToDec (builtins.elemAt hexChars 4) * 16 + hexToDec (builtins.elemAt hexChars 5);
|
|
in "${toString r} ${toString g} ${toString b}";
|
|
|
|
stripHash = s: lib.removePrefix "#" s;
|
|
bgRgb = if bgColor != null then hexToRgbStr (stripHash bgColor) else null;
|
|
|
|
# Post-OOBE script: runs as the created user via FirstLogonCommands.
|
|
postOobeScript = pkgs.writeText "post-oobe.cmd" ''
|
|
@echo off
|
|
${lib.optionalString (!autoLogon) ''
|
|
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoAdminLogon /f 2>nul
|
|
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultUserName /f 2>nul
|
|
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultPassword /f 2>nul
|
|
''}
|
|
${lib.optionalString (bgColor != null) ''
|
|
:: Set solid background color
|
|
reg add "HKCU\Control Panel\Desktop" /v WallPaper /t REG_SZ /d "" /f
|
|
reg add "HKCU\Control Panel\Colors" /v Background /t REG_SZ /d "${bgRgb}" /f
|
|
reg add "HKCU\Control Panel\Desktop" /v WallpaperStyle /t REG_SZ /d "0" /f
|
|
''}
|
|
|
|
:: Remove Edge AppxPackage for current user (runs in user context during OOBE)
|
|
:: The app is already removed on one of the templates but a ghost appx entry remains that can only be deleted at the user level
|
|
powershell -Command "Get-AppxPackage *MicrosoftEdge* | Remove-AppxPackage -ErrorAction SilentlyContinue"
|
|
powershell -Command "Get-AppxPackage *MicrosoftEdgeDevToolsClient* | Remove-AppxPackage -ErrorAction SilentlyContinue"
|
|
|
|
|
|
:: Activate Windows using HWID method
|
|
if exist C:\MAS_AIO.cmd (
|
|
echo. | call C:\MAS_AIO.cmd /HWID
|
|
)
|
|
|
|
:: Activate Office using Ohook method (if Office is installed)
|
|
if exist "C:\Program Files\Microsoft Office\root\Office16\WINWORD.EXE" (
|
|
if exist C:\MAS_AIO.cmd (
|
|
echo. | call C:\MAS_AIO.cmd /Ohook
|
|
)
|
|
)
|
|
del /q C:\MAS_AIO.cmd 2>nul
|
|
|
|
:: Clean up
|
|
del /q C:\oobe-unattend.xml 2>nul
|
|
del /q C:\vmix-audit-script.cmd 2>nul
|
|
del /q C:\vmix-audit-wrapper.cmd 2>nul
|
|
|
|
shutdown /s /t 5 /c "vmix generalize complete"
|
|
del /q C:\post-oobe.cmd 2>nul
|
|
'';
|
|
|
|
oobeXml = pkgs.writeText "oobe-unattend.xml" ''
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<unattend xmlns="urn:schemas-microsoft-com:unattend"
|
|
xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
|
|
<!-- Copy Administrator profile to default (preserves Audit Mode customizations) -->
|
|
<settings pass="specialize">
|
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64"
|
|
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
|
<CopyProfile>true</CopyProfile>
|
|
<Themes>
|
|
<WindowColor>Automatic</WindowColor>
|
|
</Themes>
|
|
</component>
|
|
</settings>
|
|
|
|
<settings pass="oobeSystem">
|
|
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64"
|
|
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
|
<InputLocale>${locale}</InputLocale>
|
|
<SystemLocale>${locale}</SystemLocale>
|
|
<UILanguage>${locale}</UILanguage>
|
|
<UserLocale>${locale}</UserLocale>
|
|
</component>
|
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64"
|
|
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
|
<OOBE>
|
|
<HideEULAPage>true</HideEULAPage>
|
|
<HideLocalAccountScreen>true</HideLocalAccountScreen>
|
|
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
|
|
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
|
|
<NetworkLocation>Work</NetworkLocation>
|
|
<SkipMachineOOBE>true</SkipMachineOOBE>
|
|
<SkipUserOOBE>true</SkipUserOOBE>
|
|
<ProtectYourPC>3</ProtectYourPC>
|
|
</OOBE>
|
|
<UserAccounts>
|
|
<LocalAccounts>
|
|
<LocalAccount wcm:action="add">
|
|
<Password>
|
|
<Value>${password}</Value>
|
|
</Password>
|
|
<Group>Administrators</Group>
|
|
<Name>${username}</Name>
|
|
</LocalAccount>
|
|
</LocalAccounts>
|
|
</UserAccounts>
|
|
<AutoLogon>
|
|
<Password>
|
|
<Value>${password}</Value>
|
|
</Password>
|
|
<Enabled>true</Enabled>
|
|
<Username>${username}</Username>
|
|
</AutoLogon>
|
|
<ComputerName>${hostname}</ComputerName>
|
|
<TimeZone>${timezone}</TimeZone>
|
|
<FirstLogonCommands>
|
|
<SynchronousCommand wcm:action="add">
|
|
<Order>1</Order>
|
|
<CommandLine>C:\post-oobe.cmd</CommandLine>
|
|
<RequiresUserInput>false</RequiresUserInput>
|
|
</SynchronousCommand>
|
|
</FirstLogonCommands>
|
|
</component>
|
|
</settings>
|
|
</unattend>
|
|
'';
|
|
in {
|
|
name = "generalize";
|
|
uploads = [
|
|
{ source = oobeXml; dest = "/oobe-unattend.xml"; }
|
|
{ source = postOobeScript; dest = "/post-oobe.cmd"; }
|
|
{ source = masScript; dest = "/MAS_AIO.cmd"; }
|
|
];
|
|
# Sysprep reboots into OOBE within the same QEMU session
|
|
auditScript = ''
|
|
@echo off
|
|
C:\Windows\System32\Sysprep\sysprep.exe /generalize /oobe /reboot /quiet /unattend:C:\oobe-unattend.xml
|
|
'';
|
|
}
|
|
|
|
# :: Enable RDP (sysprep resets offline registry changes)
|
|
# reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
|
|
# reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f
|
|
# netsh advfirewall firewall add rule name="RDP" dir=in protocol=tcp localport=3389 action=allow
|
|
# :: Start and enable the RDP service
|
|
# sc config TermService start= auto
|
|
# net start TermService
|
|
|