Files
vm-images/windows11/seed/Install-VirtIO-Drivers.ps1
guofangandClaude Sonnet 5.5 00695cdddc Install the VirtIO drivers into the base image in audit mode
Add Install-VirtIO-Drivers.ps1, run from Autounattend.xml before sysprep, and
attach the virtio-win ISO (downloaded if missing) during the build.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 22:09:05 +08:00

39 lines
1.6 KiB
PowerShell

# Runs in audit mode, before sysprep: adds the VirtIO drivers from the virtio-win
# ISO to the driver store. The devices are not present during the installation
# (it uses ramfb and e1000e), so pnputil only stages the packages; they survive
# /generalize, and Windows binds them on the first start with virtio devices.
$ErrorActionPreference = 'Stop'
$arch = if ([Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'ARM64' } else { 'amd64' }
$roots = (Get-PSDrive -PSProvider FileSystem).Root
$drivers = @(
@{ Folder = 'NetKVM'; Inf = 'netkvm.inf'; Required = $true },
@{ Folder = 'viogpudo'; Inf = 'viogpudo.inf'; Required = $true },
@{ Folder = 'vioserial'; Inf = 'vioser.inf' },
@{ Folder = 'Balloon'; Inf = 'balloon.inf' },
@{ Folder = 'viorng'; Inf = 'viorng.inf' },
@{ Folder = 'vioinput'; Inf = 'vioinput.inf' }
)
$installed = 0
foreach ($driver in $drivers) {
$inf = $roots |
ForEach-Object { Join-Path $_ "$($driver.Folder)\w11\$arch\$($driver.Inf)" } |
Where-Object { Test-Path -LiteralPath $_ } |
Select-Object -First 1
if (-not $inf) {
if ($driver.Required) {
throw "The $arch $($driver.Folder) driver was not found on the attached media."
}
continue
}
& pnputil.exe /add-driver $inf /install | Out-Host
# 3010 asks for a restart; 259 means that no device uses the driver.
if ($LASTEXITCODE -notin 0, 259, 3010) {
throw "pnputil failed to install $inf (exit code $LASTEXITCODE)."
}
$installed++
}
Write-Host "Added $installed VirtIO $arch driver packages."