From 04dfb5f327742b8eb816845a6214b5f2e9df6b94 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:37:48 -0800 Subject: [PATCH] Normalizes Windows LTSC releases for OEM drivers Adds logic to normalize LTSC/LTSB release years (such as 2016, 2019, 2021, and 2024) to their corresponding base Windows client versions (10 or 11). This ensures correct model retrieval and driver downloading, as OEM catalogs typically evaluate against base Windows versions rather than LTSC-specific release years. --- FFUDevelopment/BuildFFUVM.ps1 | 43 ++++++++++-- .../FFUUI.Core/FFUUI.Core.Drivers.psm1 | 65 ++++++++++++++++--- 2 files changed, 94 insertions(+), 14 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 2e30d55..58f721c 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -697,6 +697,26 @@ Set-BitsTransferPriority -Priority $BitsPriority #FUNCTIONS +function Get-EffectiveDriverWindowsRelease { + param( + [Parameter(Mandatory = $true)] + [int]$WindowsRelease, + [string]$WindowsSKU + ) + + # Normalize LTSC/LTSB client releases to OEM driver release values. + if (-not [string]::IsNullOrWhiteSpace($WindowsSKU) -and $WindowsSKU -like '*LTS*') { + if ($WindowsRelease -in 2016, 2019, 2021) { + return 10 + } + if ($WindowsRelease -eq 2024) { + return 11 + } + } + + return $WindowsRelease +} + function Get-Parameters { [CmdletBinding()] param ( @@ -5514,10 +5534,16 @@ if ($driversJsonPath -and (Test-Path $driversJsonPath) -and ($InstallDrivers -or else { WriteLog "Found $($driversToProcess.Count) driver entries to process from $driversJsonPath." + # Resolve effective release used for OEM driver operations. + $localDriverWindowsRelease = Get-EffectiveDriverWindowsRelease -WindowsRelease $WindowsRelease -WindowsSKU $WindowsSKU + if ($localDriverWindowsRelease -ne $WindowsRelease) { + WriteLog "Normalized WindowsRelease for Drivers.json processing from $WindowsRelease to $localDriverWindowsRelease (SKU='$WindowsSKU')." + } + $preserveSourceOnCompress = ($UseDriversAsPEDrivers -and $CompressDownloadedDriversToWim) $taskArguments = @{ DriversFolder = $DriversFolder - WindowsRelease = $WindowsRelease + WindowsRelease = $localDriverWindowsRelease WindowsArch = $WindowsArch WindowsVersion = $WindowsVersion Headers = $Headers @@ -5654,26 +5680,31 @@ if ($driversJsonPath -and (Test-Path $driversJsonPath) -and ($InstallDrivers -or } # Existing single-model driver download logic elseif (($Make -and $Model) -and ($InstallDrivers -or $CopyDrivers)) { + # Resolve effective release used for OEM driver operations. + $localDriverWindowsRelease = Get-EffectiveDriverWindowsRelease -WindowsRelease $WindowsRelease -WindowsSKU $WindowsSKU + if ($localDriverWindowsRelease -ne $WindowsRelease) { + WriteLog "Normalized WindowsRelease for single-model driver processing from $WindowsRelease to $localDriverWindowsRelease (SKU='$WindowsSKU')." + } + try { if ($Make -eq 'HP') { WriteLog 'Getting HP drivers' - Get-HPDrivers -Make $Make -Model $Model -WindowsArch $WindowsArch -WindowsRelease $WindowsRelease -WindowsVersion $WindowsVersion + Get-HPDrivers -Make $Make -Model $Model -WindowsArch $WindowsArch -WindowsRelease $localDriverWindowsRelease -WindowsVersion $WindowsVersion WriteLog 'Getting HP drivers completed successfully' } if ($make -eq 'Microsoft') { WriteLog 'Getting Microsoft drivers' - Get-MicrosoftDrivers -Make $Make -Model $Model -WindowsArch $WindowsArch -WindowsRelease $WindowsRelease + Get-MicrosoftDrivers -Make $Make -Model $Model -WindowsArch $WindowsArch -WindowsRelease $localDriverWindowsRelease WriteLog 'Getting Microsoft drivers completed successfully' } if ($make -eq 'Lenovo') { WriteLog 'Getting Lenovo drivers' - Get-LenovoDrivers -Model $Model -WindowsArch $WindowsArch -WindowsRelease $WindowsRelease + Get-LenovoDrivers -Model $Model -WindowsArch $WindowsArch -WindowsRelease $localDriverWindowsRelease WriteLog 'Getting Lenovo drivers completed successfully' } if ($make -eq 'Dell') { WriteLog 'Getting Dell drivers' - #Dell mixes Win10 and 11 drivers, hence no WindowsRelease parameter - Get-DellDrivers -Model $Model -WindowsArch $WindowsArch -WindowsRelease $WindowsRelease + Get-DellDrivers -Model $Model -WindowsArch $WindowsArch -WindowsRelease $localDriverWindowsRelease WriteLog 'Getting Dell drivers completed successfully' } } diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Drivers.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Drivers.psm1 index 4cbd33d..361bdf4 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Drivers.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Drivers.psm1 @@ -35,10 +35,41 @@ function Get-DriverDisplayName { return $BaseName.Trim() } - return "$($BaseName.Trim()) ($($Identifier.Trim()))" -} - -function Convert-DriverItemToJsonModel { + return "$($BaseName.Trim()) ($($Identifier.Trim()))" + } + + function Get-EffectiveDriverWindowsRelease { + param( + [Parameter(Mandatory = $true)] + [int]$WindowsRelease, + [string]$WindowsReleaseDisplay, + [string]$WindowsSku + ) + + # Normalize LTSC/LTSB UI release selections to client driver releases for OEM catalogs. + if (-not [string]::IsNullOrWhiteSpace($WindowsReleaseDisplay)) { + if (($WindowsReleaseDisplay -like 'Windows 10*') -and (($WindowsReleaseDisplay -like '*LTSB*') -or ($WindowsReleaseDisplay -like '*LTSC*'))) { + return 10 + } + if (($WindowsReleaseDisplay -like 'Windows 11*') -and ($WindowsReleaseDisplay -like '*LTSC*')) { + return 11 + } + } + + # Use SKU-based fallback when display text is unavailable. + if (-not [string]::IsNullOrWhiteSpace($WindowsSku) -and $WindowsSku -like '*LTS*') { + if ($WindowsRelease -in 2016, 2019, 2021) { + return 10 + } + if ($WindowsRelease -eq 2024) { + return 11 + } + } + + return $WindowsRelease + } + + function Convert-DriverItemToJsonModel { param( [Parameter(Mandatory = $true)] [pscustomobject]$DriverItem @@ -154,8 +185,20 @@ function Convert-DriverItemToJsonModel { # Get necessary values from UI or script scope $localDriversFolder = $State.Controls.txtDriversFolder.Text $localWindowsRelease = $null + $localWindowsReleaseDisplay = $null if ($null -ne $State.Controls.cmbWindowsRelease.SelectedItem) { $localWindowsRelease = $State.Controls.cmbWindowsRelease.SelectedItem.Value + $localWindowsReleaseDisplay = $State.Controls.cmbWindowsRelease.SelectedItem.Display + } + + # Resolve effective release used specifically for OEM driver operations. + $localWindowsSku = if ($null -ne $State.Controls.cmbWindowsSKU.SelectedItem) { [string]$State.Controls.cmbWindowsSKU.SelectedItem } else { $null } + $localDriverWindowsRelease = $localWindowsRelease + if ($null -ne $localWindowsRelease) { + $localDriverWindowsRelease = Get-EffectiveDriverWindowsRelease -WindowsRelease $localWindowsRelease -WindowsReleaseDisplay $localWindowsReleaseDisplay -WindowsSku $localWindowsSku + if ($localDriverWindowsRelease -ne $localWindowsRelease) { + WriteLog "Normalized WindowsRelease for model retrieval from $localWindowsRelease to $localDriverWindowsRelease (Display='$localWindowsReleaseDisplay', SKU='$localWindowsSku')." + } } # Get headers and user agent from Get-CoreStaticVariables @@ -173,7 +216,7 @@ function Convert-DriverItemToJsonModel { $rawModels = Get-MicrosoftDriversModelList -Headers $Headers -UserAgent $UserAgent -DriversFolder $localDriversFolder } 'Dell' { - $rawModels = Get-DellDriversModelList -WindowsRelease $localWindowsRelease -DriversFolder $localDriversFolder -Make $SelectedMake + $rawModels = Get-DellDriversModelList -WindowsRelease $localDriverWindowsRelease -DriversFolder $localDriversFolder -Make $SelectedMake } 'HP' { $rawModels = Get-HPDriversModelList -DriversFolder $localDriversFolder -Make $SelectedMake @@ -831,6 +874,12 @@ function Invoke-DownloadSelectedDrivers { $localDriversFolder = $State.Controls.txtDriversFolder.Text $localWindowsRelease = $State.Controls.cmbWindowsRelease.SelectedItem.Value + $localWindowsReleaseDisplay = $State.Controls.cmbWindowsRelease.SelectedItem.Display + $localWindowsSku = if ($null -ne $State.Controls.cmbWindowsSKU.SelectedItem) { [string]$State.Controls.cmbWindowsSKU.SelectedItem } else { $null } + $localDriverWindowsRelease = Get-EffectiveDriverWindowsRelease -WindowsRelease $localWindowsRelease -WindowsReleaseDisplay $localWindowsReleaseDisplay -WindowsSku $localWindowsSku + if ($localDriverWindowsRelease -ne $localWindowsRelease) { + WriteLog "Normalized WindowsRelease for driver download from $localWindowsRelease to $localDriverWindowsRelease (Display='$localWindowsReleaseDisplay', SKU='$localWindowsSku')." + } $localWindowsArch = $State.Controls.cmbWindowsArch.SelectedItem $localWindowsVersion = if ($null -ne $State.Controls.cmbWindowsVersion -and $null -ne $State.Controls.cmbWindowsVersion.SelectedItem) { $State.Controls.cmbWindowsVersion.SelectedItem } else { $null } $coreStaticVars = Get-CoreStaticVariables @@ -848,10 +897,10 @@ function Invoke-DownloadSelectedDrivers { WriteLog "Dell drivers selected. Ensuring Dell Catalog is up-to-date..." try { $dellDriversFolder = Join-Path -Path $localDriversFolder -ChildPath "Dell" - $catalogBaseName = if ($localWindowsRelease -le 11) { "CatalogIndexPC" } else { "Catalog" } + $catalogBaseName = if ($localDriverWindowsRelease -le 11) { "CatalogIndexPC" } else { "Catalog" } $dellCabFile = Join-Path -Path $dellDriversFolder -ChildPath "$($catalogBaseName).cab" $dellCatalogXML = Join-Path -Path $dellDriversFolder -ChildPath "$($catalogBaseName).xml" - $catalogUrl = if ($localWindowsRelease -le 11) { "https://downloads.dell.com/catalog/CatalogIndexPC.cab" } else { "https://downloads.dell.com/catalog/Catalog.cab" } + $catalogUrl = if ($localDriverWindowsRelease -le 11) { "https://downloads.dell.com/catalog/CatalogIndexPC.cab" } else { "https://downloads.dell.com/catalog/Catalog.cab" } $downloadCatalog = $true if (Test-Path -Path $dellCatalogXML -PathType Leaf) { @@ -891,7 +940,7 @@ function Invoke-DownloadSelectedDrivers { $preserveSource = ($State.Controls.chkUseDriversAsPEDrivers.IsChecked -and $State.Controls.chkCompressDriversToWIM.IsChecked) $taskArguments = @{ DriversFolder = $localDriversFolder - WindowsRelease = $localWindowsRelease + WindowsRelease = $localDriverWindowsRelease WindowsArch = $localWindowsArch WindowsVersion = $localWindowsVersion Headers = $localHeaders