private/microsoft-update-catalog/Save-MicrosoftUpdateCatalogDriver.ps1
|
function Save-MicrosoftUpdateCatalogDriver { [CmdletBinding(DefaultParameterSetName = 'ByPNPClass')] param ( [System.String]$DestinationDirectory, [Parameter(ParameterSetName = 'ByHardwareID')] [System.String[]]$HardwareID, [Parameter(ParameterSetName = 'ByPNPClass')] [ValidateSet('DiskDrive','Display','Net','SCSIAdapter','SecurityDevices','USB')] [System.String]$PNPClass ) #================================================= if (!($DestinationDirectory)) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Set the DestinationDirectory parameter to download the Drivers" } else { if (!(Test-Path $DestinationDirectory)){ New-Item -Path $DestinationDirectory -ItemType Directory -Force | Out-Null } } #================================================= # MSCatalog PowerShell Module # Ryan-Jan # https://github.com/ryan-jan/MSCatalog # This excellent work is a good way to gather information from MS # Catalog #================================================= <# if (!(Get-Module -ListAvailable -Name MSCatalog)) { Install-Module MSCatalog -Force -SkipPublisherCheck -ErrorAction Ignore } #> #================================================= $HardwareIDPattern = 'v[ei][dn]_([0-9a-f]){4}&[pd][ie][dv]_([0-9a-f]){4}' $SurfaceIDPattern = 'mshw0[0-1]([0-9]){2}' if (-not (Test-MicrosoftUpdateCatalog)) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Unable to reach Microsoft Update Catalog, exiting function" return } # Initialize hashtable to track searched HardwareIDs to avoid duplicates $SearchedHardwareIDs = @{} #================================================= # ByPNPClass #================================================= if ($PSCmdlet.ParameterSetName -eq 'ByPNPClass') { Write-Verbose "[$(Get-Date -format s)] ByPNPClass" $Params = @{ ClassName = 'Win32_PnpEntity' Property = 'Name','Description','DeviceID','HardwareID','ClassGuid','Manufacturer','PNPClass' } $Devices = Get-CimInstance @Params if ($Devices) { if ($PNPClass -match 'Display') { $Devices = $Devices | Where-Object {($_.Name -match 'Video') -or ($_.PNPClass -match 'Display')} } elseif ($PNPClass -match 'Net') { $Devices = $Devices | Where-Object {($_.Name -match 'Network') -or ($_.PNPClass -match 'Net')} } elseif ($PNPClass) { $Devices = $Devices | Where-Object {$_.PNPClass -match $PNPClass} } else { # No parameters were pecified, so all devices will be processed } } else { Write-Verbose "[$(Get-Date -format s)] PNP Devices were not found on the system" } if ($Devices) { if ($PNPClass) { Write-Verbose "[$(Get-Date -format s)] Devices were found for PNPClass $PNPClass" } else { Write-Verbose "[$(Get-Date -format s)] Devices were found for all PNPClasses" } # Process all devices foreach ($Item in $Devices) { Write-Verbose "[$(Get-Date -format s)] $Item" $WindowsUpdateDriver = $null $FindHardwareID = $null # Determine if the input is a HardwareID or SurfaceID pattern, and extract the relevant portion for searching Write-Verbose "[$(Get-Date -format s)] Try matching DeviceID to HardwareID pattern: $HardwareIDPattern" Write-Verbose "[$(Get-Date -format s)] DeviceID: $($Item.DeviceID)" $FindHardwareID = $Item.DeviceID | Select-String -Pattern $HardwareIDPattern -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value if (-NOT $FindHardwareID) { if ($Item.HardwareID) { Write-Verbose "[$(Get-Date -format s)] HardwareID: $($Item.HardwareID[0])" $FindHardwareID = $Item.HardwareID[0] | Select-String -Pattern $HardwareIDPattern -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value } } if ($FindHardwareID) { # Check if we have already searched for this HardwareID if ($SearchedHardwareIDs.ContainsKey($FindHardwareID)) { Write-Verbose "[$(Get-Date -format s)] Skipping duplicate search for: $FindHardwareID" continue } # Mark this HardwareID as searched $SearchedHardwareIDs[$FindHardwareID] = $true Write-Verbose "[$(Get-Date -format s)] Search: $FindHardwareID" $SearchString = "$FindHardwareID".Replace('&',"`%26") try { # Define version search order (newest to oldest) $VersionSearchOrder = @('25H2', '24H2', '23H2', '22H2', '21H2', 'Vibranium', '1903', '1809') # Search for driver with version-specific queries first foreach ($Version in $VersionSearchOrder) { $WindowsUpdateDriver = Get-MicrosoftUpdateCatalogResult -Search "$Version+$PNPClass+$SearchString" -Descending | Select-Object LastUpdated, Title, Version, Size, Guid -First 1 -ErrorAction Ignore if ($WindowsUpdateDriver) { Write-Verbose "Found driver match for version: $Version" break } } if ($WindowsUpdateDriver.Guid) { Write-Host -ForegroundColor DarkGreen "[$(Get-Date -format s)] $($WindowsUpdateDriver.Title)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] UpdateID: $($WindowsUpdateDriver.Guid)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Last Updated $($WindowsUpdateDriver.LastUpdated) Version $($WindowsUpdateDriver.Version) Size: $($WindowsUpdateDriver.Size)" if ($Item.Name -and $Item.PNPClass) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] $($Item.PNPClass) $($Item.Name)" } elseif ($Item.Name) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] $($Item.Name)" } else { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] $($Item.DeviceID)" } Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] HardwareID: $FindHardwareID" Write-Verbose "[$(Get-Date -format s)] SearchString: $SearchString" if ($DestinationDirectory) { $ExpandedLocalFolder = Join-Path $DestinationDirectory "$($WindowsUpdateDriver.Guid)" if (Test-Path $ExpandedLocalFolder) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Driver already expanded at $ExpandedLocalFolder" } else { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Downloading to $DestinationDirectory" $WindowsUpdateDriverFile = Save-MicrosoftUpdateCatalogUpdate -Guid $WindowsUpdateDriver.Guid -DestinationDirectory $DestinationDirectory if ($WindowsUpdateDriverFile) { if (-not (Test-Path $ExpandedLocalFolder)) { # Destination folder must exist before expanding the cab file New-Item -Path $ExpandedLocalFolder -ItemType Directory -Force | Out-Null } Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Expanding to $ExpandedLocalFolder" expand.exe "$($WindowsUpdateDriverFile.FullName)" -F:* "$ExpandedLocalFolder" | Out-Null Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Removing $($WindowsUpdateDriverFile.FullName)" Remove-Item $($WindowsUpdateDriverFile.FullName) -Force -ErrorAction SilentlyContinue | Out-Null } else { Write-Verbose "[$(Get-Date -format s)] Could not find a Driver for this HardwareID" } } } } else { Write-Verbose "[$(Get-Date -format s)] No Results: $($Item.Name) $FindHardwareID" } } catch{ Write-Verbose "[$(Get-Date -format s)] Unable to get Driver for Hardware component" } } else { Write-Verbose "[$(Get-Date -format s)] No Results: $FindHardwareID" } } } } #================================================= # ByHardwareID #================================================= if ($PSCmdlet.ParameterSetName -eq 'ByHardwareID') { Write-Verbose "[$(Get-Date -format s)] ByHardwareID" foreach ($Item in $HardwareID) { Write-Verbose "[$(Get-Date -format s)] $Item" $WindowsUpdateDriver = $null $FindHardwareID = $null # Determine if the input is a HardwareID or SurfaceID pattern, and extract the relevant portion for searching Write-Verbose "[$(Get-Date -format s)] Try matching HardwareID pattern: $HardwareIDPattern" $FindHardwareID = $Item | Select-String -Pattern $HardwareIDPattern | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value if (-not ($FindHardwareID)) { Write-Verbose "[$(Get-Date -format s)] Try matching SurfaceID pattern: $SurfaceIDPattern" $FindHardwareID = $Item | Select-String -Pattern $SurfaceIDPattern | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value } if (-not ($FindHardwareID)) { Write-Verbose "[$(Get-Date -format s)] Search term did not match known patterns, using raw input as search term" $FindHardwareID = $Item } if ($FindHardwareID) { # Check if we have already searched for this HardwareID if ($SearchedHardwareIDs.ContainsKey($FindHardwareID)) { Write-Verbose "[$(Get-Date -format s)] Skipping duplicate search for: $FindHardwareID" continue } # Mark this HardwareID as searched $SearchedHardwareIDs[$FindHardwareID] = $true # Write-Verbose "[$(Get-Date -format s)] Search: $FindHardwareID" $SearchString = "$FindHardwareID".Replace('&', "`%26") try { Write-Verbose "[$(Get-Date -format s)] Search: $SearchString" $WindowsUpdateDriver = Get-MicrosoftUpdateCatalogResult -Search "$SearchString" -Descending | Select-Object LastUpdated, Title, Version, Size, Guid -First 1 -ErrorAction Ignore if ($WindowsUpdateDriver) { Write-Verbose "[$(Get-Date -format s)] Found driver match for version: $($WindowsUpdateDriver.Version)" } } catch { Write-Verbose "[$(Get-Date -format s)] Error searching for driver: $_" } if ($WindowsUpdateDriver.Guid) { Write-Host -ForegroundColor DarkGreen "[$(Get-Date -format s)] $($WindowsUpdateDriver.Title)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] UpdateID: $($WindowsUpdateDriver.Guid)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Last Updated $($WindowsUpdateDriver.LastUpdated) Version $($WindowsUpdateDriver.Version) Size: $($WindowsUpdateDriver.Size)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] HardwareID: $FindHardwareID" Write-Verbose "[$(Get-Date -format s)] SearchString: $SearchString" if ($DestinationDirectory) { $ExpandedLocalFolder = Join-Path $DestinationDirectory "$($WindowsUpdateDriver.Guid)" if (Test-Path $ExpandedLocalFolder) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Driver already expanded at $ExpandedLocalFolder" } else { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Downloading to $DestinationDirectory" $WindowsUpdateDriverFile = Save-MicrosoftUpdateCatalogUpdate -Guid $WindowsUpdateDriver.Guid -DestinationDirectory $DestinationDirectory if ($WindowsUpdateDriverFile) { if (-not (Test-Path $ExpandedLocalFolder)) { # Destination folder must exist before expanding the cab file New-Item -Path $ExpandedLocalFolder -ItemType Directory -Force | Out-Null } Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Expanding to $ExpandedLocalFolder" expand.exe "$($WindowsUpdateDriverFile.FullName)" -F:* "$ExpandedLocalFolder" | Out-Null Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Removing $($WindowsUpdateDriverFile.FullName)" Remove-Item $($WindowsUpdateDriverFile.FullName) -Force -ErrorAction SilentlyContinue | Out-Null } else { Write-Verbose "[$(Get-Date -format s)] Could not find a Driver for this HardwareID" } } } } else { Write-Verbose "[$(Get-Date -format s)] No Results: $FindHardwareID" } } else { Write-Verbose "[$(Get-Date -format s)] No Results: $FindHardwareID" } } } } |