added support for viostor.inf (VirtIO Block)

script now supports using vioscsi.inf and viostor.inf
removed a few manual registry changes on Windows versions 2016 and older
This commit is contained in:
frankbartkewitz
2026-06-30 20:00:53 +02:00
parent 41e2060f84
commit 55bbc8eb58
3 changed files with 277 additions and 194 deletions
Regular → Executable
View File
Regular → Executable
+23 -17
View File
@@ -1,34 +1,40 @@
Purpose of this script
* make Windows load the VirtIO SCSI pass-through driver on boot without reboot or external programs
* make Windows load the VirtIO SCSI and/or Block driver on boot without reboot or external programs
Prerequisites
* VirtIO SCSI driver (vioscsi) must be installed **OR** path to the INF-File must be given as argument to the script
* Windows 7/8 or Windows Server 2008 or newer versions
* VirtIO SCSI driver (vioscsi) must be installed OR path to the INF file must be given as argument
* VirtIO Block driver (viostor) must be installed OR path to the INF file must be given as argument
* Windows 7/8 or Windows Server 2008
Remarks
* On Windows before Windows Server 2022 and Windows 10 2004 the software device created by the script will not be removed automatically, but this can be done via device manager. It can also be left there, no harm in that.
* You should have a backup of your system.
* This script was tested
* on Windows Server 2025 Standard Edition (24H2)
* on Windows Server 2022 Datacenter Edition (21H2)
* with virtio drivers version .266, .271, .285
* This script was tested only
** on Windows Server 2025 Standard Edition (24H2)
** on Windows Server 2022 Datacenter Edition (21H2)
** with virtio drivers version .266 .271 .285
** on Windows Server 2016 Standard Edition
** with virtio drivers version .271
* nearly all code in here was written by AI
How to use
either
* install the ``vioscsi.inf`` before **OR**
* tell the script to do it by ``-InfPath`` parameter **OR**
* use ``virtio-win-guest-tools.exe /S`` to install it
* install the vioscsi.inf/viostor.inf before OR
* tell the script to do it by -ScsiInfPath and/or -BlockInfPath parameter OR
* use virtio-win-guest-tools.exe /S to install it
depending on the set security policy it might be required to run the script via
``PowerShell /ExecutionPolicy Bypass /File <path-to-this-script-file> [-InfPath <path-to-vioscsi.inf>]``
PowerShell /ExecutionPolicy Bypass /File <path-to-this-script-file> [-Driver <scsi|block|both>] [-ScsiInfPath <path>] [-BlockInfPath <path>]
Driver options:
- scsi (default) - Install VirtIO SCSI driver only
- block - Install VirtIO Block driver only
- both - Install both drivers
How does the script work?
* install the vioscsi driver, if requested
* install the driver(s), if requested
* create a software based device via Win32-API
* add some registry settings
* use ``pnputil`` to install the driver for this device
* use ``pnputil`` to remove the device
* use pnputil to install the driver for this device
* use pnputil to remove the device
The driver-to-device assignment marks the driver for being loaded on boot.
Now the Windows is ready for migration to a VirtIO based SCSI disk.
Now the Windows is ready for migration to a VirtIO based SCSI or Block disk.
Executable → Regular
+254 -177
View File
@@ -1,40 +1,50 @@
# Purpose of this script
# * make Windows load the VirtIO SCSI pass-through driver on boot without reboot or external programs
#
# Prerequisites
# * VirtIO SCSI driver (vioscsi) must be installed OR path to the INF-File must be given as argument to the script
# * Windows 7/8 or Windows Server 2008 or newer
#
# Remarks
# * On Windows before Windows Server 2022 and Windows 10 2004 the software device created by the script will not be removed automatically, but this can be done via device manager. It can also be left there, no harm in that.
# * You should have a backup of your system.
# * This script was tested only
# ** on Windows Server 2025 Standard Edition (24H2)
# ** on Windows Server 2022 Datacenter Edition (21H2)
# ** with virtio drivers version .266, .271, .285
# * nearly all code in here was written by AI
#
# How to use
# either
# * install the vioscsi.inf before OR
# * tell the script to do it by -InfPath parameter OR
# * use virtio-win-guest-tools.exe /S to install it
# depending on the set security policy it might be required to run the script via
# PowerShell /ExecutionPolicy Bypass /File <path-to-this-script-file> [-InfPath <path-to-vioscsi.inf>]
#
# How does the script work?
# * install the vioscsi driver, if requested
# * create a software based device via Win32-API
# * add some registry settings
# * use pnputil to install the driver for this device
# * use pnputil to remove the device
# The driver-to-device assignment marks the driver for being loaded on boot.
# Now the Windows is ready for migration to a VirtIO based SCSI disk.
# Purpose of this script
# * make Windows load the VirtIO SCSI and/or Block driver on boot without reboot or external programs
#
# Prerequisites
# * VirtIO SCSI driver (vioscsi) must be installed OR path to the INF file must be given as argument
# * VirtIO Block driver (viostor) must be installed OR path to the INF file must be given as argument
# * Windows 7/8 or Windows Server 2008
#
# Remarks
# * On Windows before Windows Server 2022 and Windows 10 2004 the software device created by the script will not be removed automatically, but this can be done via device manager. It can also be left there, no harm in that.
# * You should have a backup of your system.
# * This script was tested only
# ** on Windows Server 2025 Standard Edition (24H2)
# ** on Windows Server 2022 Datacenter Edition (21H2)
# ** with virtio drivers version .266
# * nearly all code in here was written by AI
#
# How to use
# either
# * install the vioscsi.inf/viostor.inf before OR
# * tell the script to do it by -ScsiInfPath and/or -BlockInfPath parameter OR
# * use virtio-win-guest-tools.exe /S to install it
# depending on the set security policy it might be required to run the script via
# PowerShell /ExecutionPolicy Bypass /File <path-to-this-script-file> [-Driver <scsi|block|both>] [-ScsiInfPath <path>] [-BlockInfPath <path>]
#
# Driver options:
# - scsi (default) - Install VirtIO SCSI driver only
# - block - Install VirtIO Block driver only (requires -BlockInfPath)
# - both - Install both drivers (requires -ScsiInfPath and -BlockInfPath)
#
# How does the script work?
# * install the driver(s), if requested
# * create a software based device via Win32-API
# * add some registry settings
# * use pnputil to install the driver for this device
# * use pnputil to remove the device
# The driver-to-device assignment marks the driver for being loaded on boot.
# Now the Windows is ready for migration to a VirtIO based SCSI or Block disk.
# ==== PARAMETER ====
param(
[string]$InfPath = "" # Optional: Path to vioscsi.inf file
)
# ==== PARAMETER ====
param(
[string]$InfPath = "",
[ValidateSet("scsi", "block", "both")]
[string]$Driver = "scsi",
[string]$ScsiInfPath = "",
[string]$BlockInfPath = ""
)
$source = @"
using System;
@@ -107,7 +117,7 @@ public class DeviceInstaller
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData);
public static void CreateSoftwareDeviceWithHardwareId(string deviceId, string classGuidStr, string hardwareId)
public static void CreateSoftwareDeviceWithHardwareId(string deviceId, string classGuidStr, string hardwareId, string deviceDescription)
{
Guid classGuid = new Guid(classGuidStr);
IntPtr devInfoSet = SetupDiCreateDeviceInfoList(ref classGuid, IntPtr.Zero);
@@ -124,7 +134,7 @@ public class DeviceInstaller
devInfoData.cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
devInfoData.ClassGuid = classGuid;
if (!SetupDiCreateDeviceInfo(devInfoSet, deviceId, ref classGuid, "VirtIO SCSI Controller", IntPtr.Zero, DICD_GENERATE_ID, ref devInfoData))
if (!SetupDiCreateDeviceInfo(devInfoSet, deviceId, ref classGuid, deviceDescription, IntPtr.Zero, DICD_GENERATE_ID, ref devInfoData))
{
int error = Marshal.GetLastWin32Error();
throw new Exception("SetupDiCreateDeviceInfo failed with error " + error);
@@ -208,78 +218,122 @@ if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdent
exit 1
}
# Add compiled class
Add-Type -TypeDefinition $source
# Add compiled class
Add-Type -TypeDefinition $source
$driverConfigs = @{
"vioscsi" = @{
Name = "vioscsi"
HardwareId = "PCI\VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00"
HardwareIdShort = "PCI\VEN_1AF4&DEV_1004"
RegistryPath = "HKLM:\SOFTWARE\RedHat\Virtio-Win\Components\vioscsi"
InfFile = "vioscsi.inf"
DeviceDesc = "VirtIO SCSI Controller"
DriverDesc = "Red Hat VirtIO SCSI pass-through controller"
# InfSection is recorded only in the redundant Control\Class entry below; pnputil
# writes the authoritative one, so this value is cosmetic. Confirm against the
# actual INF (DDInstall section) if you ever rely on it.
InfSection = "scsi_inst"
ClassGuid = "{4d36e97b-e325-11ce-bfc1-08002be10318}"
InfPathParam = $ScsiInfPath
}
"viostor" = @{
Name = "viostor"
HardwareId = "PCI\VEN_1AF4&DEV_1001"
HardwareIdShort = "PCI\VEN_1AF4&DEV_1001"
RegistryPath = "HKLM:\SOFTWARE\RedHat\Virtio-Win\Components\viostor"
InfFile = "viostor.inf"
DeviceDesc = "VirtIO Block Controller"
DriverDesc = "Red Hat VirtIO SCSI controller"
InfSection = "rhelscsi_inst"
ClassGuid = "{4d36e97b-e325-11ce-bfc1-08002be10318}"
InfPathParam = $BlockInfPath
}
}
$driversToProcess = @()
switch ($Driver) {
"scsi" { $driversToProcess += $driverConfigs["vioscsi"] }
"block" { $driversToProcess += $driverConfigs["viostor"] }
"both" {
$driversToProcess += $driverConfigs["vioscsi"]
$driversToProcess += $driverConfigs["viostor"]
}
}
foreach ($drv in $driversToProcess) {
$deviceId = $drv.Name
$classGuid = $drv.ClassGuid
$hardwareId = $drv.HardwareId
$virtioBasePath = $drv.RegistryPath
$currentInfPath = if ($drv.InfPathParam) { $drv.InfPathParam } else { $InfPath }
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "Processing driver: $($drv.Name)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
$deviceId = "vioscsi"
$classGuid = "{4d36e97b-e325-11ce-bfc1-08002be10318}"
$hardwareId = "PCI\VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00"
# Registry path for VirtIO installation
$virtioBasePath = "HKLM:\SOFTWARE\RedHat\Virtio-Win\Components\vioscsi"
try {
# OPTIONAL: Install INF driver first if path provided
if ($InfPath -and (Test-Path $InfPath)) {
Write-Host "Installing INF driver from provided path..." -ForegroundColor Yellow
Write-Host "INF Path: $InfPath" -ForegroundColor Cyan
# Check Windows version for correct pnputil syntax
$osVersion = [System.Environment]::OSVersion.Version
$buildNumber = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").CurrentBuildNumber
$useNewSyntax = ($osVersion.Major -gt 10) -or
(($osVersion.Major -eq 10) -and ([int]$buildNumber -ge 14393)) -or
(($osVersion.Major -eq 6) -and ($osVersion.Minor -ge 3))
try {
if ($useNewSyntax) {
Write-Host "Executing: pnputil /add-driver `"$InfPath`" /install" -ForegroundColor Gray
& pnputil /add-driver "$InfPath" /install
} else {
Write-Host "Executing: pnputil -a -i `"$InfPath`"" -ForegroundColor Gray
& pnputil -a -i "$InfPath"
}
if ($LASTEXITCODE -eq 0) {
Write-Host "INF driver installed successfully!" -ForegroundColor Green
} else {
Write-Host "INF installation completed with exit code $LASTEXITCODE" -ForegroundColor Yellow
}
} catch {
Write-Host "INF installation failed: $($_.Exception.Message)" -ForegroundColor Red
throw "Cannot continue without driver installation"
}
Write-Host "Waiting for driver registration..." -ForegroundColor Cyan
Start-Sleep -Seconds 2
} elseif ($InfPath) {
throw "Provided INF path does not exist: $InfPath"
}
# Check if VirtIO registry entries exist
if (-not (Test-Path $virtioBasePath)) {
Write-Host "VirtIO guest tools registry not found, searching DriverDatabase..." -ForegroundColor Yellow
# Fallback: Search in DriverDatabase for vioscsi.inf
$driverDbPath = "HKLM:\SYSTEM\DriverDatabase\DriverPackages"
$vioscsiDrivers = Get-ChildItem $driverDbPath | Where-Object { $_.Name -like "*vioscsi.inf*" }
if ($vioscsiDrivers) {
# Take the first matching entry
$driverEntry = $vioscsiDrivers[0]
$oemInfName = (Get-ItemProperty -Path $driverEntry.PSPath).'(default)'
if ($oemInfName) {
Write-Host "Found vioscsi driver in DriverDatabase: $($driverEntry.Name.Split('\')[-1])" -ForegroundColor Cyan
Write-Host "OEM INF name: $oemInfName" -ForegroundColor Cyan
$oemInf = "$env:windir\INF\$oemInfName"
$infFullPath = $oemInf # Set for consistency
} else {
throw "Could not read OEM INF name from DriverDatabase entry"
}
} else {
throw "VirtIO SCSI driver not found in DriverDatabase. Please install vioscsi.inf or virtio-win-guest-tools.exe first."
}
} else {
try {
# OPTIONAL: Install INF driver first if path provided
if ($currentInfPath -and (Test-Path $currentInfPath)) {
Write-Host "Installing INF driver from provided path..." -ForegroundColor Yellow
Write-Host "INF Path: $currentInfPath" -ForegroundColor Cyan
# Check Windows version for correct pnputil syntax
$osVersion = [System.Environment]::OSVersion.Version
$buildNumber = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").CurrentBuildNumber
$useNewSyntax = ($osVersion.Major -gt 10) -or
(($osVersion.Major -eq 10) -and ([int]$buildNumber -ge 14393)) -or
(($osVersion.Major -eq 6) -and ($osVersion.Minor -ge 3))
try {
if ($useNewSyntax) {
Write-Host "Executing: pnputil /add-driver `"$currentInfPath`" /install" -ForegroundColor Gray
& pnputil /add-driver "$currentInfPath" /install
} else {
Write-Host "Executing: pnputil -a -i `"$currentInfPath`"" -ForegroundColor Gray
& pnputil -a -i "$currentInfPath"
}
if ($LASTEXITCODE -eq 0) {
Write-Host "INF driver installed successfully!" -ForegroundColor Green
} else {
Write-Host "INF installation completed with exit code $LASTEXITCODE" -ForegroundColor Yellow
}
} catch {
Write-Host "INF installation failed: $($_.Exception.Message)" -ForegroundColor Red
throw "Cannot continue without driver installation"
}
Write-Host "Waiting for driver registration..." -ForegroundColor Cyan
Start-Sleep -Seconds 2
} elseif ($currentInfPath) {
throw "Provided INF path does not exist: $currentInfPath"
}
# Check if VirtIO registry entries exist
if (-not (Test-Path $virtioBasePath)) {
Write-Host "VirtIO guest tools registry not found, searching DriverDatabase..." -ForegroundColor Yellow
# Fallback: Search in DriverDatabase for driver-specific INF
$driverDbPath = "HKLM:\SYSTEM\DriverDatabase\DriverPackages"
$virtioDrivers = Get-ChildItem $driverDbPath | Where-Object { $_.Name -like "*$($drv.InfFile)*" }
if ($virtioDrivers) {
# Take the first matching entry
$driverEntry = $virtioDrivers[0]
$oemInfName = (Get-ItemProperty -Path $driverEntry.PSPath).'(default)'
if ($oemInfName) {
Write-Host "Found $($drv.Name) driver in DriverDatabase: $($driverEntry.Name.Split('\')[-1])" -ForegroundColor Cyan
Write-Host "OEM INF name: $oemInfName" -ForegroundColor Cyan
$oemInf = "$env:windir\INF\$oemInfName"
$infFullPath = $oemInf # Set for consistency
} else {
throw "Could not read OEM INF name from DriverDatabase entry"
}
} else {
throw "$($drv.DeviceDesc) driver not found in DriverDatabase. Please install $($drv.InfFile) or virtio-win-guest-tools.exe first."
}
} else {
# Original method: Read from VirtIO guest tools registry
Write-Host "Reading VirtIO registry values..." -ForegroundColor Yellow
$virtioProps = Get-ItemProperty -Path $virtioBasePath
@@ -298,7 +352,7 @@ try {
# Step 1: Create device
Write-Host "`nStep 1: Creating device using Setup API..." -ForegroundColor Yellow
[DeviceInstaller]::CreateSoftwareDeviceWithHardwareId($deviceId, $classGuid, $hardwareId)
[DeviceInstaller]::CreateSoftwareDeviceWithHardwareId($deviceId, $classGuid, $hardwareId, $drv.DeviceDesc)
Write-Host "Device created successfully using Setup API!" -ForegroundColor Green
# Step 2: Assign driver
@@ -308,13 +362,21 @@ try {
# Find the created device path
$devicePath = "HKLM:\SYSTEM\CurrentControlSet\Enum\ROOT\$deviceId\0000"
# The Enum device-node property writes further down are blocked for Administrators
# on Windows Server 2016 (build 14393) - only SYSTEM may write under ...\Enum.
# There they error harmlessly because pnputil performs the real driver binding.
# On 2019+ (build > 14393) the freshly-created device subkey is writable, so the
# writes succeed. Gate them on the build to keep the 2016 run free of SecurityExceptions.
$osBuild = [int](Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").CurrentBuildNumber
$writeEnumDeviceProps = $osBuild -gt 14393
if (-not (Test-Path $devicePath)) {
Write-Host "Warning: Created device not found at expected path $devicePath" -ForegroundColor Yellow
$enumPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\ROOT"
$vioscsiDevices = Get-ChildItem $enumPath | Where-Object { $_.Name -like "*vioscsi*" -or $_.Name -like "*$deviceId*" }
if ($vioscsiDevices) {
$devicePath = $vioscsiDevices[0].PSPath + "\0000"
$foundDevices = Get-ChildItem $enumPath | Where-Object { $_.Name -like "*$deviceId*" }
if ($foundDevices) {
$devicePath = $foundDevices[0].PSPath + "\0000"
Write-Host "Found device at: $devicePath" -ForegroundColor Cyan
}
}
@@ -329,10 +391,12 @@ try {
Write-Host "Checking device registry configuration..." -ForegroundColor Cyan
# Add only missing values, no overwriting
# Add only missing values, no overwriting.
# These target the protected Enum device node; only attempt where permitted (2019+).
if ($writeEnumDeviceProps) {
if (-not $originalProps.Service) {
Set-ItemProperty -Path $devicePath -Name "Service" -Value "vioscsi" -Type String
Write-Host "Added Service: vioscsi" -ForegroundColor Green
Set-ItemProperty -Path $devicePath -Name "Service" -Value $drv.Name -Type String
Write-Host "Added Service: $($drv.Name)" -ForegroundColor Green
} else {
Write-Host "Service already set: $($originalProps.Service)" -ForegroundColor Cyan
}
@@ -345,7 +409,7 @@ try {
}
if (-not $originalProps.DeviceDesc) {
Set-ItemProperty -Path $devicePath -Name "DeviceDesc" -Value "@$oemInfName,%virtioscsi.devicedesc%;VirtIO SCSI Controller" -Type String
Set-ItemProperty -Path $devicePath -Name "DeviceDesc" -Value $drv.DeviceDesc -Type String
Write-Host "Added DeviceDesc" -ForegroundColor Green
} else {
Write-Host "DeviceDesc already set" -ForegroundColor Cyan
@@ -358,13 +422,16 @@ try {
Write-Host "Mfg already set" -ForegroundColor Cyan
}
if (-not $originalProps.CompatibleIDs) {
$compatibleIds = @("PCI\VEN_1AF4&DEV_1004", "PCI\VEN_1AF4", "PCI\CC_010000", "PCI\CC_0100")
Set-ItemProperty -Path $devicePath -Name "CompatibleIDs" -Value $compatibleIds -Type MultiString
Write-Host "Added CompatibleIDs" -ForegroundColor Green
} else {
Write-Host "CompatibleIDs already set" -ForegroundColor Cyan
}
if (-not $originalProps.CompatibleIDs) {
$compatibleIds = @($drv.HardwareIdShort, "PCI\VEN_1AF4", "PCI\CC_010000", "PCI\CC_0100")
Set-ItemProperty -Path $devicePath -Name "CompatibleIDs" -Value $compatibleIds -Type MultiString
Write-Host "Added CompatibleIDs" -ForegroundColor Green
} else {
Write-Host "CompatibleIDs already set" -ForegroundColor Cyan
}
} else {
Write-Host "Skipping manual Enum device-node writes on build $osBuild (pnputil performs the binding)" -ForegroundColor DarkGray
}
Write-Host "Device registry configuration checked" -ForegroundColor Green
}
@@ -395,51 +462,54 @@ try {
# Set driver class properties
Set-ItemProperty -Path $newClassPath -Name "InfPath" -Value $oemInfName -Type String
Set-ItemProperty -Path $newClassPath -Name "InfSection" -Value "scsi_inst" -Type String
Set-ItemProperty -Path $newClassPath -Name "InfSection" -Value $drv.InfSection -Type String
Set-ItemProperty -Path $newClassPath -Name "ProviderName" -Value "Red Hat, Inc." -Type String
Set-ItemProperty -Path $newClassPath -Name "DriverDate" -Value "10-21-2024" -Type String
Set-ItemProperty -Path $newClassPath -Name "DriverVersion" -Value "100.100.104.26600" -Type String
Set-ItemProperty -Path $newClassPath -Name "MatchingDeviceId" -Value $targetHardwareId -Type String
Set-ItemProperty -Path $newClassPath -Name "DriverDesc" -Value "Red Hat VirtIO SCSI pass-through controller" -Type String
Set-ItemProperty -Path $newClassPath -Name "DriverDesc" -Value $drv.DriverDesc -Type String
Write-Host "Driver class binding created: $nextNumberStr" -ForegroundColor Green
# Pre-configure the device to reference this driver
if (Test-Path $devicePath) {
# Pre-configure the device to reference this driver (Enum writes: build > 14393 only)
if ($writeEnumDeviceProps -and (Test-Path $devicePath)) {
Set-ItemProperty -Path $devicePath -Name "Driver" -Value "{4d36e97b-e325-11ce-bfc1-08002be10318}\$nextNumberStr" -Type String
Set-ItemProperty -Path $devicePath -Name "Problem" -Value 0 -Type DWord
Set-ItemProperty -Path $devicePath -Name "StatusFlags" -Value 0x18 -Type DWord
Write-Host "Device pre-configured with driver binding" -ForegroundColor Green
}
# Step 3: Create Critical Device Database entries
Write-Host "`nStep 3: Creating Critical Device Database entries..." -ForegroundColor Yellow
# Critical Device Database paths
$criticalDbPaths = @(
"HKLM:\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1af4&dev_1004",
"HKLM:\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1af4&dev_1004&subsys_00081af4&rev_00"
)
$criticalDbCount = 0
foreach ($criticalPath in $criticalDbPaths) {
$pathExists = Test-Path $criticalPath
if (-not $pathExists) {
New-Item -Path $criticalPath -Force -ErrorAction SilentlyContinue | Out-Null
}
# Verify path was created
if (Test-Path $criticalPath) {
Set-ItemProperty -Path $criticalPath -Name "Service" -Value "vioscsi" -Type String -ErrorAction SilentlyContinue
Set-ItemProperty -Path $criticalPath -Name "ClassGUID" -Value "{4d36e97b-e325-11ce-bfc1-08002be10318}" -Type String -ErrorAction SilentlyContinue
$criticalDbCount++
$shortPath = $criticalPath.Split('\')[-1]
Write-Host "Critical DB entry created: $shortPath" -ForegroundColor Green
}
}
Write-Host "Total Critical DB entries created: $criticalDbCount/$($criticalDbPaths.Count)" -ForegroundColor $(if ($criticalDbCount -eq $criticalDbPaths.Count) { 'Green' } else { 'Yellow' })
}
# Step 3: Create Critical Device Database entries
Write-Host "`nStep 3: Creating Critical Device Database entries..." -ForegroundColor Yellow
# Critical Device Database paths - generate based on driver hardware ID
$hardwareIdShortNormalized = $drv.HardwareIdShort -replace '\\', '#'
$hardwareIdNormalized = $hardwareId -replace '\\', '#'
$criticalDbPaths = @(
"HKLM:\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\$hardwareIdShortNormalized",
"HKLM:\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\$hardwareIdNormalized"
)
$criticalDbCount = 0
foreach ($criticalPath in $criticalDbPaths) {
$pathExists = Test-Path $criticalPath
if (-not $pathExists) {
New-Item -Path $criticalPath -Force -ErrorAction SilentlyContinue | Out-Null
}
# Verify path was created
if (Test-Path $criticalPath) {
Set-ItemProperty -Path $criticalPath -Name "Service" -Value $drv.Name -Type String -ErrorAction SilentlyContinue
Set-ItemProperty -Path $criticalPath -Name "ClassGUID" -Value $drv.ClassGuid -Type String -ErrorAction SilentlyContinue
$criticalDbCount++
$shortPath = $criticalPath.Split('\')[-1]
Write-Host "Critical DB entry created: $shortPath" -ForegroundColor Green
}
}
Write-Host "Total Critical DB entries created: $criticalDbCount/$($criticalDbPaths.Count)" -ForegroundColor $(if ($criticalDbCount -eq $criticalDbPaths.Count) { 'Green' } else { 'Yellow' })
# Step 4: Trigger device enumeration
Write-Host "`nStep 5: Triggering device enumeration..." -ForegroundColor Yellow
@@ -549,18 +619,18 @@ public class ConfigManager {
Write-Host "Both pnputil syntaxes failed" -ForegroundColor Red
}
}
# Check Windows version for pnputil /remove-device support
$buildNumber = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").CurrentBuildNumber
$supportsRemoveDevice = ([int]$buildNumber -ge 19041)
if (-not $supportsRemoveDevice) {
Write-Host "`npnputil /remove-device not supported on this Windows version (Build $buildNumber)" -ForegroundColor Yellow
Write-Host "Required: Windows 10 2004+ (Build 19041+) or Windows Server 2022+" -ForegroundColor Yellow
Write-Host "`nManual removal required:" -ForegroundColor Cyan
Write-Host "- Device Manager: devmgmt.msc -> Uninstall VirtIO SCSI Controller" -ForegroundColor Gray
Write-Host "- devcon.exe: devcon remove ROOT\\VIOSCSI\\0000" -ForegroundColor Gray
return
}
# Check Windows version for pnputil /remove-device support
$buildNumber = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").CurrentBuildNumber
$supportsRemoveDevice = ([int]$buildNumber -ge 19041)
if (-not $supportsRemoveDevice) {
Write-Host "`npnputil /remove-device not supported on this Windows version (Build $buildNumber)" -ForegroundColor Yellow
Write-Host "Required: Windows 10 2004+ (Build 19041+) or Windows Server 2022+" -ForegroundColor Yellow
Write-Host "`nManual removal required:" -ForegroundColor Cyan
Write-Host "- Device Manager: devmgmt.msc -> Uninstall $($drv.DeviceDesc)" -ForegroundColor Gray
Write-Host "- devcon.exe: devcon remove ROOT\\$($drv.Name.ToUpper())\0000" -ForegroundColor Gray
return
}
Write-Host "`nStep 1: Finding VirtIO phantom devices..." -ForegroundColor Yellow
@@ -579,7 +649,7 @@ public class ConfigManager {
}
elseif ($line -match "Device Description:\s+(.+)") {
$deviceDesc = $Matches[1].Trim()
# Only target ROOT enumerated devices (phantom devices) with vioscsi
# Only target ROOT-enumerated phantom devices for the current driver
if ($currentInstanceId -like "ROOT\*$deviceId*") {
$virtioDevices += [PSCustomObject]@{
InstanceId = $currentInstanceId
@@ -622,7 +692,7 @@ public class ConfigManager {
Write-Host "`nStep 3: Verification..." -ForegroundColor Yellow
# Check if devices still exist
$remainingDevices = Get-WmiObject -Class Win32_PnPEntity -Filter "DeviceID LIKE 'ROOT\\%vioscsi%'" -ErrorAction SilentlyContinue
$remainingDevices = Get-WmiObject -Class Win32_PnPEntity -Filter "DeviceID LIKE 'ROOT\\%$deviceId%'" -ErrorAction SilentlyContinue
if ($remainingDevices) {
Write-Host "Some VirtIO phantom devices still visible:" -ForegroundColor Yellow
foreach ($device in $remainingDevices) {
@@ -638,12 +708,19 @@ public class ConfigManager {
Write-Host "`nSummary:" -ForegroundColor Cyan
Write-Host "- Devices removed via pnputil: $removedCount" -ForegroundColor $(if ($removedCount -gt 0) { 'Green' } else { 'Yellow' })
if ($removedCount -eq 0 -and $virtioDevices.Count -eq 0) {
Write-Host "`nNo phantom devices found - system is already clean" -ForegroundColor Cyan
}
} catch {
if ($removedCount -eq 0 -and $virtioDevices.Count -eq 0) {
Write-Host "`nNo phantom devices found - system is already clean" -ForegroundColor Cyan
}
Write-Host "`n========================================" -ForegroundColor Green
Write-Host "Completed processing driver: $($drv.Name)" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
} # End try (per-driver processing)
catch {
Write-Host "`n=== ERROR ===" -ForegroundColor Red
$errorMessage = $_.Exception.Message
Write-Host "Error during device creation and configuration or removal: $errorMessage" -ForegroundColor Red
exit 1
}
} # End catch
} # End foreach $drv in $driversToProcess