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>
This commit is contained in:
guofangandClaude Sonnet 5.5 committed 2026-11-02 22:09:05 +08:00
1 parent 91ae8cb147
commit 00695cdddc
4 files changed
+61 -6

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
# 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."