# 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."