How to inject vioscsi driver into Windows install.win & boot.win using linux tools only ?

shodan

Active Member
Sep 1, 2022
222
62
33
Hi,

I am trying to create a windows installer that has the virtio drivers builtin, for fully automatic and unattended installation.

In particular I am trying to inject the driver vioscsi into boot.wim and then install.wim

I can unpack and repack the iso.

I can inject actual driver files into the wim files

I think all that is left is to create the registery keys in the registery hive files,


The keys that need to be created, if I had a "reg add" command

Code:
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi" /v Start /t REG_DWORD /d 0 /f
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi" /v Type /t REG_DWORD /d 1 /f
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi" /v ErrorControl /t REG_DWORD /d 1 /f
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi" /v ImagePath /t REG_EXPAND_SZ /d System32\drivers\vioscsi.sys /f
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi" /v LoadOrderGroup /t REG_SZ /d "SCSI miniport" /f

REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\System\vioscsi" /v EventMessageFile /t REG_EXPAND_SZ /d %SystemRoot%\System32\IoLogMsg.dll /f
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\System\vioscsi" /v TypesSupported /t REG_DWORD /d 7 /f

REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi\Parameters" /v BusType /t REG_DWORD /d 10 /f

REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi\Parameters\PnpInterface" /v 5 /t REG_DWORD /d 1 /f

REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi\Parameters\Interrupt Management\MessageSignaledInterruptProperties" /v MSISupported /t REG_DWORD /d 1 /f
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\vioscsi\Parameters\Interrupt Management\MessageSignaledInterruptProperties" /v MessageNumberLimit /t REG_DWORD /d 258 /f

REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\PnpLockdownFiles\%SystemRoot%/System32/drivers/vioscsi.sys" /v Class /t REG_DWORD /d 5 /f
### REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\PnpLockdownFiles\%SystemRoot%/System32/drivers/vioscsi.sys" /v Owners /t REG_BINARY /d <hex_value_of_inf_file> /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\PnpLockdownFiles\%SystemRoot%/System32/drivers/vioscsi.sys" /v Source /t REG_EXPAND_SZ /d %SystemRoot%\System32\DriverStore\FileRepository\vioscsi.inf_amd64 /f

REG ADD "HKLM\SYSTEM\DriverDatabase" /v OemInfMap /t REG_BINARY /d e0 /f

REG ADD "HKLM\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1004" /v vioscsi.inf /t REG_BINARY /d 02FF0000 /f
REG ADD "HKLM\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1048" /v vioscsi.inf /t REG_BINARY /d 02FF0000 /f

REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v Catalog /t REG_SZ /d vioscsi.cat /f
REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v InfName /t REG_SZ /d vioscsi.inf /f
### REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v OemPath /t REG_SZ /d C:\Users\<username>\Downloads\drivers /f
REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v Provider /t REG_SZ /d "Red Hat, Inc." /f
###REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v SignerName /t REG_SZ /d "<signature_info>" /f
REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v SignerScore /t REG_DWORD /d 218103812 /f
###REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v Version /t REG_BINARY /d <binary_version_data> /f

REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v Class /t REG_SZ /d "SCSIAdapter" /f
REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v ClassGUID /t REG_SZ /d "{4D36E97B-E325-11CE-BFC1-08002BE10318}" /f
REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v DriverVer /t REG_SZ /d "07/15/2024,100.95.104.26200" /f
REG ADD "HKLM\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06" /v Provider /t REG_SZ /d "Red Hat, Inc." /f

REG ADD "HKLM\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00" /v vioscsi.inf /t REG_BINARY /d 01FF0000 /f
REG ADD "HKLM\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1048&SUBSYS_11001AF4&REV_01" /v vioscsi.inf /t REG_BINARY /d 01FF0000 /f


But I would like to create cleaner, more reusable shell function for adding each node/key/values


Here is an untested attempt of ths reg_add shellfunction
Code:
reg_add() {
    local hive_file="$1"
    local registry_path="$2"
    local value_name="$3"
    local value_type="$4"
    local value_data="$5"

    if [[ -z "$hive_file" || -z "$registry_path" || -z "$value_name" || -z "$value_type" || -z "$value_data" ]]; then
        echo "Usage: reg_add /path/to/hive/file \"[registry_path]\" value_name value_type value_data"
        return 1
    fi

    # Convert the registry path for hivexsh
    local hive_path
    hive_path=$(echo "$registry_path" | sed -e 's/^\[//' -e 's/\]$//' -e 's|\\|/|g')

    # Run hivexsh commands
    hivexsh -w "$hive_file" <<EOF
cd $hive_path
setval 1
$value_name
$value_type:$value_data
commit
exit
EOF

    if [[ $? -eq 0 ]]; then
        echo "Successfully added \"$value_name\" to \"$registry_path\" in \"$hive_file\"."
    else
        echo "Failed to add \"$value_name\" to \"$registry_path\" in \"$hive_file\"."
        return 1
    fi
}

So we might then have a single shell function to just add vioscsi to a specified hive

Code:
#!/bin/bash

# Function to add vioscsi-related registry entries to a hive file
add_vioscsi_to_hive() {
    local hive_file="$1"

    if [[ -z "$hive_file" ]]; then
        echo "Usage: add_vioscsi_to_hive /path/to/hive"
        return 1
    fi

    if [[ ! -f "$hive_file" ]]; then
        echo "Hive file '$hive_file' not found."
        return 1
    fi

    echo "Adding vioscsi keys to hive: $hive_file"

    # SYSTEM\CurrentControlSet\Services\vioscsi
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi]" Start dword "00000000"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi]" Type dword "00000001"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi]" ErrorControl dword "00000001"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi]" ImagePath hex(2) "53,79,73,74,65,6d,33,32,5c,64,72,69,76,65,72,73,5c,76,69,6f,73,63,73,69,2e,73,79,73"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi]" LoadOrderGroup string "SCSI miniport"

    # SYSTEM\CurrentControlSet\Services\EventLog\System\vioscsi
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\System\vioscsi]" EventMessageFile hex(2) "25,53,79,73,74,65,6d,52,6f,6f,74,25,5c,53,79,73,74,65,6d,33,32,5c,49,6f,4c,6f,67,4d,73,67,2e,64,6c,6c"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\System\vioscsi]" TypesSupported dword "00000007"

    # SYSTEM\CurrentControlSet\Services\vioscsi\Parameters
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi\Parameters]" BusType dword "0000000A"

    # SYSTEM\CurrentControlSet\Services\vioscsi\Parameters\PnpInterface
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi\Parameters\PnpInterface]" 5 dword "00000001"

    # SYSTEM\CurrentControlSet\Services\vioscsi\Parameters\Interrupt Management\MessageSignaledInterruptProperties
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi\Parameters\Interrupt Management\MessageSignaledInterruptProperties]" MSISupported dword "00000001"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\vioscsi\Parameters\Interrupt Management\MessageSignaledInterruptProperties]" MessageNumberLimit dword "00000102"

    # SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\PnpLockdownFiles
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\PnpLockdownFiles\%SystemRoot%/System32/drivers/vioscsi.sys]" Class dword "00000005"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\PnpLockdownFiles\%SystemRoot%/System32/drivers/vioscsi.sys]" Source hex(2) "25,53,79,73,74,65,6d,52,6f,6f,74,25,5c,53,79,73,74,65,6d,33,32,5c,44,72,69,76,65,72,53,74,6f,72,65,5c,46,69,6c,65,52,65,70,6f,73,69,74,6f,72,79,5c,76,69,6f,73,63,73,69,2e,69,6e,66,5f,61,6d,64,36,34"

    # SYSTEM\DriverDatabase
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase]" OemInfMap hex "e0"

    # SYSTEM\DriverDatabase\DeviceIds
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1004]" vioscsi.inf hex "02FF0000"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1048]" vioscsi.inf hex "02FF0000"

    # SYSTEM\DriverDatabase\DriverPackages
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06]" Catalog string "vioscsi.cat"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06]" InfName string "vioscsi.inf"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06]" Provider string "Red Hat, Inc."
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06]" SignerScore dword "0D000004"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06]" Class string "SCSIAdapter"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06]" ClassGUID string "{4D36E97B-E325-11CE-BFC1-08002BE10318}"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverPackages\vioscsi.inf_amd64_78d23e29bdcf3e06]" DriverVer string "07/15/2024,100.95.104.26200"

    # SYSTEM\DriverDatabase\DeviceIds\PCI with SUBSYS
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00]" vioscsi.inf hex "01FF0000"
    reg_add "$hive_file" "[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1048&SUBSYS_11001AF4&REV_01]" vioscsi.inf hex "01FF0000"

    echo "Finished adding vioscsi keys to hive: $hive_file"
}


I have created a shell function which can inject drivers files to all "image indexes" in the wim file

Code:
inject_filesandfolders_to_all_wim_images iso-master/sources/boot.wim \
virtio-unzipped/vioscsi/w10/amd64/vioscsi.cat /windows/inf \
virtio-unzipped/vioscsi/w10/amd64/vioscsi.inf /windows/inf \
virtio-unzipped/vioscsi/w10/amd64/vioscsi.sys /windows/system32/drivers


Shell function not fully tested
Code:
inject_filesandfolders_to_all_wim_images() { local wim_file="$1"; shift; local dest_folder="/"; local sources=(); for arg in "$@"; do [ -e "$arg" ] && sources+=("$arg") || { [ ${#sources[@]} -gt 0 ] && { dest_folder="$arg"; for source in "${sources[@]}"; do for i in $(seq 1 "$(wimlib-imagex info "$wim_file" | grep -i "Image Count" | awk '{print $NF}')"); do [ -d "$source" ] && echo "Injecting folder $source into image index $i at $dest_folder..." && wimlib-imagex update "$wim_file" $i --command="add $source $dest_folder" || [ -f "$source" ] && echo "Injecting file $source into image index $i at $dest_folder/$(basename "$source")..." && wimlib-imagex update "$wim_file" $i --command="add $source $dest_folder/$(basename "$source")"; done; done; sources=(); }; dest_folder="$arg"; }; done; [ ${#sources[@]} -gt 0 ] && { for source in "${sources[@]}"; do for i in $(seq 1 "$(wimlib-imagex info "$wim_file" | grep -i "Image Count" | awk '{print $NF}')"); do [ -d "$source" ] && echo "Injecting folder $source into image index $i at /..." && wimlib-imagex update "$wim_file" $i --command="add $source /" || [ -f "$source" ] && echo "Injecting file $source into image index $i at /$(basename "$source")..." && wimlib-imagex update "$wim_file" $i --command="add $source /$(basename "$source")"; done; done; }; }


then I repack the iso

create_windows_iso /mnt/iso/template/win10-repack/iso-master /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-2025-1-10.iso

shell function not fully tested
Code:
create_windows_iso() { local src_folder="$1" out_iso="$2"; xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "$out_iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "$src_folder"; }

Code:
get_wim_image_count() { wimlib-imagex info "$1" | grep -i "Image Count" | awk '{print $NF}'; }

mount_wim_image() { local wim_file="$1" index="$2" mount_point="$3/$index"; [ -d "$mount_point" ] && [ "$(ls -A "$mount_point" 2>/dev/null)" ] && { echo "Error: Mount point $mount_point is not empty"; return 1; }; mkdir -p "$mount_point"; wimlib-imagex mount "$wim_file" "$index" "$mount_point" --rw; }

mount_wim_image() { local wim_file="$1" index="$2" mount_point="$3/$index"; [ -d "$mount_point" ] && [ "$(ls -A "$mount_point" 2>/dev/null)" ] && { echo "Error: Mount point $mount_point is not empty"; return 1; }; mkdir -p "$mount_point"; wimlib-imagex mount "$wim_file" "$index" "$mount_point" --rw; }


And now putting it all together

Code:
unpack_iso /mnt/iso/template/iso/virtio-win-0.1.262.iso /mnt/iso/template/win10-repack/virtio-unzipped

unpack_iso /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64.iso /mnt/iso/template/win10-repack/iso-master
inject_filesandfolders_to_all_wim_images iso-master/sources/boot.wim virtio-unzipped/vioscsi/w10/amd64/vioscsi.cat /windows/inf virtio-unzipped/vioscsi/w10/amd64/vioscsi.inf windows/inf virtio-unzipped/vioscsi/w10/amd64/vioscsi.sys /windows/system32/drivers
inject_filesandfolders_to_all_wim_images iso-master/sources/install.wim virtio-unzipped/vioscsi/w10/amd64/vioscsi.cat /windows/inf virtio-unzipped/vioscsi/w10/amd64/vioscsi.inf windows/inf virtio-unzipped/vioscsi/w10/amd64/vioscsi.sys /windows/system32/drivers

for i in $(seq 1 "$(get_wim_image_count iso-master/sources/boot.wim)"); do
   mount_wim_image iso-master/sources/boot.wim $i /mnt/iso/template/win10-repack/wim-mounts/boot/
   add_vioscsi_to_hive wim-mounts/boot/windows/System32/Config/SYSTEM
   unmount_wim_image iso-master/sources/boot.wim $i /mnt/iso/template/win10-repack/wim-mounts/boot/
done

for i in $(seq 1 "$(get_wim_image_count iso-master/sources/install.wim)"); do
   mount_wim_image iso-master/sources/install.wim $i /mnt/iso/template/win10-repack/wim-mounts/install/
   add_vioscsi_to_hive wim-mounts/install/windows/System32/Config/SYSTEM
   unmount_wim_image iso-master/sources/install.wim $i /mnt/iso/template/win10-repack/wim-mounts/install/
done

create_windows_iso /mnt/iso/template/win10-repack/iso-master /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-2025-1-10.iso
 
I was curious, why did distrobuilder windows repack did not use this special folder

https://github.com/lxc/distrobuilder/tree/main/windows

And I now realize, they skip the installer entirely.

We just create the filesystems and unpack install.wim directly into it, skipping the installer, at least the first step !

I did want a win10 iso that can cd/usb/net-boot and install windows to a baremetal/iscsi/VM but now I think for VMs it might be faster to skip portions of the installer if possible.


I also wish to incorporate
Microsoft-Windows-EMS-SAC-Desktop-Tools-FoD-Package~31bf3856ad364e35~amd64~~.cab

So that I can send terminal commands over serial to the running windows instance
 
Last edited:
Maybe sysprep later, but for now I want a one-click "original iso to fully automated, finished install" function.
Maybe I can automate this sysprep and then clone the WIMs.

Just gave a try to the $WinPeDriver$ method

Here is how that went

Code:
check_dependencies() { for cmd in 7zz xorriso wimlib-imagex dumpet isoinfo libwin-hivex-perl; do which "$cmd" >/dev/null 2>&1 || { echo "Installing missing package: $cmd"; apt-get install -qq -y 7zip xorriso wimtools libwim-doc libhivex-bin; }; done; }
create_windows_repack_folder() { [ -z "$1" ] && echo "Usage: create_windows_repack_folder /path/to/base/folder" && return 1; base="$1"; for folder in iso-master wim-mounts unattend-file virtio-unzipped; do mkdir -p "$base/$folder" || { echo "Failed to create $base/$folder"; return 1; }; done; echo "Folders created successfully in $base"; }
unpack_iso() { 7zz x "$1" -o"$2"; }
copy_virtio_drivers_to_winpedriver() { [ "$#" -lt 2 ] && { echo "Usage: copy_virtio_drivers_to_winpedriver <base_folder> <driver_name1> [driver_name2 ...]"; return 1; }; local base_folder="$1"; shift; local virtio_source="$base_folder/virtio-unzipped" dest_base="$base_folder/iso-master/\$WinPeDriver\$"; for driver in "$@"; do source_path="$virtio_source/$driver/w10/amd64"; dest_path="$dest_base/$driver/"; [ -d "$source_path" ] && { mkdir -p "$dest_path"; cp -r "$source_path"/* "$dest_path"; echo "Copied $source_path to $dest_path"; } || echo "Source path $source_path does not exist, skipping $driver"; done; }
create_windows_iso() { local src_folder="$1" out_iso="$2"; xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "$out_iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "$src_folder"; }
create_win10_vm() { local VM_ID="$1" VM_NAME="$2" VM_MEMORY="${3:-8000}" VM_CORES="${4:-8}" VM_DISK_SIZE="${5:-32}" VM_TEMPLATE_FILENAME="${6:-Win10_22H2_EnglishInternational_x64_unattended-latest.iso}" VM_VIRTIO_FILENAME="${7:-virtio-win-0.1.262.iso}" VM_OS_TYPE="win10" VM_AGENT="1" VM_SOCKETS="1" VM_STORAGE_DISK="local-lvm" VM_STORAGE_ISO="lvm-iso" VM_NETWORK_BRIDGE="vmbr0" VM_EFIDISK_SIZE="4M" VM_MAC_ADDRESS=$(printf '52:54:00:%02X:%02X:%02X' $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256))); local CMD="qm create \"$VM_ID\" --name \"$VM_NAME\" --memory \"$VM_MEMORY\" --sockets \"$VM_SOCKETS\" --cores \"$VM_CORES\" --numa 0 --bios ovmf --machine pc-q35-7.1 --efidisk0 \"$VM_STORAGE_DISK:0,size=$VM_EFIDISK_SIZE,efitype=4m,pre-enrolled-keys=1\" --scsi0 \"$VM_STORAGE_DISK:$VM_DISK_SIZE,backup=0,cache=writeback,discard=on,iothread=1\" --ide0 \"$VM_STORAGE_ISO:iso/$VM_VIRTIO_FILENAME,media=cdrom\" --ide2 \"$VM_STORAGE_ISO:iso/$VM_TEMPLATE_FILENAME,media=cdrom\" --net0 \"e1000=$VM_MAC_ADDRESS,bridge=$VM_NETWORK_BRIDGE\" --scsihw virtio-scsi-single --boot \"order=scsi0\" --bootdisk \"scsi0\" --agent \"enabled=$VM_AGENT\" --ostype \"$VM_OS_TYPE\""; [ -n "$VM_UUID" ] && CMD+=" --smbios1 uuid=$VM_UUID"; [ -n "$VM_VMGENID" ] && CMD+=" --vmgenid $VM_VMGENID"; echo "Executing: $CMD"; eval "$CMD"; }

check_dependencies
create_windows_repack_folder /mnt/iso/template/win10-repack
unpack_iso /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64.iso /mnt/iso/template/win10-repack/iso-master
unpack_iso /mnt/iso/template/iso/virtio-win-0.1.262.iso /mnt/iso/template/win10-repack/virtio-unzipped
copy_virtio_drivers_to_winpedriver /mnt/iso/template/win10-repack viofs vioserial viorng qxldod viogpudo NetKVM pvpanic vioinput fwcfg Balloon viostor sriov vioscsi qemupciserial viomem
create_windows_iso /mnt/iso/template/win10-repack/iso-master /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso
create_win10_vm 1770 wintest1


Problems with that are
1. boot order missing ide2 to boot
2. Still need to "press a key to enter setup"
3. drivers aren't loaded

1737847977841.png

Why aren't the drivers loading ?

It appears the "$" characters have been replaced with "_" characters

1737848037795.png

Looking at the actual folder structure in the folder iso-master

Code:
root@proxmox:/mnt/iso/template/win10-repack/iso-master# ls
'$WinPeDriver$'   autorun.inf   boot   bootmgr   bootmgr.efi   efi   setup.exe   sources   support
root@proxmox:/mnt/iso/template/win10-repack/iso-master# find "\$WinPeDriver\$"/
$WinPeDriver$/
$WinPeDriver$/viomem
$WinPeDriver$/viomem/viomem.pdb
$WinPeDriver$/viomem/viomem.sys
$WinPeDriver$/viomem/viomem.inf
$WinPeDriver$/viomem/viomem.cat
$WinPeDriver$/qemupciserial
$WinPeDriver$/qemupciserial/qemupciserial.cat
$WinPeDriver$/qemupciserial/qemupciserial.inf
$WinPeDriver$/vioscsi
$WinPeDriver$/vioscsi/vioscsi.sys
$WinPeDriver$/vioscsi/vioscsi.cat
....

Looks good here, but strangely, the iso is wrong ??

So I went and mounted the iso file

Code:
root@proxmox:/mnt/iso/template/iso# mount -o loop /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso /mnt/test
mount: /mnt/test: WARNING: source write-protected, mounted read-only.
root@proxmox:/mnt/iso/template/iso# cd /mnt/test
root@proxmox:/mnt/test# ls
'$WinPeDriver$'   autorun.inf   boot   bootmgr   bootmgr.efi   efi   setup.exe   sources   support
root@proxmox:/mnt/test# find "\$WinPeDriver\$"/
$WinPeDriver$/
$WinPeDriver$/Balloon
$WinPeDriver$/Balloon/balloon.cat
$WinPeDriver$/Balloon/balloon.inf
$WinPeDriver$/Balloon/balloon.pdb
$WinPeDriver$/Balloon/balloon.sys
$WinPeDriver$/Balloon/blnsvr.exe
$WinPeDriver$/Balloon/blnsvr.pdb
$WinPeDriver$/fwcfg
$WinPeDriver$/fwcfg/fwcfg.cat
$WinPeDriver$/fwcfg/fwcfg.inf
$WinPeDriver$/fwcfg/fwcfg.pdb
$WinPeDriver$/fwcfg/fwcfg.sys
$WinPeDriver$/NetKVM

Strangely the iso is also fine, I wonder why ...


1737848483255.png
 
put only minimal drivers in $WinpeDriver$
netkvm and vioscsi
Then install with FirstLogonCommands of Autounattend.xml :
qemu drivers (win-gt.msi) and qemu agent (qemu-ga.msi)

edit : seems missing option ( joliet or udf version) for iso creation to fix missing $
Microsoft cdimage.exe use :
-u2 : Produces an ISO image that has only the Universal Disk Format (UDF) file system on it.

-udfver102 : Writes UDF revision 1.02 (Supported: Windows 98 and later)
 
Last edited:
Hi,

My windows iso was created with the following command

Code:
xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "/mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "/mnt/iso/template/win10-repack/iso-master"

And one weird thing is that the ISO does contain the "$" characters in the file...

Example
Code:
root@proxmox:/mnt/iso/template# 7zz l iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso  | grep -i winpe
2025-01-25 18:12:02 D....                            $WinPeDriver$
2025-01-25 18:12:02 D....                            $WinPeDriver$/Balloon
2025-01-25 18:12:02 .....        12266        12266  $WinPeDriver$/Balloon/balloon.cat
2025-01-25 18:12:02 .....         2427         2427  $WinPeDriver$/Balloon/balloon.inf
2025-01-25 18:12:02 .....       978944       978944  $WinPeDriver$/Balloon/balloon.pdb
2025-01-25 18:12:02 .....        63640        63640  $WinPeDriver$/Balloon/balloon.sys
2025-01-25 18:12:02 .....       185640       185640  $WinPeDriver$/Balloon/blnsvr.exe
2025-01-25 18:12:02 .....      6574080      6574080  $WinPeDriver$/Balloon/blnsvr.pdb
2025-01-25 18:12:02 D....                            $WinPeDriver$/fwcfg
2025-01-25 18:12:02 .....        11785        11785  $WinPeDriver$/fwcfg/fwcfg.cat
2025-01-25 18:12:02 .....         1785         1785  $WinPeDriver$/fwcfg/fwcfg.inf
2025-01-25 18:12:02 .....       708608       708608  $WinPeDriver$/fwcfg/fwcfg.pdb
2025-01-25 18:12:02 .....        28208        28208  $WinPeDriver$/fwcfg/fwcfg.sys
2025-01-25 18:12:02 D....                            $WinPeDriver$/NetKVM
2025-01-25 18:12:02 .....        12681        12681  $WinPeDriver$/NetKVM/netkvm.cat
2025-01-25 18:12:02 .....        17174        17174  $WinPeDriver$/NetKVM/netkvm.inf
2025-01-25 18:12:02 .....      1789952      1789952  $WinPeDriver$/NetKVM/netkvm.pdb
2025-01-25 18:12:02 .....       187544       187544  $WinPeDriver$/NetKVM/netkvm.sys
2025-01-25 18:12:02 .....      1024296      1024296  $WinPeDriver$/NetKVM/netkvmco.exe
2025-01-25 18:12:02 .....     12767232     12767232  $WinPeDriver$/NetKVM/netkvmco.pdb
2025-01-25 18:12:02 .....       190616       190616  $WinPeDriver$/NetKVM/netkvmp.exe
2025-01-25 18:12:02 .....      3690496      3690496  $WinPeDriver$/NetKVM/netkvmp.pdb
2025-01-25 18:12:02 .....         6283         6283  $WinPeDriver$/NetKVM/Readme.md
2025-01-25 18:12:02 D....                            $WinPeDriver$/pvpanic
2025-01-25 18:12:02 .....        11806        11806  $WinPeDriver$/pvpanic/pvpanic.cat
2025-01-25 18:12:02 .....         1700         1700  $WinPeDriver$/pvpanic/pvpanic.inf

I tried changing -iso-level 3 to -iso-level 4
This had no effect

Here is some information about this iso

Code:
root@proxmox:/mnt/iso/template# isoinfo -i iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso -d -J -l
CD-ROM is in ISO 9660 format
System id:
Volume id: CCCOMA_X64FRE_EN-GB_DV9
Volume set id:
Publisher id:
Data preparer id: XORRISO-1.5.4 2021.01.30.150001, LIBISOBURN-1.5.4, LIBISOFS-1.5.4, LIBBURN-1.5.4
Application id:
Copyright File id:
Abstract File id:
Bibliographic File id:
Volume set size is: 1
Volume set sequence number is: 1
Logical block size is: 2048
Volume size is: 3139701
El Torito VD version 1 found, boot catalog is in sector 320
CD-ROM uses ISO 9660:1999 relaxed format
isoinfo: Unable to find Joliet SVD

root@proxmox:/mnt/iso/template# dumpet -i iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso
Validation Entry:
        Header Indicator: 0x01 (Validation Entry)
        PlatformId: 0x00 (80x86)
        ID: ""
        Checksum: 0x55aa
        Key bytes: 0x55aa
Boot Catalog Default Entry:
        Entry is bootable
        Boot Media emulation type: no emulation
        Media load segment: 0x0 (0000:7c00)
        System type: 0 (0x00)
        Load Sectors: 8 (0x0008)
        Load LBA: 321 (0x00000141)
Section Header Entry:
        Header Indicator: 0x91 (Final Section Header Entry)
        PlatformId: 0xef (EFI)
        Section Entries: 1
        ID: ""
Boot Catalog Section Entry:
        Entry is bootable
        Boot Media emulation type: no emulation
        Media load address: 0 (0x0000)
        System type: 0 (0x00)
        Load Sectors: 2880 (0x0b40)
        Load LBA: 323 (0x00000143)

As you mention, there is something wrong with the joliet specification

According to chatgpt, the following command line parameters should enable this

Code:
-joliet on -joliet-long

Chatgpt earlier suggested to use the following command line parameters instead

Code:
-allow-lowercase -allow-multidot -relaxed-filenames


I will now test all of these suggestions


Code:
root@proxmox:/mnt/iso/template# create_windows_iso() { local src_folder="$1" out_iso="$2"; xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -relaxed-filenames -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "$out_iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "$src_folder"; }
root@proxmox:/mnt/iso/template# create_windows_iso /mnt/iso/template/win10-repack/iso-master /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso                                                                      xorriso 1.5.4 : RockRidge filesystem manipulator, libburnia project.

Drive current: -outdev 'stdio:/mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso'
Media current: stdio file, overwriteable
Media status : is blank
Media summary: 0 sessions, 0 data blocks, 0 data, 41.2g free
xorriso : WARNING : -volid text does not comply to ISO 9660 / ECMA 119 rules
Added to ISO image: directory '/'='/mnt/iso/template/win10-repack/iso-master'
xorriso : UPDATE :    1082 files added in 1 seconds
xorriso : UPDATE :    1082 files added in 1 seconds
xorriso : UPDATE :  1.77% done
xorriso : UPDATE : Thank you for being patient. Working since 35 seconds.
ISO image produced: 3139571 sectors
Written to medium : 3139571 sectors at LBA 0
Writing to 'stdio:/mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso' completed successfully.
root@proxmox:/mnt/iso/template# isoinfo -i iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso -d -J -l                                                                                                                                 CD-ROM is in ISO 9660 format
System id:
Volume id: CCCOMA_X64FRE_EN-GB_DV9
Volume set id:
Publisher id:
Data preparer id: XORRISO-1.5.4 2021.01.30.150001, LIBISOBURN-1.5.4, LIBISOFS-1.5.4, LIBBURN-1.5.4
Application id:
Copyright File id:
Abstract File id:
Bibliographic File id:
Volume set size is: 1
Volume set sequence number is: 1
Logical block size is: 2048
Volume size is: 3139571
El Torito VD version 1 found, boot catalog is in sector 190
isoinfo: Unable to find Joliet SVD
root@proxmox:/mnt/iso/template# dumpet -i iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso                                                                                                                                           Validation Entry:
        Header Indicator: 0x01 (Validation Entry)
        PlatformId: 0x00 (80x86)
        ID: ""
        Checksum: 0x55aa
        Key bytes: 0x55aa
Boot Catalog Default Entry:
        Entry is bootable
        Boot Media emulation type: no emulation
        Media load segment: 0x0 (0000:7c00)
        System type: 0 (0x00)
        Load Sectors: 8 (0x0008)
        Load LBA: 191 (0x000000bf)
Section Header Entry:
        Header Indicator: 0x91 (Final Section Header Entry)
        PlatformId: 0xef (EFI)
        Section Entries: 1
        ID: ""
Boot Catalog Section Entry:
        Entry is bootable
        Boot Media emulation type: no emulation
        Media load address: 0 (0x0000)
        System type: 0 (0x00)
        Load Sectors: 2880 (0x0b40)
        Load LBA: 193 (0x000000c1)

I also tried -joliet on -joliet-long
The correct parameters were in fact
"-joliet -joliet-long"


Code:
root@proxmox:/mnt/iso/template# create_windows_iso() { local src_folder="$1" out_iso="$2"; xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -joliet -joliet-long -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "$out_iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "$src_folder"; }
root@proxmox:/mnt/iso/template# create_windows_iso /mnt/iso/template/win10-repack/iso-master /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso                                                                      xorriso 1.5.4 : RockRidge filesystem manipulator, libburnia project.

Drive current: -outdev 'stdio:/mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso'
Media current: stdio file, overwriteable
Media status : is blank
Media summary: 0 sessions, 0 data blocks, 0 data, 41.2g free
xorriso : WARNING : -volid text is too long for Joliet (23 > 16)
xorriso : WARNING : -volid text does not comply to ISO 9660 / ECMA 119 rules
Added to ISO image: directory '/'='/mnt/iso/template/win10-repack/iso-master'
xorriso : UPDATE :    1082 files added in 1 seconds
xorriso : UPDATE :    1082 files added in 1 seconds
xorriso : UPDATE :  1.43% done
xorriso : UPDATE : Thank you for being patient. Working since 27 seconds.
ISO image produced: 3139713 sectors
Written to medium : 3139713 sectors at LBA 0
Writing to 'stdio:/mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso' completed successfully.

root@proxmox:/mnt/iso/template# isoinfo -i iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso -d -J -l                                                                                                                                 CD-ROM is in ISO 9660 format
System id:
Volume id: CCCOMA_X64FRE_EN-GB_DV9
Volume set id:
Publisher id:
Data preparer id: XORRISO-1.5.4 2021.01.30.150001, LIBISOBURN-1.5.4, LIBISOFS-1.5.4, LIBBURN-1.5.4
Application id:
Copyright File id:
Abstract File id:
Bibliographic File id:
Volume set size is: 1
Volume set sequence number is: 1
Logical block size is: 2048
Volume size is: 3139713
El Torito VD version 1 found, boot catalog is in sector 332
Joliet with UCS level 3 found
Rock Ridge signatures version 1 found
Eltorito validation header:
    Hid 1
    Arch 0 (x86)
    ID ''
    Key 55 AA
    Eltorito defaultboot header:
        Bootid 88 (bootable)
        Boot media 0 (No Emulation Boot)
        Load segment 0
        Sys type 0
        Nsect 8
        Bootoff 14D 333
root@proxmox:/mnt/iso/template# dumpet -i iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso                                                                                                                                           Validation Entry:
        Header Indicator: 0x01 (Validation Entry)
        PlatformId: 0x00 (80x86)
        ID: ""
        Checksum: 0x55aa
        Key bytes: 0x55aa
Boot Catalog Default Entry:
        Entry is bootable
        Boot Media emulation type: no emulation
        Media load segment: 0x0 (0000:7c00)
        System type: 0 (0x00)
        Load Sectors: 8 (0x0008)
        Load LBA: 333 (0x0000014d)
Section Header Entry:
        Header Indicator: 0x91 (Final Section Header Entry)
        PlatformId: 0xef (EFI)
        Section Entries: 1
        ID: ""
Boot Catalog Section Entry:
        Entry is bootable
        Boot Media emulation type: no emulation
        Media load address: 0 (0x0000)
        System type: 0 (0x00)
        Load Sectors: 2880 (0x0b40)
        Load LBA: 335 (0x0000014f)
root@proxmox:/mnt/iso/template#

It turns out that both approaches work, as far as the folder "$WinPeDriver$" naming is concerned

1738350687532.png


Conclusion

Both approaches work

With -relaxed-filenames

Code:
xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -relaxed-filenames -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "/mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "/mnt/iso/template/win10-repack/iso-master"

and with joliet enabled

Code:
xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -joliet -joliet-long -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "/mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "/mnt/iso/template/win10-repack/iso-master"

Here are either shell functions

With -relaxed-filenames
Code:
create_windows_iso() { local src_folder="$1" out_iso="$2"; xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -relaxed-filenames -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "$out_iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "$src_folder"; }

and with joliet enabled
Code:
create_windows_iso() { local src_folder="$1" out_iso="$2"; xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -joliet -joliet-long -volid "CCCOMA_X64FRE_EN-GB_DV9" -output "$out_iso" -eltorito-boot boot/etfsboot.com -eltorito-catalog boot/boot.cat -no-emul-boot -boot-load-size 8 -boot-info-table -eltorito-alt-boot -e efi/microsoft/boot/efisys.bin -no-emul-boot -boot-load-size 1 -isohybrid-gpt-basdat "$src_folder"; }

and you call these as follows
Code:
create_windows_iso /mnt/iso/template/win10-repack/iso-master /mnt/iso/template/iso/Win10_22H2_EnglishInternational_x64_unattended-latest.iso
 
Last edited: