sync with labv2.nix + standalone flake with toDisk app
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>
This commit is contained in:
parent
dd1fb16e1b
commit
94f299bb81
77 changed files with 2785 additions and 796 deletions
|
|
@ -4,7 +4,6 @@ let
|
|||
network = import ./network.nix { inherit pkgs lib; };
|
||||
in
|
||||
{
|
||||
inherit images;
|
||||
inherit (images.commons) customizeImage customizeImageFold;
|
||||
inherit (images) linux windows;
|
||||
inherit network;
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{ pkgs, lib, ... }: rec {
|
||||
# basic scripts and files used across various OS images
|
||||
scriptsNFiles = (import ./scripts-n-files.nix) { inherit pkgs lib; };
|
||||
customizeImage = (import ./customizeImage.nix) { inherit pkgs lib; };
|
||||
customizeImageFold = builtins.foldl' customizeImage;
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
{ pkgs, lib, system, ... }:
|
||||
let
|
||||
commons = (import ./commons) { inherit pkgs lib system; };
|
||||
debian = (import ./debian) { inherit pkgs lib system commons; };
|
||||
in {
|
||||
inherit commons debian;
|
||||
{
|
||||
linux = (import ./linux) { inherit pkgs lib system; };
|
||||
windows = (import ./windows) { inherit pkgs lib system; };
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# wrapper function around virt-customize to create custom OS image from an original OS image
|
||||
# wrapper function around virt-customize to create custom Linux image from an original OS image
|
||||
{ pkgs, lib, ... }:
|
||||
originalImage: {
|
||||
name ? "",
|
||||
|
|
@ -10,19 +10,16 @@
|
|||
install ? [],
|
||||
run ? "",
|
||||
commands ? "",
|
||||
osType ? "linux",
|
||||
debug ? false
|
||||
debug ? false,
|
||||
impure ? true,
|
||||
# Linux-only: script to run on first boot (via systemd --firstboot)
|
||||
firstboot ? ""
|
||||
}:
|
||||
let
|
||||
originalImageName = lib.strings.removeSuffix "-vmix" (lib.strings.removeSuffix ".qcow2" originalImage.name);
|
||||
customImageName = (if name != "" then name else "custom") + "-${originalImageName}-vmix.qcow2";
|
||||
resultImg = "./disk.qcow2";
|
||||
|
||||
qemuWrapperScript = (pkgs.writeShellScript "qemu-wrapper-script" ''
|
||||
export PATH="${pkgs.qemu}/bin:$PATH"
|
||||
exec qemu-kvm -nic user,model=virtio-net-pci "$@"
|
||||
'');
|
||||
|
||||
setHostname = if hostname != "" then hostname else if nameToHostname then name else "";
|
||||
virtCustomizeArgsHostname = if setHostname != "" then "--hostname '${setHostname}'" else "";
|
||||
|
||||
|
|
@ -30,6 +27,9 @@
|
|||
virtCustomizeArgsCommandsFile = if commands != "" then ("--commands-from-file " + pkgs.writeText "${name}-virt-customize-commands-file" commands) else "";
|
||||
virtCustomizeArgsRun = if run != "" then ("--run " + pkgs.writeScript "${name}-virt-customize-run-script" "${run}") else "";
|
||||
|
||||
virtCustomizeArgsFirstboot = lib.optionalString (firstboot != "")
|
||||
("--firstboot " + pkgs.writeScript "${name}-firstboot" firstboot);
|
||||
|
||||
builderCommand = ''
|
||||
export PATH="${pkgs.qemu}/bin:${pkgs.curl}/bin:$PATH"
|
||||
|
||||
|
|
@ -39,7 +39,6 @@
|
|||
|
||||
# run script inside image using virt-customize
|
||||
export LIBGUESTFS_APPEND="ipv6.disable=1"
|
||||
#export LIBGUESTFS_HV="${qemuWrapperScript}"
|
||||
|
||||
${pkgs.guestfs-tools}/bin/virt-customize \
|
||||
${lib.optionalString debug "-v"} \
|
||||
|
|
@ -48,10 +47,13 @@
|
|||
--memsize ${builtins.toString memSize} \
|
||||
${virtCustomizeArgsHostname} \
|
||||
${virtCustomizeArgsInstall} \
|
||||
${virtCustomizeArgsFirstboot} \
|
||||
${virtCustomizeArgsCommandsFile} \
|
||||
${virtCustomizeArgsRun}
|
||||
|
||||
mv ${resultImg} $out
|
||||
'';
|
||||
|
||||
builtImage = pkgs.runCommand customImageName (lib.optionalAttrs impure { __noChroot = true; }) builderCommand;
|
||||
in
|
||||
pkgs.runCommand customImageName { __noChroot = true; } builderCommand
|
||||
builtImage // { _vmixOsType = "linux"; }
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
{ pkgs, lib, system, commons, ... }:
|
||||
{ pkgs, lib, system, linux, ... }:
|
||||
let
|
||||
# upstream distro images
|
||||
upstreamImagesJSON = lib.importJSON ./upstream.json;
|
||||
upstreamImages = lib.mapAttrs (name: src: pkgs.fetchurl src) upstreamImagesJSON.${system};
|
||||
templates = (import ./templates.nix) { inherit pkgs lib system commons; };
|
||||
customs = (import ./customs.nix) { inherit pkgs lib system commons upstreamImages templates; };
|
||||
upstreamImages = lib.mapAttrs (name: src: (pkgs.fetchurl src) // { _vmixOsType = "linux"; }) upstreamImagesJSON.${system};
|
||||
templates = (import ./templates.nix) { inherit pkgs lib system linux; };
|
||||
customs = (import ./images.nix) { inherit pkgs lib system linux upstreamImages templates; };
|
||||
mergeUpstreamAndCustomImages =
|
||||
name: upstreamImage:
|
||||
let
|
||||
|
|
@ -13,4 +13,4 @@ let
|
|||
customImages // { upstream = upstreamImage; };
|
||||
|
||||
images = lib.mapAttrs mergeUpstreamAndCustomImages upstreamImages;
|
||||
in images // { inherit templates; }
|
||||
in images // { inherit templates; }
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# create additional useful customized images from templates and upstream images
|
||||
{ pkgs, lib, system, commons, upstreamImages, templates, ... }:
|
||||
with commons;
|
||||
{ pkgs, lib, system, linux, upstreamImages, templates, ... }:
|
||||
with linux;
|
||||
with scriptsNFiles;
|
||||
let
|
||||
upstreamImageName = "v12";
|
||||
|
|
@ -20,8 +20,8 @@ in
|
|||
});
|
||||
|
||||
# proxmox
|
||||
proxmox = customizeImage default (templates.proxmoxOnDebian12 // {
|
||||
proxmox = customizeImage upstreamImages.${upstreamImageName} (templates.proxmoxOnDebian12 // {
|
||||
name = "proxmox";
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
# ready to use customization templates to apply on images
|
||||
{ pkgs, lib, system, commons, ... }:
|
||||
with commons;
|
||||
{ pkgs, lib, system, linux, ... }:
|
||||
with linux;
|
||||
with scriptsNFiles;
|
||||
{
|
||||
# essential functionalities like ssh, networking etc
|
||||
essentials = {
|
||||
impure = true;
|
||||
install = [ "htop" "openssh-server" "inetutils-ping" "dnsutils" "cloud-guest-utils" "qemu-guest-agent" ];
|
||||
commands = ''
|
||||
upload ${grub-ifnames-0}:/etc/default/grub.d/90-ifnames-0.cfg
|
||||
upload ${grub-disable-microcode}:/etc/default/grub.d/00-disable-microcode.cfg
|
||||
run-command mount /boot/efi && update-grub
|
||||
run-command mountpoint -q /boot/efi || mount /boot/efi
|
||||
run-command update-grub
|
||||
upload ${dhcp-network-for-iface { iface = "eth0"; }}:/etc/systemd/network/00-eth0-dhcp.network
|
||||
run ${ssh-service-override-conf-create}
|
||||
upload ${grow-root-sh}:/usr/local/sbin/grow-root.sh
|
||||
|
|
@ -22,6 +24,7 @@ with scriptsNFiles;
|
|||
|
||||
# set easy root access
|
||||
rooted = {
|
||||
impure = true;
|
||||
install = [ "openssh-server" ];
|
||||
commands = ''
|
||||
run ${ssh-service-override-conf-create}
|
||||
|
|
@ -36,17 +39,43 @@ with scriptsNFiles;
|
|||
|
||||
# install proxmox
|
||||
proxmoxOnDebian12 = {
|
||||
diskSize = "+2G";
|
||||
impure = true;
|
||||
diskSize = "+3G";
|
||||
smp = 4;
|
||||
memSize = 4096;
|
||||
install = [ "cloud-guest-utils" ];
|
||||
commands = ''
|
||||
debug = true;
|
||||
commands =
|
||||
let
|
||||
# proxmox makes it very hard to manually add interfaces directly on /etc/network/interfaces while the pve services are not running
|
||||
# it also doesn't pick up files in interfaces.d
|
||||
# so manually do that via service after boot
|
||||
mergeNetIfacesDService = pkgs.writeText "manual-net-ifaces.d.service" ''
|
||||
[Service]
|
||||
Type = oneshot
|
||||
ExecStart = /bin/bash -c "cat /etc/network/interfaces.d/* >> /etc/network/interfaces; rm /etc/network/interfaces.d/*; ifreload -a;"
|
||||
After = network.target
|
||||
|
||||
[Install]
|
||||
WantedBy = multi-user.target
|
||||
'';
|
||||
in
|
||||
''
|
||||
upload ${grub-ifnames-0}:/etc/default/grub.d/90-ifnames-0.cfg
|
||||
upload ${grub-disable-microcode}:/etc/default/grub.d/00-disable-microcode.cfg
|
||||
|
||||
truncate /etc/machine-id
|
||||
delete /var/lib/dbus/machine-id
|
||||
|
||||
upload ${grow-root-sh}:/usr/local/sbin/grow-root.sh
|
||||
upload ${grow-root-service}:/etc/systemd/system/grow-root.service
|
||||
run-command systemctl enable grow-root.service
|
||||
|
||||
upload ${mergeNetIfacesDService}:/etc/systemd/system/manual-net-ifaces.d.service
|
||||
run-command systemctl enable manual-net-ifaces.d.service
|
||||
'';
|
||||
run = ''
|
||||
# script originally taken from https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_12_Bookworm
|
||||
# script originally taken and modified from https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_12_Bookworm
|
||||
# exit if error
|
||||
set -e
|
||||
|
||||
|
|
@ -54,7 +83,7 @@ with scriptsNFiles;
|
|||
/usr/local/sbin/grow-root.sh
|
||||
|
||||
# mount efi for grub changes
|
||||
mount /boot/efi
|
||||
mount /boot/efi || true
|
||||
|
||||
# add proxmox repo
|
||||
echo "deb [arch=amd64] http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-install-repo.list
|
||||
|
|
@ -70,6 +99,29 @@ with scriptsNFiles;
|
|||
|
||||
# remove previous kernels
|
||||
apt remove -y os-prober linux-image-amd64 'linux-image-6.*';
|
||||
|
||||
# otherwise grub upgrades make the device unbootable
|
||||
echo 'grub-efi-amd64 grub2/force_efi_extra_removable boolean true' | debconf-set-selections -v -u
|
||||
rm -rf /boot/efi/*
|
||||
grub-install /dev/sda
|
||||
grub-install --target=x86_64-efi --removable
|
||||
|
||||
# disable subscription warning
|
||||
# https://dannyda.com/2020/05/17/how-to-remove-you-do-not-have-a-valid-subscription-for-this-server-from-proxmox-virtual-environment-6-1-2-proxmox-ve-6-1-2-pve-6-1-2/
|
||||
sed -i -z "s/res === null ||\n\s* res === undefined ||\n\s* \!res ||\n\s* res.data.status.toLowerCase() \!== 'active'/false/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
|
||||
|
||||
# stop hangs due to network
|
||||
systemctl disable systemd-networkd-wait-online.service
|
||||
|
||||
# create vmbr0 conf, enable dhcp. this conf will be picked by manual-net-ifaces.d.service
|
||||
cat >> /etc/network/interfaces.d/vmbr0.conf << EOF
|
||||
auto vmbr0
|
||||
iface vmbr0 inet dhcp
|
||||
bridge-ports eth0
|
||||
bridge-stp off
|
||||
bridge-fd 0
|
||||
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
@ -11,12 +11,12 @@
|
|||
},
|
||||
"x86_64-linux": {
|
||||
"v12": {
|
||||
"sha256": "0inga3c772wr9b296w86n8prlqvw47wd6b5z8347pygiw810y5yq",
|
||||
"url": "https://cloud.debian.org/images/cloud/bookworm/20240507-1740/debian-12-generic-amd64-20240507-1740.qcow2"
|
||||
"sha256": "5fvoe45ooVSPwQ3FRn8+ge18sAvSVk+m3iUO71WTM1A=",
|
||||
"url": "https://cloud.debian.org/images/cloud/bookworm/20250530-2128/debian-12-generic-amd64-20250530-2128.qcow2"
|
||||
},
|
||||
"v13": {
|
||||
"sha256": "1bixl6gnzigwryac1arc3n81nv4hwdi6wxpwmvrgigzni64b3x6w",
|
||||
"url": "https://cloud.debian.org/images/cloud/trixie/daily/20240512-1745/debian-13-generic-amd64-daily-20240512-1745.qcow2"
|
||||
"url": "https://cloud.debian.org/images/cloud/trixie/daily/20250605-2134/debian-13-generic-amd64-daily-20250605-2134.raw"
|
||||
}
|
||||
}
|
||||
}
|
||||
14
lib/images/linux/default.nix
Normal file
14
lib/images/linux/default.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{ pkgs, lib, system, ... }:
|
||||
let
|
||||
linux = rec {
|
||||
# basic scripts and files used across various Linux images
|
||||
scriptsNFiles = (import ./scripts-n-files.nix) { inherit pkgs lib; };
|
||||
customizeImage = (import ./customizeImage.nix) { inherit pkgs lib; };
|
||||
customizeImageFold = builtins.foldl' customizeImage;
|
||||
};
|
||||
debian = (import ./debian) { inherit pkgs lib system linux; };
|
||||
in linux // {
|
||||
images = {
|
||||
debian = debian;
|
||||
};
|
||||
}
|
||||
|
|
@ -69,4 +69,14 @@
|
|||
[Install]
|
||||
WantedBy = multi-user.target
|
||||
'';
|
||||
|
||||
add-9p-mounts-to-fstab = shares:
|
||||
let
|
||||
shareToFstabEntry = name: share: "${name} ${share.target} 9p trans=virtio,version=9p2000.L,rw,posixacl,msize=104857600,cache=loose 0 0";
|
||||
in
|
||||
pkgs.writeText "9p-to-fstab-sh" ''
|
||||
cat >> /etc/fstab << EOF
|
||||
${lib.concatStringsSep "\n" (lib.mapAttrsToList shareToFstabEntry shares)}
|
||||
EOF
|
||||
'';
|
||||
}
|
||||
32
lib/images/windows/default.nix
Normal file
32
lib/images/windows/default.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{ pkgs, lib, system, ... }:
|
||||
let
|
||||
windows = rec {
|
||||
drivers = import ./drivers { inherit pkgs system; };
|
||||
makeFilesISO = (import ./helpers/makeFilesISO.nix) { inherit pkgs; };
|
||||
customizeImage = (import ./helpers/customizeImage.nix) { inherit pkgs lib; };
|
||||
customizeImageFold = builtins.foldl' customizeImage;
|
||||
templates = (import ./templates) { inherit pkgs lib system drivers makeFilesISO; };
|
||||
makeAuditModeAutounattend = (import ./helpers/makeAuditModeAutounattend.nix) { inherit pkgs lib; };
|
||||
makeWinISO = (import ./helpers/makeWinISO.nix) { inherit pkgs; };
|
||||
makeImage = (import ./helpers/makeImage.nix) { inherit pkgs lib drivers makeWinISO makeAuditModeAutounattend; };
|
||||
};
|
||||
|
||||
win10 = (import ./win10) { inherit pkgs lib system windows; };
|
||||
win11 = (import ./win11) { inherit pkgs lib system windows; };
|
||||
|
||||
# Recursively add .generalize to every derivation leaf in the image tree
|
||||
addGeneralize = val:
|
||||
if val ? _vmixOsType then
|
||||
val // { generalize = args:
|
||||
let
|
||||
templateArgs = builtins.removeAttrs args [ "vncDisplay" ];
|
||||
displayArgs = lib.optionalAttrs (args ? vncDisplay) { inherit (args) vncDisplay; };
|
||||
in windows.customizeImage val (windows.templates.generalize templateArgs // displayArgs);
|
||||
}
|
||||
else if builtins.isAttrs val then
|
||||
lib.mapAttrs (_: addGeneralize) val
|
||||
else val;
|
||||
|
||||
in windows // {
|
||||
images = addGeneralize { inherit win10 win11; };
|
||||
}
|
||||
5
lib/images/windows/drivers/amd-gpu-drivers.nix
Normal file
5
lib/images/windows/drivers/amd-gpu-drivers.nix
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{ pkgs }:
|
||||
pkgs.fetchurl {
|
||||
url = "https://github.com/Matishzz/AMD-Install-Drivers/releases/download/25.3.1/25.3.1.w11-w10.zip";
|
||||
sha256 = "0mrz3kkiavs0l4x00978vdbw9la1j16jar0y6lny0l8z59hqp9gq";
|
||||
}
|
||||
4
lib/images/windows/drivers/default.nix
Normal file
4
lib/images/windows/drivers/default.nix
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{ pkgs, system, ... }: {
|
||||
virtio-iso = import ./virtio-iso-w10-11.nix { inherit pkgs; };
|
||||
amd-gpu-zip = import ./amd-gpu-drivers.nix { inherit pkgs; };
|
||||
}
|
||||
6
lib/images/windows/drivers/virtio-iso-w10-11.nix
Normal file
6
lib/images/windows/drivers/virtio-iso-w10-11.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# VirtIO drivers ISO for Windows guests (stable release from Fedora)
|
||||
{ pkgs, ... }:
|
||||
pkgs.fetchurl {
|
||||
url = " https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.285-1/virtio-win-0.1.285.iso";
|
||||
sha256 = "0cb3jyik40mkmyjwbagfj6609cnyzvysf2q7y0jykhwj8jwz4k71";
|
||||
}
|
||||
113
lib/images/windows/helpers/customizeImage.nix
Normal file
113
lib/images/windows/helpers/customizeImage.nix
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# Customize Windows images via offline registry merge and/or Audit Mode script execution.
|
||||
#
|
||||
# Templates can provide:
|
||||
# windowsRegistry — merged offline via virt-win-reg (fast, no boot needed)
|
||||
# auditScript — injected into image and run in Audit Mode via QEMU boot
|
||||
# cdroms — ISO files to attach as CDs when booting for auditScript
|
||||
#
|
||||
# Both can be combined: registry is applied first (offline), then the script runs (online).
|
||||
{ pkgs, lib, ... }:
|
||||
originalImage: {
|
||||
name ? "",
|
||||
diskSize ? "",
|
||||
impure ? true,
|
||||
# Offline: merge .reg file into registry via virt-win-reg
|
||||
windowsRegistry ? "",
|
||||
# Online: boot into Audit Mode and run this script
|
||||
auditScript ? "",
|
||||
# CD-ROMs to attach when booting for auditScript (e.g. VirtIO ISO)
|
||||
cdroms ? [],
|
||||
# Files to upload into the image before running auditScript
|
||||
# List of { source = <drv or path>; dest = "/Windows/path"; }
|
||||
uploads ? [],
|
||||
# QEMU settings for auditScript boot
|
||||
vncDisplay ? null,
|
||||
smp ? 4,
|
||||
memSize ? 4096,
|
||||
}:
|
||||
let
|
||||
originalImageName = lib.strings.removeSuffix "-vmix" (lib.strings.removeSuffix ".qcow2" originalImage.name);
|
||||
customImageName = (if name != "" then name else "custom") + "-${originalImageName}-vmix.qcow2";
|
||||
resultImg = "./disk.qcow2";
|
||||
|
||||
hasRegistry = windowsRegistry != "";
|
||||
hasAuditScript = auditScript != "";
|
||||
|
||||
# Offline registry merge
|
||||
windowsRegFile = pkgs.writeText "${name}-registry.reg" windowsRegistry;
|
||||
virtWinRegMerge = lib.optionalString hasRegistry ''
|
||||
|
||||
echo "=== vmix: merging registry entries (${name}) ==="
|
||||
virt-win-reg --merge ${resultImg} ${windowsRegFile}
|
||||
'';
|
||||
|
||||
# Audit Mode script injection + QEMU boot
|
||||
auditScriptFile = pkgs.writeText "${name}-audit.cmd" auditScript;
|
||||
wrapperScript = pkgs.writeText "${name}-audit-wrapper.cmd" ''
|
||||
@echo off
|
||||
echo === vmix audit: ${name} ===
|
||||
call C:\vmix-audit-script.cmd
|
||||
echo === vmix audit: ${name} complete ===
|
||||
del /q C:\vmix-audit-script.cmd 2>nul
|
||||
shutdown /s /t 5 /c "vmix: ${name} complete" 2>nul
|
||||
del /q C:\vmix-audit-wrapper.cmd 2>nul
|
||||
'';
|
||||
runOnceReg = pkgs.writeText "${name}-runonce.reg" (lib.concatStringsSep "\n" [
|
||||
"Windows Registry Editor Version 5.00"
|
||||
""
|
||||
''[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce]''
|
||||
''"vmixAudit"="C:\\vmix-audit-wrapper.cmd"''
|
||||
""
|
||||
]);
|
||||
|
||||
cdromArgs = lib.concatMapStringsSep " \\\n " (cd: "-drive file=${cd},media=cdrom,readonly=on") cdroms;
|
||||
|
||||
auditBootCommands = lib.optionalString hasAuditScript ''
|
||||
|
||||
echo "=== vmix: injecting audit script (${name}) ==="
|
||||
virt-customize -a ${resultImg} \
|
||||
--upload ${auditScriptFile}:/vmix-audit-script.cmd \
|
||||
--upload ${wrapperScript}:/vmix-audit-wrapper.cmd \
|
||||
${lib.concatMapStringsSep " \\\n " (u: let dir = builtins.dirOf u.dest; in "${lib.optionalString (dir != "/") "--mkdir ${dir}"} --upload ${u.source}:${u.dest}") uploads}
|
||||
|
||||
echo "=== vmix: adding RunOnce entry ==="
|
||||
virt-win-reg --merge ${resultImg} ${runOnceReg}
|
||||
|
||||
# Boot into Audit Mode to run the script
|
||||
cp ${pkgs.OVMF.fd}/FV/OVMF_VARS.fd vars.fd
|
||||
chmod +w vars.fd
|
||||
|
||||
echo "=== vmix: booting Audit Mode for ${name} (VNC: ${if vncDisplay != null then vncDisplay else "disabled"}) ==="
|
||||
timeout 1800 qemu-system-x86_64 \
|
||||
${if vncDisplay != null then "-vnc ${vncDisplay}" else "-nographic"} \
|
||||
-accel kvm \
|
||||
-m ${toString memSize} \
|
||||
-smp ${toString smp} \
|
||||
-cpu host \
|
||||
-machine type=q35 \
|
||||
-drive if=pflash,format=raw,readonly=on,file=${pkgs.OVMF.fd}/FV/OVMF_CODE.fd \
|
||||
-drive if=pflash,format=raw,file=vars.fd \
|
||||
-rtc base=localtime,clock=host \
|
||||
-device qemu-xhci -device usb-tablet \
|
||||
-global ICH9-LMB.disable_s3=1 -global ICH9-LMB.disable_s4=1 \
|
||||
-drive file=${resultImg},format=qcow2,if=virtio \
|
||||
${cdromArgs} \
|
||||
-nic user,model=virtio-net-pci
|
||||
|
||||
echo "=== vmix: audit script ${name} complete ==="
|
||||
'';
|
||||
|
||||
builderCommand = ''
|
||||
# create resulting image backed by original image
|
||||
qemu-img create -f qcow2 -b ${originalImage} -F qcow2 ${resultImg}
|
||||
[ -n "${diskSize}" ] && qemu-img resize ${resultImg} ${diskSize}
|
||||
${virtWinRegMerge}
|
||||
${auditBootCommands}
|
||||
mv ${resultImg} $out
|
||||
'';
|
||||
builtImage = pkgs.runCommand customImageName ({
|
||||
nativeBuildInputs = with pkgs; [ qemu perl guestfs-tools ];
|
||||
requiredSystemFeatures = [ "kvm" ];
|
||||
} // lib.optionalAttrs impure { __noChroot = true; }) builderCommand;
|
||||
in
|
||||
builtImage // { _vmixOsType = "windows"; }
|
||||
174
lib/images/windows/helpers/makeAuditModeAutounattend.nix
Normal file
174
lib/images/windows/helpers/makeAuditModeAutounattend.nix
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# Autounattend.xml for unattended Windows installation into Audit Mode.
|
||||
# Minimal — only what's needed to install Windows and enter Audit Mode.
|
||||
# All customization (hostname, timezone, telemetry, UAC, etc.) is done via templates.
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
locale ? "en-US",
|
||||
productKey ? "",
|
||||
diskIndex ? 0,
|
||||
imageIndex ? 1,
|
||||
efi ? true,
|
||||
virtioDriverLetter ? "E",
|
||||
bypassRequirements ? false,
|
||||
windowsVersionForVirtioDrivers
|
||||
}: pkgs.writeText "Autounattend.xml" ''
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend"
|
||||
xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
|
||||
|
||||
<!-- windowsPE — locale, product key, VirtIO drivers, disk partitioning -->
|
||||
<settings pass="windowsPE">
|
||||
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<SetupUILanguage>
|
||||
<UILanguage>${locale}</UILanguage>
|
||||
</SetupUILanguage>
|
||||
<InputLocale>${locale}</InputLocale>
|
||||
<SystemLocale>${locale}</SystemLocale>
|
||||
<UILanguage>${locale}</UILanguage>
|
||||
<UserLocale>${locale}</UserLocale>
|
||||
</component>
|
||||
|
||||
<component name="Microsoft-Windows-PnpCustomizationsWinPE" processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<DriverPaths>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="1">
|
||||
<Path>${virtioDriverLetter}:\amd64\${windowsVersionForVirtioDrivers}</Path>
|
||||
</PathAndCredentials>
|
||||
</DriverPaths>
|
||||
</component>
|
||||
|
||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<UserData>
|
||||
${lib.optionalString (productKey != "") ''
|
||||
<ProductKey>
|
||||
<Key>${productKey}</Key>
|
||||
</ProductKey>
|
||||
''}
|
||||
<AcceptEula>true</AcceptEula>
|
||||
</UserData>
|
||||
|
||||
<ImageInstall>
|
||||
<OSImage>
|
||||
<InstallFrom>
|
||||
<MetaData wcm:action="add">
|
||||
<Key>/IMAGE/INDEX</Key>
|
||||
<Value>${toString imageIndex}</Value>
|
||||
</MetaData>
|
||||
</InstallFrom>
|
||||
<InstallTo>
|
||||
<DiskID>${toString diskIndex}</DiskID>
|
||||
<PartitionID>${if efi then "3" else "1"}</PartitionID>
|
||||
</InstallTo>
|
||||
</OSImage>
|
||||
</ImageInstall>
|
||||
|
||||
<DiskConfiguration>
|
||||
<Disk wcm:action="add">
|
||||
<DiskID>${toString diskIndex}</DiskID>
|
||||
<WillWipeDisk>true</WillWipeDisk>
|
||||
${if efi then ''
|
||||
<CreatePartitions>
|
||||
<CreatePartition wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Size>100</Size>
|
||||
<Type>EFI</Type>
|
||||
</CreatePartition>
|
||||
<CreatePartition wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<Size>16</Size>
|
||||
<Type>MSR</Type>
|
||||
</CreatePartition>
|
||||
<CreatePartition wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<Extend>true</Extend>
|
||||
<Type>Primary</Type>
|
||||
</CreatePartition>
|
||||
</CreatePartitions>
|
||||
<ModifyPartitions>
|
||||
<ModifyPartition wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<PartitionID>1</PartitionID>
|
||||
<Format>FAT32</Format>
|
||||
<Label>EFI</Label>
|
||||
</ModifyPartition>
|
||||
<ModifyPartition wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<PartitionID>2</PartitionID>
|
||||
</ModifyPartition>
|
||||
<ModifyPartition wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<PartitionID>3</PartitionID>
|
||||
<Format>NTFS</Format>
|
||||
<Label>Windows</Label>
|
||||
</ModifyPartition>
|
||||
</ModifyPartitions>
|
||||
'' else ''
|
||||
<CreatePartitions>
|
||||
<CreatePartition wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Extend>true</Extend>
|
||||
<Type>Primary</Type>
|
||||
</CreatePartition>
|
||||
</CreatePartitions>
|
||||
<ModifyPartitions>
|
||||
<ModifyPartition wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<PartitionID>1</PartitionID>
|
||||
<Format>NTFS</Format>
|
||||
<Label>Windows</Label>
|
||||
<Active>true</Active>
|
||||
</ModifyPartition>
|
||||
</ModifyPartitions>
|
||||
''}
|
||||
</Disk>
|
||||
</DiskConfiguration>
|
||||
|
||||
${lib.optionalString bypassRequirements ''
|
||||
<RunSynchronous>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassTPMCheck /t REG_DWORD /d 1 /f</Path>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassSecureBootCheck /t REG_DWORD /d 1 /f</Path>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassRAMCheck /t REG_DWORD /d 1 /f</Path>
|
||||
</RunSynchronousCommand>
|
||||
</RunSynchronous>
|
||||
''}
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<!-- specialize — inject RunOnce to clean up cached Autounattend and shutdown -->
|
||||
<settings pass="specialize">
|
||||
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<RunSynchronous>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Path>reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" /v vmixCleanup /t REG_SZ /d "cmd /c del /q C:\Windows\Panther\unattend.xml" /f</Path>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<Path>reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" /v vmixShutdown /t REG_SZ /d "shutdown /s /t 10 /c vmix-audit-ready" /f</Path>
|
||||
</RunSynchronousCommand>
|
||||
</RunSynchronous>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<!-- oobeSystem — enter Audit Mode -->
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<Reseal>
|
||||
<Mode>Audit</Mode>
|
||||
</Reseal>
|
||||
</component>
|
||||
</settings>
|
||||
</unattend>
|
||||
''
|
||||
23
lib/images/windows/helpers/makeFilesISO.nix
Normal file
23
lib/images/windows/helpers/makeFilesISO.nix
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Create an ISO from a list of files. Zips are automatically extracted.
|
||||
# Nix store hash prefixes are stripped from filenames.
|
||||
# Usage:
|
||||
# makeFilesISO { name = "my-stuff"; files = [ ./foo.exe someZip anotherFile ]; }
|
||||
# makeFilesISO { name = "my-stuff"; files = [ (pkgs.fetchurl { ... }) ]; }
|
||||
{ pkgs, ... }:
|
||||
{ name ? "files", files }:
|
||||
pkgs.runCommand "${name}.iso" {
|
||||
nativeBuildInputs = with pkgs; [ unzip cdrkit file ];
|
||||
} ''
|
||||
mkdir -p content
|
||||
${builtins.concatStringsSep "\n" (map (f: ''
|
||||
if file --mime-type -b "${f}" | grep -q "application/zip"; then
|
||||
unzip -q -o "${f}" -d content
|
||||
else
|
||||
# Strip nix store hash prefix (e.g. "abc123-foo.exe" -> "foo.exe")
|
||||
fname=$(basename "${f}")
|
||||
stripped="''${fname#*-}"
|
||||
cp "${f}" "content/$stripped"
|
||||
fi
|
||||
'') files)}
|
||||
genisoimage -o $out -joliet -joliet-long -rational-rock content
|
||||
''
|
||||
69
lib/images/windows/helpers/makeImage.nix
Normal file
69
lib/images/windows/helpers/makeImage.nix
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# Build a pre-installed Windows qcow2 image using QEMU unattended install.
|
||||
# Boots into Audit Mode after install and shuts down.
|
||||
# Apply templates via customizeImageFold to install software (auditScript)
|
||||
# and customize registry (windowsRegistry), then generalize when done.
|
||||
{ pkgs, lib, drivers, makeWinISO, makeAuditModeAutounattend, ... }:
|
||||
{
|
||||
name ? "windows",
|
||||
upstreamISO,
|
||||
productKey ? "",
|
||||
imageIndex ? 1,
|
||||
diskSize ? "64G",
|
||||
bypassRequirements ? false,
|
||||
locale ? "en-US",
|
||||
efi ? true,
|
||||
smp ? 4,
|
||||
memSize ? 4096,
|
||||
vncDisplay ? null, # e.g. ":10" to enable VNC on port 5910 for monitoring
|
||||
windowsVersionForVirtioDrivers ? "w10", # "w10", "w11", "2k22", "2k19", etc.
|
||||
}:
|
||||
let
|
||||
AutounattendedXml = makeAuditModeAutounattend {
|
||||
inherit locale productKey imageIndex
|
||||
efi bypassRequirements windowsVersionForVirtioDrivers;
|
||||
diskIndex = 0;
|
||||
virtioDriverLetter = "E";
|
||||
};
|
||||
|
||||
iso = makeWinISO {
|
||||
iso = upstreamISO;
|
||||
inherit AutounattendedXml;
|
||||
};
|
||||
|
||||
drv = pkgs.runCommand "${name}-vmix.qcow2" {
|
||||
__noChroot = true;
|
||||
requiredSystemFeatures = [ "kvm" ];
|
||||
nativeBuildInputs = with pkgs; [ qemu ];
|
||||
} ''
|
||||
# create empty disk
|
||||
qemu-img create -f qcow2 disk.qcow2 ${diskSize}
|
||||
|
||||
# writable UEFI NVRAM so boot order persists across reboots
|
||||
cp ${pkgs.OVMF.fd}/FV/OVMF_VARS.fd vars.fd
|
||||
chmod +w vars.fd
|
||||
|
||||
echo "=== Starting Windows unattended install (this takes 15-30 minutes) ==="
|
||||
|
||||
# Windows installs unattended, reboots into Audit Mode,
|
||||
# deletes cached Autounattend, shuts down → QEMU exits.
|
||||
timeout 3600 qemu-system-x86_64 \
|
||||
${if vncDisplay != null then "-vnc ${vncDisplay}" else "-nographic"} \
|
||||
-accel kvm \
|
||||
-m ${toString memSize} \
|
||||
-smp ${toString smp} \
|
||||
-cpu host \
|
||||
-machine type=q35 \
|
||||
-drive if=pflash,format=raw,readonly=on,file=${pkgs.OVMF.fd}/FV/OVMF_CODE.fd \
|
||||
-drive if=pflash,format=raw,file=vars.fd \
|
||||
-rtc base=localtime,clock=host \
|
||||
-device qemu-xhci -device usb-tablet \
|
||||
-global ICH9-LMB.disable_s3=1 -global ICH9-LMB.disable_s4=1 \
|
||||
-drive file=disk.qcow2,format=qcow2,if=virtio \
|
||||
-drive file=${iso},media=cdrom,readonly=on \
|
||||
-drive file=${drivers.virtio-iso},media=cdrom,readonly=on \
|
||||
-nic user,model=virtio-net-pci
|
||||
|
||||
echo "=== Windows install complete (Audit Mode image) ==="
|
||||
mv disk.qcow2 $out
|
||||
'';
|
||||
in drv // { _vmixOsType = "windows"; }
|
||||
40
lib/images/windows/helpers/makeWinISO.nix
Normal file
40
lib/images/windows/helpers/makeWinISO.nix
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Remaster a Windows ISO: remove boot prompt, optionally inject Autounattend.xml and scripts
|
||||
{ pkgs, ... }:
|
||||
{ iso, AutounattendedXml ? null, postInstallScript ? null }:
|
||||
pkgs.runCommand "windows-remastered.iso" {
|
||||
nativeBuildInputs = with pkgs; [ p7zip cdrkit ];
|
||||
} ''
|
||||
workdir=$(mktemp -d)
|
||||
isopath="${iso}"
|
||||
if [ -d "$isopath" ]; then
|
||||
isopath="$(find "$isopath" -maxdepth 1 -name '*.iso' -type f | head -n1)"
|
||||
if [ -z "$isopath" ]; then
|
||||
echo "ERROR: no .iso file found in $isopath"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
7z x -o"$workdir" "$isopath" > /dev/null
|
||||
|
||||
# remove "Press any key to boot from CD/DVD" prompt
|
||||
if [ -f "$workdir/efi/microsoft/boot/efisys_noprompt.bin" ]; then
|
||||
cp "$workdir/efi/microsoft/boot/efisys_noprompt.bin" \
|
||||
"$workdir/efi/microsoft/boot/efisys.bin"
|
||||
fi
|
||||
if [ -f "$workdir/efi/microsoft/boot/cdboot_noprompt.efi" ]; then
|
||||
cp "$workdir/efi/microsoft/boot/cdboot_noprompt.efi" \
|
||||
"$workdir/efi/microsoft/boot/cdboot.efi"
|
||||
fi
|
||||
rm -f "$workdir/boot/bootfix.bin"
|
||||
|
||||
# inject unattend and post-install script into ISO root
|
||||
${if AutounattendedXml != null then ''cp ${AutounattendedXml} "$workdir/Autounattend.xml"'' else ""}
|
||||
${if postInstallScript != null then ''cp ${postInstallScript} "$workdir/post-install.cmd"'' else ""}
|
||||
|
||||
genisoimage \
|
||||
-allow-limited-size -iso-level 3 -o "$out" \
|
||||
-joliet -joliet-long -rational-rock -udf \
|
||||
-b boot/etfsboot.com -no-emul-boot -boot-load-size 8 -boot-info-table \
|
||||
-eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot \
|
||||
"$workdir"
|
||||
rm -rf "$workdir"
|
||||
''
|
||||
BIN
lib/images/windows/templates/apps/7zip-file-associations.reg
Normal file
BIN
lib/images/windows/templates/apps/7zip-file-associations.reg
Normal file
Binary file not shown.
20
lib/images/windows/templates/apps/7zip.nix
Normal file
20
lib/images/windows/templates/apps/7zip.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Install 7-Zip and set file associations
|
||||
{ pkgs, makeFilesISO, ... }:
|
||||
let
|
||||
installer = pkgs.fetchurl {
|
||||
url = "https://github.com/ip7z/7zip/releases/download/26.00/7z2600-x64.msi";
|
||||
hash = "sha256-w4jQREhxyhGyEjcAGvFYz92tfhN4UXleW2XO5ptRhJU=";
|
||||
};
|
||||
assocReg = ./7zip-file-associations.reg;
|
||||
in {
|
||||
name = "7zip";
|
||||
cdroms = [ (makeFilesISO { name = "7zip"; files = [ installer assocReg ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing 7-Zip...
|
||||
msiexec /i "D:\7z2600-x64.msi" /qn /norestart
|
||||
|
||||
echo Importing 7-Zip file associations...
|
||||
regedit /s "D:\7zip-file-associations.reg"
|
||||
'';
|
||||
}
|
||||
18
lib/images/windows/templates/apps/edge-webview.nix
Normal file
18
lib/images/windows/templates/apps/edge-webview.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Install Microsoft Edge WebView2 Runtime
|
||||
{ pkgs, makeFilesISO, ... }:
|
||||
let
|
||||
installer = pkgs.fetchurl {
|
||||
url = "https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/7ff41be4-dbce-4efe-823f-c7d33a4e3c5e/MicrosoftEdgeWebview2Setup.exe";
|
||||
hash = "sha256-Asl+XjKpfYlhY+xoo+o6sDOeV/J0NIuGiTmWOLZJsrk=";
|
||||
};
|
||||
in {
|
||||
name = "edge-webview";
|
||||
cdroms = [ (makeFilesISO { name = "edge-webview"; files = [ installer ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing Edge WebView2 Runtime...
|
||||
copy D:\MicrosoftEdgeWebview2Setup.exe C:\webview-setup.exe
|
||||
start /wait C:\webview-setup.exe /silent /install
|
||||
del /q C:\webview-setup.exe
|
||||
'';
|
||||
}
|
||||
Binary file not shown.
26
lib/images/windows/templates/apps/imageglass.nix
Normal file
26
lib/images/windows/templates/apps/imageglass.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Install ImageGlass and set file associations
|
||||
{ pkgs, makeFilesISO, ... }:
|
||||
let
|
||||
installer = pkgs.fetchurl {
|
||||
url = "https://github.com/d2phap/ImageGlass/releases/download/9.4.1.15/ImageGlass_9.4.1.15_x64.msi";
|
||||
hash = "sha256-o7q+5XpGLK+P/GQxvN/Ud5w1NxPpJ24AL54HNwda32Q=";
|
||||
};
|
||||
assocReg = ./imageglass-file-associations.reg;
|
||||
in {
|
||||
name = "imageglass";
|
||||
cdroms = [ (makeFilesISO { name = "imageglass"; files = [ installer assocReg ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing ImageGlass...
|
||||
msiexec /i "D:\ImageGlass_9.4.1.15_x64.msi" /qn /norestart ALLUSERS=1
|
||||
|
||||
echo Importing ImageGlass file associations...
|
||||
regedit /s "D:\imageglass-file-associations.reg"
|
||||
|
||||
:: delete shortcut on desktop
|
||||
del /q "C:\Users\Public\Desktop\ImageGlass.lnk"
|
||||
|
||||
:: Remove Paint Brush class registration
|
||||
reg delete "HKLM\SOFTWARE\Classes\PBrush" /f 2>nul
|
||||
'';
|
||||
}
|
||||
29
lib/images/windows/templates/apps/office.nix
Normal file
29
lib/images/windows/templates/apps/office.nix
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Install Microsoft Office 2024 (Word, Excel, PowerPoint) via offline deployment
|
||||
{ pkgs, makeFilesISO, ... }:
|
||||
let
|
||||
officeSrc = pkgs.fetchurl {
|
||||
url = "https://git.sagar.ch/dotfiles/office-2024-word-excel-powerpoint/archive/4351e8d93ceb28f65de9ec4dc9c27dccbe91ff34.zip";
|
||||
hash = "sha256-ulNecpkUH6O9cqYhgtmG++a1gi+c4HIR1Vvo22VygJs=";
|
||||
};
|
||||
in {
|
||||
name = "office";
|
||||
cdroms = [ (makeFilesISO { name = "office"; files = [ officeSrc ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing Microsoft Office 2024...
|
||||
call D:\office-2024-word-excel-powerpoint\install.bat
|
||||
|
||||
:: Office privacy policies (HKCU, preserved to new users via CopyProfile)
|
||||
reg add "HKCU\Software\Policies\Microsoft\office\16.0\common\privacy" /v "disconnectedstate" /t REG_DWORD /d 2 /f >nul
|
||||
reg add "HKCU\Software\Policies\Microsoft\office\16.0\common\privacy" /v "usercontentdisabled" /t REG_DWORD /d 2 /f >nul
|
||||
reg add "HKCU\Software\Policies\Microsoft\office\16.0\common\privacy" /v "downloadcontentdisabled" /t REG_DWORD /d 2 /f >nul
|
||||
reg add "HKCU\Software\Policies\Microsoft\office\16.0\common\privacy" /v "controllerconnectedservicesenabled" /t REG_DWORD /d 2 /f >nul
|
||||
reg add "HKCU\Software\Policies\Microsoft\office\common\clienttelemetry" /v "sendtelemetry" /t REG_DWORD /d 3 /f >nul
|
||||
|
||||
:: incase of enabling connected experiences, this disables the dialog box that shows at first run
|
||||
:: reg add "HKCU\SOFTWARE\Microsoft\Office\16.0\Common\Privacy\SettingsStore\Anonymous" /v "OptionalConnectedExperiencesNoticeVersion" /t REG_DWORD /d 2 /f >nul
|
||||
|
||||
:: supress dialogbox - Choose your theme for 365 Apps
|
||||
reg add "HKCU\SOFTWARE\Microsoft\Office\16.0\Common\PromoDialog" /v "FluentWelcomeDialogShown" /t REG_DWORD /d 1 /f >nul
|
||||
'';
|
||||
}
|
||||
16
lib/images/windows/templates/apps/sandboxie.nix
Normal file
16
lib/images/windows/templates/apps/sandboxie.nix
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Install Sandboxie-Plus
|
||||
{ pkgs, makeFilesISO, ... }:
|
||||
let
|
||||
installer = pkgs.fetchurl {
|
||||
url = "https://github.com/sandboxie-plus/Sandboxie/releases/download/v1.15.6/Sandboxie-Plus-x64-v1.15.6.exe";
|
||||
hash = "sha256-0VQXy9rFCJCfVyHLJYXe/s6imcwEZugsNOKMhUoLUVM=";
|
||||
};
|
||||
in {
|
||||
name = "sandboxie";
|
||||
cdroms = [ (makeFilesISO { name = "sandboxie"; files = [ installer ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing Sandboxie-Plus...
|
||||
start /wait D:\Sandboxie-Plus-x64-v1.15.6.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /MERGETASKS="!desktopicon"
|
||||
'';
|
||||
}
|
||||
40
lib/images/windows/templates/apps/thorium.nix
Normal file
40
lib/images/windows/templates/apps/thorium.nix
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Install Thorium browser and set as default via Active Setup (all users)
|
||||
# PS-SFTA is stored in Program Files and runs at each user's first logon.
|
||||
# post-oobe.cmd also runs SFTA for the initial user.
|
||||
{ pkgs, makeFilesISO, ... }:
|
||||
let
|
||||
installer = pkgs.fetchurl {
|
||||
url = "https://github.com/Alex313031/Thorium-Win/releases/download/M138.0.7204.303/thorium_AVX2_mini_installer.exe";
|
||||
hash = "sha256-43daDPX4N7NbVx1UfmO6KDMKKufhmpeQMO7qTeRggqo=";
|
||||
};
|
||||
sfta = pkgs.fetchurl {
|
||||
url = "https://raw.githubusercontent.com/DanysysTeam/PS-SFTA/master/SFTA.ps1";
|
||||
hash = "sha256-Prb23uP9jJFgQEIGC51ljwjshdP9ChR2kRnf14vDCFE=";
|
||||
};
|
||||
in {
|
||||
name = "thorium";
|
||||
cdroms = [ (makeFilesISO { name = "thorium"; files = [ installer sfta ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing Thorium browser...
|
||||
copy D:\thorium_AVX2_mini_installer.exe C:\thorium_installer.exe
|
||||
start /wait C:\thorium_installer.exe --silent --system-level --do-not-launch-chrome
|
||||
del /q C:\thorium_installer.exe
|
||||
echo Waiting for setup.exe to finish...
|
||||
:wait_loop
|
||||
tasklist /fi "imagename eq setup.exe" 2>nul | find /i "setup.exe" >nul
|
||||
if not errorlevel 1 (
|
||||
timeout /t 5 /nobreak >nul
|
||||
goto wait_loop
|
||||
)
|
||||
|
||||
echo Setting up Thorium as default browser for all users...
|
||||
:: Store SFTA in Program Files (survives sysprep as installed program)
|
||||
mkdir "C:\Program Files\vmix" 2>nul
|
||||
copy D:\SFTA.ps1 "C:\Program Files\vmix\SFTA.ps1" >nul
|
||||
:: Register Active Setup: runs at first logon for every new user
|
||||
reg add "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\vmix-default-browser" /v "(Default)" /t REG_SZ /d "Set default browser" /f >nul
|
||||
reg add "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\vmix-default-browser" /v "StubPath" /t REG_SZ /d "powershell -WindowStyle Hidden -ExecutionPolicy Bypass -Command \". 'C:\\Program Files\\vmix\\SFTA.ps1'; Set-FTA 'ThoriumHTM' '.htm'; Set-FTA 'ThoriumHTM' '.html'; Set-PTA 'ThoriumHTM' 'http'; Set-PTA 'ThoriumHTM' 'https'\"" /f >nul
|
||||
reg add "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\vmix-default-browser" /v "Version" /t REG_SZ /d "1,0,0,0" /f >nul
|
||||
'';
|
||||
}
|
||||
19
lib/images/windows/templates/apps/vlc.nix
Normal file
19
lib/images/windows/templates/apps/vlc.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Install VLC and register shell handlers for video/audio formats
|
||||
{ pkgs, makeFilesISO, ... }:
|
||||
let
|
||||
installer = pkgs.fetchurl {
|
||||
url = "https://get.videolan.org/vlc/3.0.21/win64/vlc-3.0.21-win64.exe";
|
||||
hash = "sha256-l0JomlDpbdwE2Azv8EayjaK+79YXvhgWb4xecV7GDFk=";
|
||||
};
|
||||
in {
|
||||
name = "vlc";
|
||||
cdroms = [ (makeFilesISO { name = "vlc"; files = [ installer ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing VLC...
|
||||
start /wait D:\vlc-3.0.21-win64.exe /S /L=1033
|
||||
|
||||
:: delete shortcut on desktop
|
||||
del /q "C:\Users\Public\Desktop\VLC media player.lnk"
|
||||
'';
|
||||
}
|
||||
49
lib/images/windows/templates/default-apps.nix
Normal file
49
lib/images/windows/templates/default-apps.nix
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Set default file associations via DefaultAssociations.xml policy.
|
||||
# Writes XML to C:\Program Files\vmix\ (survives sysprep as installed program).
|
||||
# Sets Group Policy registry to point at the XML.
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
name = "default-apps";
|
||||
auditScript = ''
|
||||
@echo off
|
||||
set "DA=C:\Program Files\vmix\DefaultAssociations.xml"
|
||||
mkdir "C:\Program Files\vmix" 2>nul
|
||||
echo ^<?xml version="1.0" encoding="UTF-8"?^> > "%DA%"
|
||||
echo ^<DefaultAssociations^> >> "%DA%"
|
||||
echo ^<Association Identifier=".7z" ProgId="7-Zip.7z" ApplicationName="7-Zip"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".zip" ProgId="7-Zip.zip" ApplicationName="7-Zip"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".rar" ProgId="7-Zip.rar" ApplicationName="7-Zip"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".tar" ProgId="7-Zip.tar" ApplicationName="7-Zip"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".gz" ProgId="7-Zip.gz" ApplicationName="7-Zip"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".xz" ProgId="7-Zip.xz" ApplicationName="7-Zip"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".cab" ProgId="7-Zip.cab" ApplicationName="7-Zip"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".mp4" ProgId="VLC.mp4" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".mkv" ProgId="VLC.mkv" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".avi" ProgId="VLC.avi" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".mov" ProgId="VLC.mov" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".wmv" ProgId="VLC.wmv" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".webm" ProgId="VLC.webm" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".mpg" ProgId="VLC.mpg" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".ts" ProgId="VLC.ts" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".mp3" ProgId="VLC.mp3" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".flac" ProgId="VLC.flac" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".wav" ProgId="VLC.wav" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".aac" ProgId="VLC.aac" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".ogg" ProgId="VLC.ogg" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".wma" ProgId="VLC.wma" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".m4a" ProgId="VLC.m4a" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".opus" ProgId="VLC.opus" ApplicationName="VLC"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".jpg" ProgId="ImageGlass.jpg" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".jpeg" ProgId="ImageGlass.jpeg" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".png" ProgId="ImageGlass.png" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".gif" ProgId="ImageGlass.gif" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".bmp" ProgId="ImageGlass.bmp" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".webp" ProgId="ImageGlass.webp" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".tif" ProgId="ImageGlass.tif" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".ico" ProgId="ImageGlass.ico" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".svg" ProgId="ImageGlass.svg" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^<Association Identifier=".heic" ProgId="ImageGlass.heic" ApplicationName="ImageGlass"/^> >> "%DA%"
|
||||
echo ^</DefaultAssociations^> >> "%DA%"
|
||||
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\System" /v DefaultAssociationsConfiguration /t REG_SZ /d "C:\Program Files\vmix\DefaultAssociations.xml" /f
|
||||
'';
|
||||
}
|
||||
43
lib/images/windows/templates/default.nix
Normal file
43
lib/images/windows/templates/default.nix
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Windows customization templates.
|
||||
# Templates can provide:
|
||||
# windowsRegistry — offline registry merge (fast, no boot)
|
||||
# auditScript — runs in Audit Mode via QEMU boot
|
||||
# cdroms — ISOs to attach when booting for auditScript
|
||||
# uploads — files to inject into the image before auditScript
|
||||
{ pkgs, lib, system, drivers, makeFilesISO, ... }:
|
||||
let
|
||||
args = { inherit pkgs lib system drivers makeFilesISO; };
|
||||
in {
|
||||
# Essentials (drivers, runtimes, removals, performance)
|
||||
essentials = {
|
||||
virtioTools = import ./essentials/virtio-tools.nix args;
|
||||
removeEdge = import ./essentials/remove-edge.nix args;
|
||||
removeIE = import ./essentials/remove-ie.nix args;
|
||||
removeWMP = import ./essentials/remove-wmp.nix args;
|
||||
removePaint = import ./essentials/remove-paint.nix args;
|
||||
amdGpuDrivers = import ./essentials/amd-gpu-drivers.nix args;
|
||||
vcppRuntimes = import ./essentials/vcpp-runtimes.nix args;
|
||||
bestPerformance = import ./essentials/best-performance.nix args;
|
||||
clearFileAssociations = import ./essentials/clear-file-associations.nix args;
|
||||
};
|
||||
|
||||
# Applications
|
||||
apps = {
|
||||
thorium = import ./apps/thorium.nix args;
|
||||
edgeWebview = import ./apps/edge-webview.nix args;
|
||||
sevenZip = import ./apps/7zip.nix args;
|
||||
vlc = import ./apps/vlc.nix args;
|
||||
imageGlass = import ./apps/imageglass.nix args;
|
||||
sandboxie = import ./apps/sandboxie.nix args;
|
||||
office = import ./apps/office.nix args;
|
||||
};
|
||||
|
||||
# Default file associations policy
|
||||
defaultApps = import ./default-apps.nix args;
|
||||
|
||||
# Generalize (sysprep + OOBE)
|
||||
generalize = import ./generalize.nix args;
|
||||
|
||||
# Offline registry templates
|
||||
reg = import ./registry args;
|
||||
}
|
||||
11
lib/images/windows/templates/essentials/amd-gpu-drivers.nix
Normal file
11
lib/images/windows/templates/essentials/amd-gpu-drivers.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Install AMD GPU drivers (silent install via INF from ISO)
|
||||
{ drivers, makeFilesISO, ... }:
|
||||
{
|
||||
name = "amd-gpu";
|
||||
cdroms = [ (makeFilesISO { name = "amd-gpu-drivers"; files = [ drivers.amd-gpu-zip ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing AMD GPU drivers (INF)...
|
||||
pnputil /add-driver "D:\WT6A_INF\u0413647.inf" /install /subdirs
|
||||
'';
|
||||
}
|
||||
46
lib/images/windows/templates/essentials/best-performance.nix
Normal file
46
lib/images/windows/templates/essentials/best-performance.nix
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Best Performance visual effects — set on Administrator profile in Audit Mode.
|
||||
# Used with generalize's CopyProfile=true: the Administrator's profile
|
||||
# (with these settings applied) becomes the default profile for new users.
|
||||
# CopyProfile bypasses SystemParametersInfo defaults during profile creation.
|
||||
# CopyProfile is the only approach that reliably actually works. Editing NTUSER.dat still reset some parameters
|
||||
{ ... }:
|
||||
{
|
||||
name = "best-perf";
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Applying best performance to current profile...
|
||||
:: Set appearance options to "custom"
|
||||
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\VisualEffects" /v VisualFXSetting /t REG_DWORD /d 3 /f
|
||||
:: Animate controls, fade/slide menus, fade/slide tooltips,
|
||||
:: fade out menu items, shadows under mouse, shadows under windows,
|
||||
:: slide open combo boxes, smooth-scroll list boxes (disabled)
|
||||
reg add "HKCU\Control Panel\Desktop" /v UserPreferencesMask /t REG_BINARY /d 9012038010000000 /f
|
||||
:: Animate windows when minimizing and maximizing (disabled)
|
||||
reg add "HKCU\Control Panel\Desktop\WindowMetrics" /v MinAnimate /t REG_SZ /d "0" /f
|
||||
:: Animations in the taskbar (disabled)
|
||||
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v TaskbarAnimations /t REG_DWORD /d 0 /f
|
||||
:: Enable Peek (disabled)
|
||||
reg add "HKCU\Software\Microsoft\Windows\DWM" /v EnableAeroPeek /t REG_DWORD /d 0 /f
|
||||
:: Save taskbar thumbnail previews (disabled)
|
||||
reg add "HKCU\Software\Microsoft\Windows\DWM" /v AlwaysHibernateThumbnails /t REG_DWORD /d 0 /f
|
||||
:: Show thumbnails instead of icons (disabled)
|
||||
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v IconsOnly /t REG_DWORD /d 1 /f
|
||||
:: Show translucent selection rectangle (disabled)
|
||||
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v ListviewAlphaSelect /t REG_DWORD /d 0 /f
|
||||
:: Show window contents while dragging (disabled)
|
||||
reg add "HKCU\Control Panel\Desktop" /v DragFullWindows /t REG_SZ /d "0" /f
|
||||
:: Smooth edges of screen fonts (enabled)
|
||||
reg add "HKCU\Control Panel\Desktop" /v FontSmoothing /t REG_SZ /d "2" /f
|
||||
reg add "HKCU\Control Panel\Desktop" /v FontSmoothingGamma /t REG_DWORD /d 0 /f
|
||||
reg add "HKCU\Control Panel\Desktop" /v FontSmoothingOrientation /t REG_DWORD /d 1 /f
|
||||
reg add "HKCU\Control Panel\Desktop" /v FontSmoothingType /t REG_DWORD /d 2 /f
|
||||
:: Use drop shadows for icon labels on the desktop (disabled)
|
||||
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v ListviewShadow /t REG_DWORD /d 0 /f
|
||||
:: Disable transparency effects
|
||||
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v EnableTransparency /t REG_DWORD /d 0 /f
|
||||
:: Disable accent color on taskbar and window borders
|
||||
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v ColorPrevalence /t REG_DWORD /d 0 /f
|
||||
reg add "HKCU\Software\Microsoft\Windows\DWM" /v ColorPrevalence /t REG_DWORD /d 0 /f
|
||||
|
||||
'';
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Clear all FileExts UserChoice entries on the Administrator profile.
|
||||
# In Audit Mode these keys aren't hash-protected yet.
|
||||
# With CopyProfile=true in generalize, the clean profile (without UserChoice)
|
||||
# is copied to new users, so HKLM Classes become the effective defaults.
|
||||
{ ... }:
|
||||
{
|
||||
name = "clear-assoc";
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Clearing FileExts UserChoice entries...
|
||||
reg delete "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts" /f 2>nul
|
||||
'';
|
||||
}
|
||||
50
lib/images/windows/templates/essentials/remove-edge.nix
Normal file
50
lib/images/windows/templates/essentials/remove-edge.nix
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Remove Microsoft Edge (both Chromium and built-in LTSC versions)
|
||||
{ ... }:
|
||||
{
|
||||
name = "no-edge";
|
||||
auditScript = ''
|
||||
@echo off
|
||||
:: Remove Chromium Edge using its installer
|
||||
for /f "delims=" %%i in ('dir /b /ad "C:\Program Files (x86)\Microsoft\Edge\Application" 2^>nul') do (
|
||||
if exist "C:\Program Files (x86)\Microsoft\Edge\Application\%%i\Installer\setup.exe" (
|
||||
"C:\Program Files (x86)\Microsoft\Edge\Application\%%i\Installer\setup.exe" --uninstall --system-level --force-uninstall
|
||||
)
|
||||
)
|
||||
|
||||
:: Remove Edge Update
|
||||
if exist "C:\Program Files (x86)\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe" (
|
||||
"C:\Program Files (x86)\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe" /uninstall
|
||||
)
|
||||
|
||||
:: Remove Edge directories
|
||||
rmdir /s /q "C:\Program Files (x86)\Microsoft\Edge" 2>nul
|
||||
rmdir /s /q "C:\Program Files (x86)\Microsoft\EdgeUpdate" 2>nul
|
||||
rmdir /s /q "C:\Program Files (x86)\Microsoft\EdgeCore" 2>nul
|
||||
|
||||
:: Remove Edge and DevToolsClient SystemApps
|
||||
for /d %%d in ("C:\Windows\SystemApps\Microsoft.MicrosoftEdge_*") do (
|
||||
takeown /f "%%d" /r /d y >nul 2>nul
|
||||
icacls "%%d" /grant Administrators:F /t >nul 2>nul
|
||||
rmdir /s /q "%%d" 2>nul
|
||||
)
|
||||
for /d %%d in ("C:\Windows\SystemApps\Microsoft.MicrosoftEdgeDevToolsClient_*") do (
|
||||
takeown /f "%%d" /r /d y >nul 2>nul
|
||||
icacls "%%d" /grant Administrators:F /t >nul 2>nul
|
||||
rmdir /s /q "%%d" 2>nul
|
||||
)
|
||||
|
||||
:: Remove Edge AppxPackage for all users (audit mode)
|
||||
powershell -Command "Get-AppxPackage -AllUsers *MicrosoftEdge* | Remove-AppxPackage -AllUsers -EA SilentlyContinue"
|
||||
|
||||
:: Remove Edge shortcuts
|
||||
del /q "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk" 2>nul
|
||||
del /q "%PUBLIC%\Desktop\Microsoft Edge.lnk" 2>nul
|
||||
del /q "%APPDATA%\Microsoft\Internet Explorer\Quick Launch\Microsoft Edge.lnk" 2>nul
|
||||
del /q "%APPDATA%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Microsoft Edge.lnk" 2>nul
|
||||
|
||||
:: Remove Edge Update scheduled tasks
|
||||
schtasks /delete /tn "\MicrosoftEdgeUpdateTaskMachineCore" /f 2>nul
|
||||
schtasks /delete /tn "\MicrosoftEdgeUpdateTaskMachineUA" /f 2>nul
|
||||
reg add "HKLM\SOFTWARE\Microsoft\EdgeUpdate" /v DoNotUpdateToEdgeWithChromium /t REG_DWORD /d 1 /f
|
||||
'';
|
||||
}
|
||||
12
lib/images/windows/templates/essentials/remove-ie.nix
Normal file
12
lib/images/windows/templates/essentials/remove-ie.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Remove Internet Explorer
|
||||
{ ... }:
|
||||
{
|
||||
name = "no-ie";
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Removing Internet Explorer...
|
||||
dism /online /Remove-Capability /CapabilityName:Browser.InternetExplorer~~~~0.0.11.0 /NoRestart 2>nul
|
||||
:: Disable IE feature if still present
|
||||
dism /online /Disable-Feature /FeatureName:Internet-Explorer-Optional-amd64 /NoRestart 2>nul
|
||||
'';
|
||||
}
|
||||
20
lib/images/windows/templates/essentials/remove-paint.nix
Normal file
20
lib/images/windows/templates/essentials/remove-paint.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Remove Microsoft Paint
|
||||
{ ... }:
|
||||
{
|
||||
name = "no-paint";
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Removing Microsoft Paint...
|
||||
:: Take ownership and delete mspaint.exe
|
||||
takeown /f "C:\Windows\System32\mspaint.exe" >nul 2>nul
|
||||
icacls "C:\Windows\System32\mspaint.exe" /grant Administrators:F >nul 2>nul
|
||||
del /f "C:\Windows\System32\mspaint.exe" 2>nul
|
||||
:: Remove Paint optional feature
|
||||
dism /online /Remove-Capability /CapabilityName:Microsoft.Windows.MSPaint~~~~0.0.1.0 /NoRestart 2>nul
|
||||
:: Remove Paint shortcuts
|
||||
del /q "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Accessories\Paint.lnk" 2>nul
|
||||
:: Remove PBrush class registration
|
||||
reg delete "HKLM\SOFTWARE\Classes\PBrush" /f 2>nul
|
||||
reg delete "HKLM\SOFTWARE\Classes\pbrush" /f 2>nul
|
||||
'';
|
||||
}
|
||||
11
lib/images/windows/templates/essentials/remove-wmp.nix
Normal file
11
lib/images/windows/templates/essentials/remove-wmp.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Remove Windows Media Player
|
||||
{ ... }:
|
||||
{
|
||||
name = "no-wmp";
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Removing Windows Media Player...
|
||||
dism /online /Disable-Feature /FeatureName:WindowsMediaPlayer /NoRestart 2>nul
|
||||
dism /online /Remove-Capability /CapabilityName:Microsoft.Windows.MediaPlayer~~~~0.0.12.0 /NoRestart 2>nul
|
||||
'';
|
||||
}
|
||||
18
lib/images/windows/templates/essentials/vcpp-runtimes.nix
Normal file
18
lib/images/windows/templates/essentials/vcpp-runtimes.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Install all Visual C++ Redistributable runtimes (2005-2022, x86+x64)
|
||||
{ pkgs, makeFilesISO, ... }:
|
||||
let
|
||||
installer = pkgs.fetchurl {
|
||||
url = "https://github.com/abbodi1406/vcredist/releases/download/v0.103.0/VisualCppRedist_AIO_x86_x64.exe";
|
||||
hash = "sha256-PBiORlG8wH3yvbBtaVhRWHl7G6+5FVewkhdiFijNWyM=";
|
||||
};
|
||||
in {
|
||||
name = "vcpp";
|
||||
cdroms = [ (makeFilesISO { name = "vcpp-runtimes"; files = [ installer ]; }) ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
echo Installing Visual C++ Redistributable runtimes...
|
||||
copy D:\VisualCppRedist_AIO_x86_x64.exe C:\vcpp-setup.exe
|
||||
start /wait C:\vcpp-setup.exe /ai /gm2
|
||||
del /q C:\vcpp-setup.exe
|
||||
'';
|
||||
}
|
||||
18
lib/images/windows/templates/essentials/virtio-tools.nix
Normal file
18
lib/images/windows/templates/essentials/virtio-tools.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Install VirtIO guest tools (QEMU agent + SPICE vdagent)
|
||||
{ drivers, ... }:
|
||||
{
|
||||
name = "virtio";
|
||||
cdroms = [ drivers.virtio-iso ];
|
||||
auditScript = ''
|
||||
@echo off
|
||||
:: VirtIO ISO is the first (and only) CD — drive letter D:
|
||||
if exist D:\cert\virtio_win_cert.cer (
|
||||
certutil -addstore TrustedPublisher D:\cert\virtio_win_cert.cer
|
||||
)
|
||||
if exist D:\virtio-win-guest-tools.exe (
|
||||
D:\virtio-win-guest-tools.exe /install /passive /norestart
|
||||
) else if exist D:\guest-agent\qemu-ga-x86_64.msi (
|
||||
msiexec /i D:\guest-agent\qemu-ga-x86_64.msi /qn /norestart
|
||||
)
|
||||
'';
|
||||
}
|
||||
168
lib/images/windows/templates/generalize.nix
Normal file
168
lib/images/windows/templates/generalize.nix
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
# 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
|
||||
|
||||
10
lib/images/windows/templates/registry/ai.nix
Normal file
10
lib/images/windows/templates/registry/ai.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Disable Copilot, Recall, and AI data analysis
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsCopilot]
|
||||
"TurnOffWindowsCopilot"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsAI]
|
||||
"AllowRecallEnablement"=dword:00000000
|
||||
"DisableAIDataAnalysis"=dword:00000001
|
||||
''
|
||||
50
lib/images/windows/templates/registry/consumer.nix
Normal file
50
lib/images/windows/templates/registry/consumer.nix
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Disable consumer features, suggested apps, push-to-install, widgets, Cortana
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CloudContent]
|
||||
"DisableWindowsConsumerFeatures"=dword:00000001
|
||||
"DisableTailoredExperiencesWithDiagnosticData"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\PushToInstall]
|
||||
"DisablePushToInstall"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Windows Feeds]
|
||||
"EnableFeeds"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Dsh]
|
||||
"AllowNewsAndInterests"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Windows Search]
|
||||
"AllowCortana"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Explorer]
|
||||
"DisableSearchBoxSuggestions"=dword:00000001
|
||||
"HideSCAMeetNow"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\GameDVR]
|
||||
"AllowGameDVR"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\System\GameConfigStore]
|
||||
"GameDVR_Enabled"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Maps]
|
||||
"AutoDownloadAndUpdateMapData"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\MapsBroker]
|
||||
"Start"=dword:00000004
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\XblAuthManager]
|
||||
"Start"=dword:00000004
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\XblGameSave]
|
||||
"Start"=dword:00000004
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\XboxNetApiSvc]
|
||||
"Start"=dword:00000004
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\WMPNetworkSvc]
|
||||
"Start"=dword:00000004
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\RetailDemo]
|
||||
"Start"=dword:00000004
|
||||
''
|
||||
63
lib/images/windows/templates/registry/default.nix
Normal file
63
lib/images/windows/templates/registry/default.nix
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Offline registry customization templates.
|
||||
# Each file returns raw registry entries (no header).
|
||||
# Templates are composed into bundles via mkReg which adds the .reg header.
|
||||
{ ... }:
|
||||
let
|
||||
regHeader = "Windows Registry Editor Version 5.00";
|
||||
mkReg = entries: ''
|
||||
${regHeader}
|
||||
${entries}
|
||||
'';
|
||||
|
||||
rdpEntries = import ./rdp.nix;
|
||||
telemetryEntries = import ./telemetry.nix;
|
||||
errorReportingEntries = import ./error-reporting.nix;
|
||||
defenderEntries = import ./defender.nix;
|
||||
updatesEntries = import ./updates.nix;
|
||||
smartScreenEntries = import ./smart-screen.nix;
|
||||
hibernationEntries = import ./hibernation.nix;
|
||||
systemRestoreEntries = import ./system-restore.nix;
|
||||
networkEntries = import ./insecure-samba.nix;
|
||||
privacyEntries = import ./privacy.nix;
|
||||
aiEntries = import ./ai.nix;
|
||||
consumerEntries = import ./consumer.nix;
|
||||
performanceEntries = import ./performance.nix;
|
||||
disableUcpdEntries = import ./disable-ucpd.nix;
|
||||
|
||||
in rec {
|
||||
# === Individual templates ===
|
||||
disableTelemetry = { name = "no-telemetry"; windowsRegistry = mkReg telemetryEntries; };
|
||||
disableErrorReporting = { name = "no-wer"; windowsRegistry = mkReg errorReportingEntries; };
|
||||
disableDefender = { name = "no-defender"; windowsRegistry = mkReg defenderEntries; };
|
||||
disableUpdates = { name = "no-updates"; windowsRegistry = mkReg updatesEntries; };
|
||||
disableSmartScreen = { name = "no-smartscreen"; windowsRegistry = mkReg smartScreenEntries; };
|
||||
disableHibernation = { name = "no-hibernate"; windowsRegistry = mkReg hibernationEntries; };
|
||||
disableSystemRestore = { name = "no-restore"; windowsRegistry = mkReg systemRestoreEntries; };
|
||||
networkTweaks = { name = "network"; windowsRegistry = mkReg networkEntries; };
|
||||
disablePrivacyTracking = { name = "no-tracking"; windowsRegistry = mkReg privacyEntries; };
|
||||
disableAI = { name = "no-ai"; windowsRegistry = mkReg aiEntries; };
|
||||
disableConsumerFeatures = { name = "no-consumer"; windowsRegistry = mkReg consumerEntries; };
|
||||
performanceTweaks = { name = "performance"; windowsRegistry = mkReg performanceEntries; };
|
||||
disableUCPD = { name = "no-ucpd"; windowsRegistry = mkReg disableUcpdEntries; };
|
||||
|
||||
# === Convenience bundles ==
|
||||
|
||||
# Hardened: comprehensive debloat for lab VMs
|
||||
hardened = {
|
||||
name = "hardened";
|
||||
windowsRegistry = mkReg (
|
||||
telemetryEntries
|
||||
+ errorReportingEntries
|
||||
+ defenderEntries
|
||||
+ updatesEntries
|
||||
+ smartScreenEntries
|
||||
+ hibernationEntries
|
||||
+ systemRestoreEntries
|
||||
+ networkEntries
|
||||
+ privacyEntries
|
||||
+ aiEntries
|
||||
+ consumerEntries
|
||||
+ performanceEntries
|
||||
);
|
||||
};
|
||||
}
|
||||
11
lib/images/windows/templates/registry/defender.nix
Normal file
11
lib/images/windows/templates/registry/defender.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Disable Windows Defender
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender]
|
||||
"DisableAntiSpyware"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection]
|
||||
"DisableRealtimeMonitoring"=dword:00000001
|
||||
''
|
||||
10
lib/images/windows/templates/registry/disable-ucpd.nix
Normal file
10
lib/images/windows/templates/registry/disable-ucpd.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Disable User Choice Protection Driver (UCPD) on Win11
|
||||
# This allows programmatic changes to file/URL associations via UserChoice
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\System]
|
||||
"EnableUCPD"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\UCPD]
|
||||
"Start"=dword:00000004
|
||||
''
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Disable Windows Error Reporting
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting]
|
||||
"Disabled"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\WerSvc]
|
||||
"Start"=dword:00000004
|
||||
''
|
||||
9
lib/images/windows/templates/registry/hibernation.nix
Normal file
9
lib/images/windows/templates/registry/hibernation.nix
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Disable hibernation and fast startup (avoids disk corruption with snapshots)
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Power]
|
||||
"HiberbootEnabled"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Power]
|
||||
"HibernateEnabled"=dword:00000000
|
||||
''
|
||||
12
lib/images/windows/templates/registry/insecure-samba.nix
Normal file
12
lib/images/windows/templates/registry/insecure-samba.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Suppress network discovery popup and allow insecure guest logons for SMB
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Network\NewNetworkWindowOff]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\LanmanWorkstation]
|
||||
"AllowInsecureGuestAuth"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\LanmanWorkstation\Parameters]
|
||||
"AllowInsecureGuestAuth"=dword:00000001
|
||||
"RequireSecuritySignature"=dword:00000000
|
||||
''
|
||||
34
lib/images/windows/templates/registry/performance.nix
Normal file
34
lib/images/windows/templates/registry/performance.nix
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# VM performance optimizations: disable power throttling, SysMain, lock screen, autorun
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Power]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Power\PowerThrottling]
|
||||
"PowerThrottlingOff"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control]
|
||||
"SvcHostSplitThresholdInKB"=dword:00400000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\FileSystem]
|
||||
"LongPathsEnabled"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Remote Assistance]
|
||||
"fAllowToGetHelp"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Personalization]
|
||||
"NoLockScreen"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer]
|
||||
"NoDriveTypeAutoRun"=dword:000000ff
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\FileHistory]
|
||||
"Disabled"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\SysMain]
|
||||
"Start"=dword:00000004
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\RemoteRegistry]
|
||||
"Start"=dword:00000004
|
||||
''
|
||||
44
lib/images/windows/templates/registry/privacy.nix
Normal file
44
lib/images/windows/templates/registry/privacy.nix
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# Disable activity tracking, advertising ID, location, and input data collection
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\System]
|
||||
"EnableActivityFeed"=dword:00000000
|
||||
"PublishUserActivities"=dword:00000000
|
||||
"UploadUserActivities"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\AdvertisingInfo]
|
||||
"DisabledByGroupPolicy"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Privacy]
|
||||
"TailoredExperiencesWithDiagnosticDataEnabled"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\LocationAndSensors]
|
||||
"DisableLocation"=dword:00000001
|
||||
"DisableLocationScripting"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\lfsvc]
|
||||
"Start"=dword:00000004
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\HandwritingErrorReports]
|
||||
"PreventHandwritingErrorReports"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\TabletPC]
|
||||
"PreventHandwritingDataSharing"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\InputPersonalization]
|
||||
"RestrictImplicitTextCollection"=dword:00000001
|
||||
"RestrictImplicitInkCollection"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsInkWorkspace]
|
||||
"AllowWindowsInkWorkspace"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Settings]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Settings\OnlineSpeechPrivacy]
|
||||
"HasAccepted"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\AppPrivacy]
|
||||
"LetAppsRunInBackground"=dword:00000002
|
||||
''
|
||||
6
lib/images/windows/templates/registry/smart-screen.nix
Normal file
6
lib/images/windows/templates/registry/smart-screen.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Disable SmartScreen
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\System]
|
||||
"EnableSmartScreen"=dword:00000000
|
||||
''
|
||||
8
lib/images/windows/templates/registry/system-restore.nix
Normal file
8
lib/images/windows/templates/registry/system-restore.nix
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Disable system restore
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\SystemRestore]
|
||||
"DisableSR"=dword:00000001
|
||||
''
|
||||
15
lib/images/windows/templates/registry/telemetry.nix
Normal file
15
lib/images/windows/templates/registry/telemetry.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Disable telemetry, diagnostics tracking, and feedback
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\DataCollection]
|
||||
"AllowTelemetry"=dword:00000000
|
||||
"DoNotShowFeedbackNotifications"=dword:00000001
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\DiagTrack]
|
||||
"Start"=dword:00000004
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\dmwappushservice]
|
||||
"Start"=dword:00000004
|
||||
''
|
||||
21
lib/images/windows/templates/registry/updates.nix
Normal file
21
lib/images/windows/templates/registry/updates.nix
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Disable automatic Windows updates, driver searching, and update-related annoyances
|
||||
''
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU]
|
||||
"NoAutoUpdate"=dword:00000001
|
||||
"NoAutoRebootWithLoggedOnUsers"=dword:00000001
|
||||
"AUPowerManagement"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization]
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config]
|
||||
"DODownloadMode"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\DriverSearching]
|
||||
"SearchOrderConfig"=dword:00000000
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\DoSvc]
|
||||
"Start"=dword:00000004
|
||||
''
|
||||
12
lib/images/windows/win10/default.nix
Normal file
12
lib/images/windows/win10/default.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{ pkgs, lib, system, windows, ... }:
|
||||
let
|
||||
upstreamISOsJSON = lib.importJSON ./upstream.json;
|
||||
|
||||
fetchUpstream = name: src:
|
||||
if (src.type or "") == "fetchgit"
|
||||
then pkgs.fetchgit { inherit (src) url rev hash fetchLFS; }
|
||||
else pkgs.fetchurl { inherit (src) url sha256; };
|
||||
|
||||
upstreamISOs = lib.mapAttrs fetchUpstream upstreamISOsJSON.${system};
|
||||
images = (import ./images.nix) { inherit pkgs lib system windows upstreamISOs; };
|
||||
in images
|
||||
34
lib/images/windows/win10/images.nix
Normal file
34
lib/images/windows/win10/images.nix
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Pre-built Win10 LTSC 2021 images from upstream ISO
|
||||
# Pipeline: makeImage (Audit Mode) → essentials → apps → registry → generalize
|
||||
{ pkgs, lib, system, windows, upstreamISOs, ... }:
|
||||
with windows;
|
||||
{
|
||||
ltsc = rec {
|
||||
upstream = makeImage {
|
||||
name = "win10-ltsc-2021";
|
||||
upstreamISO = upstreamISOs.win10-ltsc-2021;
|
||||
productKey = "M7XTQ-FN8P6-TTKYV-9D4CC-J462D";
|
||||
};
|
||||
basic = customizeImageFold upstream (with templates; [
|
||||
essentials.virtioTools
|
||||
essentials.removeIE
|
||||
essentials.removeWMP
|
||||
essentials.removeEdge
|
||||
essentials.vcppRuntimes
|
||||
essentials.bestPerformance
|
||||
reg.hardened
|
||||
apps.edgeWebview
|
||||
apps.thorium
|
||||
]);
|
||||
|
||||
withApps = customizeImageFold basic (with templates; [
|
||||
apps.sandboxie
|
||||
apps.sevenZip
|
||||
apps.vlc
|
||||
apps.imageGlass
|
||||
apps.office
|
||||
]);
|
||||
|
||||
withAMDGPU = customizeImage basic templates.essentials.amdGpuDrivers;
|
||||
};
|
||||
}
|
||||
11
lib/images/windows/win10/upstream.json
Normal file
11
lib/images/windows/win10/upstream.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"x86_64-linux": {
|
||||
"win10-ltsc-2021": {
|
||||
"type": "fetchgit",
|
||||
"url": "https://git.sagar.ch/dotfiles/win10ltsc2021-official.iso.git",
|
||||
"rev": "9bb55c21ceaf224504c4240677e808b3ec91a610",
|
||||
"hash": "sha256-AeGnOnkToOSiD5iRblLKaRmR8qBUkCaGp8F8KkGlVIA=",
|
||||
"fetchLFS": true
|
||||
}
|
||||
}
|
||||
}
|
||||
12
lib/images/windows/win11/default.nix
Normal file
12
lib/images/windows/win11/default.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{ pkgs, lib, system, windows, ... }:
|
||||
let
|
||||
upstreamISOsJSON = lib.importJSON ./upstream.json;
|
||||
|
||||
fetchUpstream = name: src:
|
||||
if (src.type or "") == "fetchgit"
|
||||
then pkgs.fetchgit { inherit (src) url rev hash fetchLFS; }
|
||||
else pkgs.fetchurl { inherit (src) url sha256; };
|
||||
|
||||
upstreamISOs = lib.mapAttrs fetchUpstream upstreamISOsJSON.${system};
|
||||
images = (import ./images.nix) { inherit pkgs lib system windows upstreamISOs; };
|
||||
in images
|
||||
38
lib/images/windows/win11/images.nix
Normal file
38
lib/images/windows/win11/images.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Pre-built Win11 LTSC 2024 images from upstream ISO
|
||||
# Pipeline: makeImage (Audit Mode) → essentials → apps → registry
|
||||
{ pkgs, lib, system, windows, upstreamISOs, ... }:
|
||||
with windows;
|
||||
{
|
||||
ltsc = rec {
|
||||
upstream = makeImage {
|
||||
name = "win11-ltsc-2024";
|
||||
upstreamISO = upstreamISOs.win11-ltsc-2024;
|
||||
productKey = "M7XTQ-FN8P6-TTKYV-9D4CC-J462D";
|
||||
bypassRequirements = true;
|
||||
windowsVersionForVirtioDrivers = "w11";
|
||||
};
|
||||
|
||||
basic = customizeImageFold upstream (with templates; [
|
||||
essentials.virtioTools
|
||||
essentials.removeIE
|
||||
essentials.removeWMP
|
||||
essentials.removeEdge
|
||||
essentials.vcppRuntimes
|
||||
essentials.bestPerformance
|
||||
reg.hardened
|
||||
reg.disableUCPD
|
||||
apps.edgeWebview
|
||||
apps.thorium
|
||||
]);
|
||||
|
||||
withApps = customizeImageFold basic (with templates; [
|
||||
apps.sandboxie
|
||||
apps.sevenZip
|
||||
apps.vlc
|
||||
apps.imageGlass
|
||||
apps.office
|
||||
]);
|
||||
|
||||
withAMDGPU = customizeImage basic templates.essentials.amdGpuDrivers;
|
||||
};
|
||||
}
|
||||
11
lib/images/windows/win11/upstream.json
Normal file
11
lib/images/windows/win11/upstream.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"x86_64-linux": {
|
||||
"win11-ltsc-2024": {
|
||||
"type": "fetchgit",
|
||||
"url": "https://git.sagar.ch/dotfiles/win11ltsc2024-official.iso.git",
|
||||
"rev": "d4a749719eb593884d1ba9835b96104e1f06290b",
|
||||
"hash": "sha256-AWp4SPVfpHT7jAczaq24bgrYUZy4sLByRHMhGbPFBwg=",
|
||||
"fetchLFS": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{ pkgs, lib, ... }: rec {
|
||||
calc = (import ((builtins.fetchTarball "https://gist.github.com/duairc/5c9bb3c922e5d501a1edb9e7b3b845ba/archive/3885f7cd9ed0a746a9d675da6f265d41e9fd6704.tar.gz") + "/net.nix" ) { inherit lib; }).lib.net;
|
||||
calc = (import ((builtins.fetchTarball { url = "https://gist.github.com/duairc/5c9bb3c922e5d501a1edb9e7b3b845ba/archive/3885f7cd9ed0a746a9d675da6f265d41e9fd6704.tar.gz"; sha256 = "sha256:0s17g6jdkfnsqxwh1k9arhn4r2aa3rknpnhpkppw1sbzjix36c4b"; }) + "/net.nix" ) { inherit lib; }).lib.net;
|
||||
regex.ipv4 =
|
||||
let
|
||||
compRegex = "(25[0-5]|(2[0-4]|10|1?[1-9])?[0-9])";
|
||||
|
|
@ -8,6 +8,33 @@
|
|||
|
||||
regex.cidr4 = "${regex.ipv4}/(3[0-2]|[1-2]?[0-9])";
|
||||
regex.ipOrCidr4 = "(${regex.ipv4}|${regex.cidr4})";
|
||||
ipv4ToInt = ipv4: calc.ip.diff ipv4 "0.0.0.0";
|
||||
intToipv4 = inte: calc.ip.add "0.0.0.0" inte;
|
||||
|
||||
ipv4ToInt = ip:
|
||||
with builtins;
|
||||
with lib;
|
||||
let
|
||||
octets = match ''^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$'' ip;
|
||||
in
|
||||
if octets == null then
|
||||
throw "Invalid IPv4 address: ${ip}"
|
||||
else
|
||||
let
|
||||
a = toInt (elemAt octets 0);
|
||||
b = toInt (elemAt octets 1);
|
||||
c = toInt (elemAt octets 2);
|
||||
d = toInt (elemAt octets 3);
|
||||
in
|
||||
if a > 255 || b > 255 || c > 255 || d > 255 then
|
||||
throw "Invalid IPv4 octet > 255: ${ip}"
|
||||
else
|
||||
(a * 256 * 256 * 256) + (b * 256 * 256) + (c * 256) + d;
|
||||
|
||||
intToIpv4 = n:
|
||||
let
|
||||
a = n / (256 * 256 * 256);
|
||||
b = builtins.mod (n / (256 * 256)) 256;
|
||||
c = builtins.mod (n / 256) 256;
|
||||
d = builtins.mod n 256;
|
||||
in
|
||||
"${toString a}.${toString b}.${toString c}.${toString d}";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue