dist/temp/WindowsUpdateTools/Private/Resolve-WUDriverDetails.ps1
|
function Resolve-WUDriverDetails { <# .SYNOPSIS Resolves OEM driver references to actual driver information. .DESCRIPTION Takes OEM INF references (like oem116.inf) and returns detailed information about the actual driver including manufacturer, device name, hardware IDs, and associated devices. .PARAMETER OemInfName The OEM INF filename (e.g., "oem116.inf") .PARAMETER LogPath Path to the log file for detailed logging. .EXAMPLE $driverInfo = Resolve-WUDriverDetails -OemInfName "oem116.inf" -LogPath $LogPath .NOTES Returns detailed driver information for better troubleshooting. This is a private function used internally by the WindowsUpdateTools module. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$OemInfName, [string]$LogPath ) $driverInfo = [PSCustomObject]@{ OemInf = $OemInfName OriginalName = "Unknown" ProviderName = "Unknown" ClassName = "Unknown" ClassGuid = "Unknown" DriverVersion = "Unknown" DriverDate = "Unknown" IsSigned = $false SignerName = "Unknown" InfPath = $null HardwareIDs = @() AssociatedDevices = @() DeviceDescriptions = @() ErrorMessage = $null ResolvedSuccessfully = $false } try { Write-WULog -Message "Resolving driver details for: $OemInfName" -LogPath $LogPath # Method 1: Use pnputil to get basic driver information (fastest and most reliable) try { $pnpOutput = & pnputil.exe /enum-drivers 2>$null | Out-String # Find the section for our OEM INF $lines = $pnpOutput -split "`n" $inDriverSection = $false $currentDriver = @{} foreach ($line in $lines) { $line = $line.Trim() if ($line -match "Published Name:\s*(.+)") { if ($inDriverSection -and $currentDriver.Count -gt 0) { # We've moved to a new driver, process the previous one if it was ours break } $inDriverSection = $matches[1].Trim() -eq $OemInfName if ($inDriverSection) { $currentDriver = @{} } } if ($inDriverSection -and $line) { if ($line -match "Original Name:\s*(.+)") { $driverInfo.OriginalName = $matches[1].Trim() } elseif ($line -match "Provider Name:\s*(.+)") { $driverInfo.ProviderName = $matches[1].Trim() } elseif ($line -match "Class Name:\s*(.+)") { $driverInfo.ClassName = $matches[1].Trim() } elseif ($line -match "Class GUID:\s*(.+)") { $driverInfo.ClassGuid = $matches[1].Trim() } elseif ($line -match "Driver Version:\s*(.+)") { $versionInfo = $matches[1].Trim() -split '\s+' if ($versionInfo.Length -ge 1) { $driverInfo.DriverDate = $versionInfo[0] } if ($versionInfo.Length -ge 2) { $driverInfo.DriverVersion = $versionInfo[1] } } elseif ($line -match "Signer Name:\s*(.+)") { $signerName = $matches[1].Trim() $driverInfo.SignerName = $signerName # Enhanced signature detection logic # Consider driver signed if: # 1. Signer is explicitly Microsoft # 2. Signer contains Microsoft in the name # 3. Signer is not "Not signed" or empty # 4. Has Windows Hardware Quality Labs (WHQL) signature if ($signerName -eq "Microsoft Windows" -or $signerName -eq "Microsoft Corporation" -or $signerName -like "*Microsoft*" -or $signerName -like "*WHQL*" -or $signerName -like "*Windows Hardware Compatibility*" -or ($signerName -ne "Not signed" -and $signerName -ne "" -and $signerName -ne "Unknown")) { $driverInfo.IsSigned = $true } else { $driverInfo.IsSigned = $false } Write-WULog -Message "Driver signature analysis for $OemInfName`: Signer='$signerName', Considered signed: $($driverInfo.IsSigned)" -LogPath $LogPath } } } if ($driverInfo.OriginalName -ne "Unknown") { $driverInfo.ResolvedSuccessfully = $true Write-WULog -Message "Successfully resolved $OemInfName via pnputil" -LogPath $LogPath Write-WULog -Message " Provider: $($driverInfo.ProviderName), Class: $($driverInfo.ClassName)" -LogPath $LogPath Write-WULog -Message " Signature: $($driverInfo.IsSigned) by '$($driverInfo.SignerName)'" -LogPath $LogPath } } catch { Write-WULog -Message "pnputil method failed for $OemInfName`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Method 2: Additional signature verification using Get-AuthenticodeSignature (if available) if ($driverInfo.ResolvedSuccessfully) { try { $infPath = Join-Path "$env:WINDIR\INF" $OemInfName if (Test-Path $infPath) { $signature = Get-AuthenticodeSignature -FilePath $infPath -ErrorAction SilentlyContinue if ($signature) { $authenticodeValid = $signature.Status -eq 'Valid' $authenticodeSigner = if ($signature.SignerCertificate) { $signature.SignerCertificate.Subject } else { "No certificate" } Write-WULog -Message "Authenticode verification for $OemInfName`: Status=$($signature.Status), Signer='$authenticodeSigner'" -LogPath $LogPath # Cross-validate with pnputil results if ($authenticodeValid -and -not $driverInfo.IsSigned) { Write-WULog -Message "SIGNATURE VERIFICATION: pnputil reported unsigned but Authenticode shows valid signature" -Level Warning -LogPath $LogPath $driverInfo.IsSigned = $true $driverInfo.SignerName = $authenticodeSigner } elseif (-not $authenticodeValid -and $driverInfo.IsSigned) { Write-WULog -Message "SIGNATURE VERIFICATION: pnputil reported signed but Authenticode shows invalid/missing signature" -Level Warning -LogPath $LogPath # Trust pnputil over Authenticode for driver store entries } } } } catch { Write-WULog -Message "Authenticode signature verification failed for $OemInfName`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } # Method 3: Try to read the INF file directly for additional details $infPath = Join-Path "$env:WINDIR\INF" $OemInfName $driverInfo.InfPath = $infPath if (Test-Path $infPath) { try { $infContent = Get-Content $infPath -ErrorAction Stop # Parse INF file for device descriptions and hardware IDs $currentSection = "" $strings = @{} foreach ($line in $infContent) { $line = $line.Trim() # Track current section if ($line -match '^\[(.+)\]') { $currentSection = $matches[1] continue } # Collect string definitions if ($currentSection -eq "Strings" -and $line -match '^([^=]+)\s*=\s*"([^"]+)"') { $strings[$matches[1].Trim()] = $matches[2].Trim() } # Look for device descriptions in manufacturer sections if ($line -match '"([^"]+)"\s*=\s*[^,]+,\s*(.+)') { $deviceDesc = $matches[1].Trim() $hwIdRaw = $matches[2].Trim().Trim('"') if ($deviceDesc -and $deviceDesc -notin $driverInfo.DeviceDescriptions) { $driverInfo.DeviceDescriptions += $deviceDesc } if ($hwIdRaw -and $hwIdRaw -notlike '*%*' -and $hwIdRaw -notin $driverInfo.HardwareIDs) { $driverInfo.HardwareIDs += $hwIdRaw } } # Look for hardware IDs in install sections if ($line -match 'HardwareIds\s*=\s*(.+)') { $hwIds = $matches[1] -split ',' | ForEach-Object { $_.Trim().Trim('"') } foreach ($hwId in $hwIds) { if ($hwId -and $hwId -notlike '*%*' -and $hwId -notin $driverInfo.HardwareIDs) { $driverInfo.HardwareIDs += $hwId } } } } # Resolve string references in device descriptions for ($i = 0; $i -lt $driverInfo.DeviceDescriptions.Count; $i++) { $desc = $driverInfo.DeviceDescriptions[$i] if ($desc -match '%(.+)%') { $stringKey = $matches[1] if ($strings.ContainsKey($stringKey)) { $driverInfo.DeviceDescriptions[$i] = $strings[$stringKey] } } } Write-WULog -Message "Enhanced $OemInfName with INF file details" -LogPath $LogPath } catch { Write-WULog -Message "Could not parse INF file for $OemInfName`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } # Method 3: Find associated devices using hardware IDs if ($driverInfo.HardwareIDs.Count -gt 0) { try { $devices = Get-CimInstance -ClassName Win32_PnPEntity -ErrorAction SilentlyContinue foreach ($device in $devices) { if ($device.HardwareID) { foreach ($hwId in $driverInfo.HardwareIDs) { if ($device.HardwareID -contains $hwId) { $deviceObj = [PSCustomObject]@{ Name = $device.Name DeviceID = $device.DeviceID Status = $device.Status Present = $device.Present Manufacturer = $device.Manufacturer } # Avoid duplicates $exists = $driverInfo.AssociatedDevices | Where-Object { $_.DeviceID -eq $deviceObj.DeviceID } if (-not $exists) { $driverInfo.AssociatedDevices += $deviceObj } } } } } if ($driverInfo.AssociatedDevices.Count -gt 0) { Write-WULog -Message "Found $($driverInfo.AssociatedDevices.Count) associated devices for $OemInfName" -LogPath $LogPath } } catch { Write-WULog -Message "Could not enumerate devices for $OemInfName`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } # Log the resolved information Write-WULog -Message "Driver resolution complete for $OemInfName`:" -LogPath $LogPath Write-WULog -Message " Original Name: $($driverInfo.OriginalName)" -LogPath $LogPath Write-WULog -Message " Provider: $($driverInfo.ProviderName)" -LogPath $LogPath Write-WULog -Message " Class: $($driverInfo.ClassName)" -LogPath $LogPath Write-WULog -Message " Version: $($driverInfo.DriverVersion)" -LogPath $LogPath Write-WULog -Message " Date: $($driverInfo.DriverDate)" -LogPath $LogPath Write-WULog -Message " Signed: $($driverInfo.IsSigned)" -LogPath $LogPath Write-WULog -Message " Signer: $($driverInfo.SignerName)" -LogPath $LogPath Write-WULog -Message " Device Descriptions: $($driverInfo.DeviceDescriptions.Count)" -LogPath $LogPath Write-WULog -Message " Hardware IDs: $($driverInfo.HardwareIDs.Count)" -LogPath $LogPath Write-WULog -Message " Associated Devices: $($driverInfo.AssociatedDevices.Count)" -LogPath $LogPath } catch { $driverInfo.ErrorMessage = $_.Exception.Message Write-WULog -Message "Error resolving driver $OemInfName`: $($_.Exception.Message)" -Level Error -LogPath $LogPath } return $driverInfo } |