Compare commits

...

12 Commits

Author SHA1 Message Date
b9e261de6f layers msvc cache: update outputHash 2023-05-25 15:59:36 +02:00
285b33a674 autounattend: fix installation without productKey 2023-05-25 15:59:36 +02:00
9a92143337 autounattend: disable forced password expiry in autounattended install stage already 2023-05-25 15:59:36 +02:00
16e041282f add enableTpm 2023-05-25 15:59:36 +02:00
bc24fd6a2b autounattend: remove more optional bypasses 2023-05-25 15:59:36 +02:00
af9218e652 remove configurable efi flag
Win11 is EFI-only
2023-05-25 15:59:36 +02:00
fe347240f5 enable secureboot 2023-05-25 15:59:36 +02:00
d2d9c7acf6 layers.msvc: update bootstapper sha256 2023-05-25 15:59:36 +02:00
267b3eec44 autounattend: explicitly set the InstallFrom/Path
Apparently required for Win11.
2023-05-25 15:59:36 +02:00
1550caf442 autounattend: add Bypass*Check
At least the TPM2.0 is missing from our qemu run but Windows 11's error
message doesn't reveal what else is missing. It is therefore hard to
estimate the work to do this properly.
2023-05-25 15:59:36 +02:00
598b311215 windowsIso: Win10_21H2 -> Win11_22H2 2023-05-25 15:59:36 +02:00
79c1685f89 virtioWinIso: 0.1.185-2 -> 0.1.229-1 2023-05-23 21:48:23 +02:00
5 changed files with 71 additions and 46 deletions

View File

@ -14,8 +14,8 @@
, services ? {}
, impureShellCommands ? []
, driveLetter ? "D:"
, efi ? true
, imageSelection ? "Windows 10 Pro"
, imageSelection ? "Windows 11 Pro N"
, enableTpm
, ...
}:
@ -58,18 +58,16 @@ let
assertCommand = c: builtins.typeOf c == "string" || builtins.typeOf c == "set" && builtins.hasAttr "Path" c && builtins.hasAttr "Description" c;
commands = builtins.map (x: assert assertCommand x; if builtins.typeOf x == "string" then { Path = x; Description = x; } else x) (
[
{
Path = "powershell.exe Set-ExecutionPolicy -Force Unrestricted";
Description = "Allow unsigned powershell scripts.";
}
]
++ [
{
Path = ''powershell.exe ${driveLetter}\win-bundle-installer.exe'';
Description = "Install any declared packages.";
}
]
[ {
Path = "powershell.exe Set-ExecutionPolicy -Force Unrestricted";
Description = "Allow unsigned powershell scripts.";
} {
Path = ''powershell.exe ${driveLetter}\win-bundle-installer.exe'';
Description = "Install any declared packages.";
} {
Path = "net accounts /maxpwage:unlimited";
Description = "Disable forced password expiry.";
} ]
++ setupCommands
++ [
{
@ -121,8 +119,7 @@ let
# Windows expects a flat list of users while we want to manage them as a set
flatUsers = builtins.attrValues (builtins.mapAttrs (name: s: s // { inherit name; }) users);
diskId =
if efi then 2 else 1;
diskId = 2;
autounattendXML = pkgs.writeText "autounattend.xml" ''
<?xml version="1.0" encoding="utf-8"?>
@ -148,18 +145,26 @@ let
</DriverPaths>
</component>
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
${lib.optionalString (!enableTpm) ''
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>reg add HKLM\System\Setup\LabConfig /v BypassTPMCheck /t reg_dword /d 0x00000001 /f</Path>
</RunSynchronousCommand>
</RunSynchronous>
''}
<DiskConfiguration>
<Disk wcm:action="add">
<CreatePartitions>
<CreatePartition wcm:action="add">
<Order>1</Order>
<Type>${if efi then "EFI" else "Primary"}</Type>
<Type>EFI</Type>
<Size>300</Size>
</CreatePartition>
<CreatePartition wcm:action="add">
<Order>2</Order>
<Type>${if efi then "MSR" else "Primary"}</Type>
<Type>MSR</Type>
<Size>16</Size>
</CreatePartition>
<CreatePartition wcm:action="add">
@ -171,7 +176,7 @@ let
<ModifyPartitions>
<ModifyPartition wcm:action="add">
<Order>1</Order>
<Format>${if efi then "FAT32" else "NTFS"}</Format>
<Format>FAT32</Format>
<Label>System</Label>
<PartitionID>1</PartitionID>
</ModifyPartition>
@ -199,6 +204,7 @@ let
<PartitionID>3</PartitionID>
</InstallTo>
<InstallFrom>
<Path>\install.swm</Path>
<MetaData wcm:action="add">
<Key>/IMAGE/NAME</Key>
<Value>${imageSelection}</Value>
@ -209,7 +215,7 @@ let
<UserData>
<ProductKey>
${if productKey != null then "<Key>${productKey}</Key>" else ""}
${if productKey != null then "<Key>${productKey}</Key>" else "<Key/>"}
<WillShowUI>OnError</WillShowUI>
</ProductKey>
<AcceptEula>true</AcceptEula>
@ -299,7 +305,7 @@ let
</component>
</settings>
<cpi:offlineImage cpi:source="wim:c:/wim/windows-10/install.wim#${imageSelection}" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
<cpi:offlineImage cpi:source="wim:c:/wim/windows-11/install.wim#${imageSelection}" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>
'';

View File

@ -19,9 +19,9 @@ wfvm.makeWindowsImage {
# Custom base iso
# windowsImage = pkgs.requireFile rec {
# name = "Win10_21H1_English_x64.iso";
# sha256 = "1sl51lnx4r6ckh5fii7m2hi15zh8fh7cf7rjgjq9kacg8hwyh4b9";
# message = "Get ${name} from https://www.microsoft.com/en-us/software-download/windows10ISO";
# name = "Win11_22H2_English_x64v1.iso";
# sha256 = "08mbppsm1naf73z8fjyqkf975nbls7xj9n4fq0yp802dv1rz3whd";
# message = "Get disk image ${name} from https://www.microsoft.com/en-us/software-download/windows11/";
# };
# impureShellCommands = [
@ -70,7 +70,7 @@ wfvm.makeWindowsImage {
# License key (required)
# productKey = throw "Search the f* web"
imageSelection = "Windows 10 Pro";
imageSelection = "Windows 11 Pro N";
# Locales

View File

@ -72,7 +72,7 @@ in
bootstrapper = pkgs.fetchurl {
name = "RESTRICTDIST-vs_Community.exe";
url = "https://aka.ms/vs/16/release/vs_community.exe";
sha256 = "sha256-4X8NhdcNyfHkN6eKkNz8Unvv49wRZE4CQ1vf6P1R2ic=";
sha256 = "sha256-l4ZKFZTgHf3BmD0eFWyGwsvb4lqB/LiQYizAABOs3gg=";
};
# This touchy-feely "community" piece of trash seems deliberately crafted to break Wine, so we use the VM to run it.
download-vs = wfvm.utils.wfvm-run {
@ -93,7 +93,7 @@ in
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "0ic3jvslp2y9v8yv9mfr2mafkvj2q5frmcyhmlbxj71si1x3kpag";
outputHash = "sha256-GoOKzln8DXVMx52jWGEjwkOFkpSW+wEffAVmBVugIyk=";
phases = [ "buildPhase" ];
buildInputs = [ download-vs ];

View File

@ -1,23 +1,42 @@
{ pkgs, baseRtc ? "2022-10-10T10:10:10", cores ? "4", qemuMem ? "4G", efi ? true }:
{ pkgs
, baseRtc ? "2022-10-10T10:10:10"
, cores ? "4"
, qemuMem ? "4G"
, enableTpm ? false
}:
rec {
# qemu_test is a smaller closure only building for a single system arch
qemu = pkgs.qemu;
OVMF = pkgs.OVMF.override {
secureBoot = true;
};
mkQemuFlags = extraFlags: [
"-enable-kvm"
"-cpu host"
"-smp ${cores}"
"-m ${qemuMem}"
"-M q35"
"-M q35,smm=on"
"-vga qxl"
"-rtc base=${baseRtc}"
"-device qemu-xhci"
"-device virtio-net-pci,netdev=n1"
] ++ pkgs.lib.optionals efi [
"-bios ${pkgs.OVMF.fd}/FV/OVMF.fd"
"-bios ${OVMF.fd}/FV/OVMF.fd"
] ++ pkgs.lib.optionals enableTpm [
"-chardev" "socket,id=chrtpm,path=tpm.sock"
"-tpmdev" "emulator,id=tpm0,chardev=chrtpm"
"-device" "tpm-tis,tpmdev=tpm0"
] ++ extraFlags;
tpmStartCommands = pkgs.lib.optionalString enableTpm ''
mkdir -p tpmstate
${pkgs.swtpm}/bin/swtpm socket \
--tpmstate dir=tpmstate \
--ctrl type=unixio,path=tpm.sock &
'';
# Pass empty config file to prevent ssh from failing to create ~/.ssh
sshOpts = "-F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o ConnectTimeout=1";
win-exec = pkgs.writeShellScriptBin "win-exec" ''
@ -93,6 +112,7 @@ rec {
]);
in pkgs.writeShellScriptBin "wfvm-run-${name}" ''
set -e -m
${tpmStartCommands}
${qemu}/bin/qemu-system-x86_64 ${pkgs.lib.concatStringsSep " " qemuParams} &
${win-wait}/bin/win-wait

View File

@ -5,15 +5,15 @@
, impureMode ? false
, installCommands ? []
, users ? {}
, enableTpm ? true
# autounattend always installs index 1, so this default is backward-compatible
, imageSelection ? "Windows 10 Pro"
, efi ? true
, imageSelection ? "Windows 11 Pro N"
, ...
}@attrs:
let
lib = pkgs.lib;
utils = import ./utils.nix { inherit pkgs efi; };
utils = import ./utils.nix { inherit pkgs enableTpm; };
inherit (pkgs) guestfs-tools;
# p7zip on >20.03 has known vulns but we have no better option
@ -36,15 +36,14 @@ let
);
windowsIso = if windowsImage != null then windowsImage else pkgs.requireFile rec {
name = "Win10_21H2_English_x64.iso";
sha256 = "0kr3m0bjy086whcbssagsshdxj6lffcz7wmvbh50zhrkxgq3hrbz";
message = "Get ${name} from https://www.microsoft.com/en-us/software-download/windows10ISO";
name = "Win11_22H2_English_x64v1.iso";
sha256 = "08mbppsm1naf73z8fjyqkf975nbls7xj9n4fq0yp802dv1rz3whd";
message = "Get disk image ${name} from https://www.microsoft.com/en-us/software-download/windows11/";
};
# stable as of 2021-04-08
virtioWinIso = pkgs.fetchurl {
url = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.185-2/virtio-win-0.1.185.iso";
sha256 = "11n3kjyawiwacmi3jmfmn311g9xvfn6m0ccdwnjxw1brzb4kqaxg";
url = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.229-1/virtio-win.iso";
sha256 = "1q5vrcd70kya4nhlbpxmj7mwmwra1hm3x7w8rzkawpk06kg0v2n8";
};
openSshServerPackage = pkgs.fetchurl {
@ -54,7 +53,7 @@ let
autounattend = import ./autounattend.nix (
attrs // {
inherit pkgs;
inherit pkgs enableTpm;
users = users // {
wfvm = {
password = "1234";
@ -96,7 +95,7 @@ let
"usb-storage,drive=virtio-win"
# USB boot
"-drive"
"id=win-install,file=${if efi then "usb" else "cd"}image.img,if=none,format=raw,readonly=on,media=${if efi then "disk" else "cdrom"}"
"id=win-install,file=usbimage.img,if=none,format=raw,readonly=on,media=disk"
"-device"
"usb-storage,drive=win-install"
# Output image
@ -125,13 +124,11 @@ let
cp ${autounattend.autounattendXML} win/autounattend.xml
${if efi then ''
virt-make-fs --partition --type=fat win/ usbimage.img
'' else ''
${pkgs.cdrkit}/bin/mkisofs -iso-level 4 -l -R -udf -D -b boot/etfsboot.com -no-emul-boot -boot-load-size 8 -hide boot.catalog -eltorito-alt-boot -o cdimage.img win/
''}
rm -rf win
${utils.tpmStartCommands}
# Qemu requires files to be rw
qemu-img create -f qcow2 c.img ${diskImageSize}
qemu-system-x86_64 ${lib.concatStringsSep " " qemuParams}
@ -159,6 +156,8 @@ let
in ''
set -x
${utils.tpmStartCommands}
# Create an image referencing the previous image in the chain
qemu-img create -F qcow2 -f qcow2 -b ${acc} c.img