generalize: writeFilter, putting UWF's overlay on the data volume
A disk-mode overlay defaults to C:\uwfswap.sys -- on the very volume being protected, which is the opposite of the point. uwfmgr grew a create-swapfile subcommand for exactly this, and it only accepts the call while the filter is off and the overlay is already in disk mode, so the ordering in the generated script is forced rather than stylistic. Configuration is deferred to the target's first boot through RunOnce instead of running in the build. Two reasons: uwfmgr does not exist until the DISM feature has been through a reboot, and the swapfile belongs on the real data volume rather than on the throwaway copy the build attaches. Enabling the filter needs one more restart after that, which the script asks for itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117qMyjpuXsjpVAcpJbFD8g
This commit is contained in:
parent
c213fc4db9
commit
9a8f5da998
1 changed files with 38 additions and 1 deletions
|
|
@ -35,6 +35,10 @@ in
|
|||
# during the build (see extraDisk in the returned set), so this is done and
|
||||
# verified before the image ever reaches a host.
|
||||
dataDisk ? null,
|
||||
# Unified Write Filter: protect a volume by redirecting its writes to a
|
||||
# disk-backed overlay held on another one, e.g.
|
||||
# { protectedVolume = "C:"; swapfileVolume = "D:"; overlaySizeMB = 8192; }
|
||||
writeFilter ? null,
|
||||
# delayOobeRun = true: sysprep only, OOBE + activation on real hardware
|
||||
# delayOobeRun = false: sysprep + OOBE + activation in build VM
|
||||
delayOobeRun ? false,
|
||||
|
|
@ -54,6 +58,30 @@ in
|
|||
stripHash = s: lib.removePrefix "#" s;
|
||||
bgRgb = if bgColor != null then hexToRgbStr (stripHash bgColor) else null;
|
||||
|
||||
uwfProtected = if writeFilter != null then (writeFilter.protectedVolume or "C:") else "C:";
|
||||
uwfSwapVolume = if writeFilter != null then (writeFilter.swapfileVolume or "D:") else "D:";
|
||||
uwfOverlaySizeMB = if writeFilter != null then (writeFilter.overlaySizeMB or 8192) else 8192;
|
||||
|
||||
# Runs from RunOnce on the target's first boot rather than during the build,
|
||||
# for two reasons: enabling the DISM feature needs a reboot before uwfmgr
|
||||
# exists at all, and the overlay swapfile has to be created on the real data
|
||||
# volume rather than on the build's throwaway copy of it.
|
||||
#
|
||||
# Order is forced by uwfmgr: create-swapfile is only accepted while the
|
||||
# filter is off and the overlay is already in disk mode. The default disk
|
||||
# overlay would otherwise sit at C:\uwfswap.sys, on the volume being
|
||||
# protected. Enabling the filter itself only takes effect after a restart.
|
||||
uwfConfigScript = pkgs.writeText "vmix-uwf-config.cmd" ''
|
||||
@echo off
|
||||
uwfmgr.exe overlay set-type disk
|
||||
uwfmgr.exe overlay set-size ${toString uwfOverlaySizeMB}
|
||||
uwfmgr.exe volume create-swapfile ${uwfSwapVolume}
|
||||
uwfmgr.exe volume protect ${uwfProtected}
|
||||
uwfmgr.exe filter enable
|
||||
del /q C:\vmix-uwf-config.cmd 2>nul
|
||||
shutdown /r /t 10 /c "vmix: activating the write filter"
|
||||
'';
|
||||
|
||||
staticDnsList = lib.optionalString (staticIP != null)
|
||||
(lib.concatMapStringsSep "," (s: "'${s}'") staticIP.dns);
|
||||
|
||||
|
|
@ -172,6 +200,14 @@ in
|
|||
powershell -NoProfile -Command "$a = Get-NetAdapter -Physical | Sort-Object ifIndex | Select-Object -First 1; Remove-NetIPAddress -InterfaceIndex $a.ifIndex -AddressFamily IPv4 -Confirm:$false -ErrorAction SilentlyContinue; Remove-NetRoute -InterfaceIndex $a.ifIndex -AddressFamily IPv4 -Confirm:$false -ErrorAction SilentlyContinue; New-NetIPAddress -InterfaceIndex $a.ifIndex -IPAddress '${staticIP.address}' -PrefixLength ${toString staticIP.prefixLength} -DefaultGateway '${staticIP.gateway}' | Out-Null; Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ServerAddresses ${staticDnsList}"
|
||||
''}
|
||||
|
||||
${lib.optionalString (writeFilter != null) ''
|
||||
:: Install the feature now, but defer configuring it: uwfmgr does not exist
|
||||
:: until this has been through a reboot, and the swapfile belongs on the
|
||||
:: real data volume, so RunOnce picks it up on the target's first boot.
|
||||
dism /online /enable-feature /featurename:Client-UnifiedWriteFilter /all /norestart
|
||||
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" /v "vmixUwf" /t REG_SZ /d "C:\vmix-uwf-config.cmd" /f
|
||||
''}
|
||||
|
||||
:: Clean up
|
||||
del /q C:\oobe-unattend.xml 2>nul
|
||||
del /q C:\vmix-audit-script.cmd 2>nul
|
||||
|
|
@ -264,7 +300,8 @@ in {
|
|||
{ source = oobeXml; dest = "/oobe-unattend.xml"; }
|
||||
{ source = postOobeScript; dest = "/post-oobe.cmd"; }
|
||||
{ source = masScript; dest = "/MAS_AIO.cmd"; }
|
||||
] ++ lib.optional (dataDisk != null) { source = initDataDiskScript; dest = "/vmix-init-data-disk.cmd"; };
|
||||
] ++ lib.optional (dataDisk != null) { source = initDataDiskScript; dest = "/vmix-init-data-disk.cmd"; }
|
||||
++ lib.optional (writeFilter != null) { source = uwfConfigScript; dest = "/vmix-uwf-config.cmd"; };
|
||||
# delayOobeRun: sysprep + shutdown — OOBE runs on real hardware
|
||||
# generalize: sysprep + reboot into OOBE in the same QEMU session
|
||||
auditScript = ''
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue