mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
Enhances Dell driver retrieval by resolving missing CabUrl through CatalogIndexPC. Introduces Resolve-DellCabUrlFromModel function for improved reliability. Updates Save-DriversJson and Import-DriversJson functions to handle additional properties (SystemId, CabUrl, CabRelativePath) for Dell models. Refines Get-DellDrivers function to ensure consistent model handling and logging.
This commit is contained in:
@@ -1432,7 +1432,7 @@ function Get-DellDrivers {
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Model,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet('x64','x86','ARM64')]
|
||||
[ValidateSet('x64', 'x86', 'ARM64')]
|
||||
[string]$WindowsArch,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[int]$WindowsRelease
|
||||
@@ -1454,9 +1454,18 @@ function Get-DellDrivers {
|
||||
if (-not $target) { throw "Requested Dell model '$Model' not found in index." }
|
||||
|
||||
$cabUrl = $target.CabUrl
|
||||
if ([string]::IsNullOrWhiteSpace($cabUrl)) {
|
||||
WriteLog "CabUrl missing for '$($target.Model)'; resolving via CatalogIndexPC."
|
||||
$resolved = Resolve-DellCabUrlFromModel -DriversFolder $DriversFolder -ModelDisplay $target.Model
|
||||
if ($null -eq $resolved -or [string]::IsNullOrWhiteSpace($resolved.CabUrl)) {
|
||||
throw "Unable to resolve CabUrl for $($target.Model) from CatalogIndexPC."
|
||||
}
|
||||
$cabUrl = $resolved.CabUrl
|
||||
$target.CabUrl = $cabUrl
|
||||
}
|
||||
$modelCabName = [IO.Path]::GetFileName($cabUrl)
|
||||
$modelCabPath = Join-Path $DriversFolder $modelCabName
|
||||
$modelXmlPath = Join-Path $DriversFolder ($modelCabName -replace '\.cab$','.xml')
|
||||
$modelXmlPath = Join-Path $DriversFolder ($modelCabName -replace '\.cab$', '.xml')
|
||||
|
||||
if (Test-Path $modelCabPath) { Remove-Item $modelCabPath -Force -ErrorAction SilentlyContinue }
|
||||
if (Test-Path $modelXmlPath) { Remove-Item $modelXmlPath -Force -ErrorAction SilentlyContinue }
|
||||
@@ -1473,7 +1482,7 @@ function Get-DellDrivers {
|
||||
}
|
||||
|
||||
foreach ($pkg in $pkgs) {
|
||||
$categorySafe = ($pkg.Category -replace '[\\\/\:\*\?\"\<\>\| ]','_')
|
||||
$categorySafe = ($pkg.Category -replace '[\\\/\:\*\?\"\<\>\| ]', '_')
|
||||
$downloadFolder = Join-Path $DriversFolder (Join-Path $Model $categorySafe)
|
||||
if (-not (Test-Path $downloadFolder)) { New-Item -Path $downloadFolder -ItemType Directory -Force | Out-Null }
|
||||
$driverFilePath = Join-Path $downloadFolder $pkg.DriverFileName
|
||||
@@ -1535,8 +1544,8 @@ function Get-DellDrivers {
|
||||
$driverPath = $component.path
|
||||
$downloadUrl = $baseLocation + $driverPath
|
||||
$driverFileName = [System.IO.Path]::GetFileName($driverPath)
|
||||
$name = $component.Name.Display.'#cdata-section' -replace '[\\\/\:\*\?\"\<\>\| ]','_' -replace '[\,]','-'
|
||||
$category = $component.Category.Display.'#cdata-section' -replace '[\\\/\:\*\?\"\<\>\| ]','_'
|
||||
$name = $component.Name.Display.'#cdata-section' -replace '[\\\/\:\*\?\"\<\>\| ]', '_' -replace '[\,]', '-'
|
||||
$category = $component.Category.Display.'#cdata-section' -replace '[\\\/\:\*\?\"\<\>\| ]', '_'
|
||||
$version = [version]$component.vendorVersion
|
||||
$namePrefix = ($name -split '-')[0]
|
||||
if (-not $latestDrivers[$category]) { $latestDrivers[$category] = @{} }
|
||||
|
||||
@@ -231,4 +231,50 @@ function Get-DellLatestDriverPackages {
|
||||
return $chosen
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function Convert-DellVendorVersion,Compare-DellVendorVersion,Get-DellCatalogIndex,Get-DellClientModels,Get-DellLatestDriverPackages
|
||||
# Resolve a Dell per‑model CabUrl when missing by inspecting CatalogIndexPC
|
||||
function Resolve-DellCabUrlFromModel {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$DriversFolder,
|
||||
[Parameter()][string]$ModelDisplay,
|
||||
[Parameter()][string]$SystemId
|
||||
)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($SystemId) -and -not [string]::IsNullOrWhiteSpace($ModelDisplay)) {
|
||||
# Try to parse the trailing (XXXX) token (SystemId)
|
||||
if ($ModelDisplay -match '\(([0-9A-Fa-f]{4})\)\s*$') {
|
||||
$SystemId = $matches[1].ToUpperInvariant()
|
||||
}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($SystemId)) {
|
||||
WriteLog "Resolve-DellCabUrlFromModel: No SystemId could be determined from '$ModelDisplay'."
|
||||
return $null
|
||||
}
|
||||
|
||||
try {
|
||||
$indexXml = Get-DellCatalogIndex -DriversFolder $DriversFolder
|
||||
# Reuse existing model parsing to avoid duplicating streaming logic
|
||||
$allModels = Get-DellClientModels -CatalogIndexXmlPath $indexXml
|
||||
$match = $allModels | Where-Object { $_.SystemId -eq $SystemId } | Select-Object -First 1
|
||||
if ($null -eq $match) {
|
||||
WriteLog "Resolve-DellCabUrlFromModel: SystemId '$SystemId' not found in CatalogIndexPC.xml."
|
||||
return $null
|
||||
}
|
||||
WriteLog "Resolve-DellCabUrlFromModel: Resolved CabUrl for '$($match.ModelDisplay)' -> $($match.CabUrl)"
|
||||
return [pscustomobject]@{
|
||||
Brand = $match.Brand
|
||||
ModelNumber = $match.ModelNumber
|
||||
SystemId = $match.SystemId
|
||||
CabRelativePath = $match.CabRelativePath
|
||||
CabUrl = $match.CabUrl
|
||||
ModelDisplay = $match.ModelDisplay
|
||||
}
|
||||
}
|
||||
catch {
|
||||
WriteLog "Resolve-DellCabUrlFromModel: Failure resolving CabUrl for '$ModelDisplay' / SystemId '$SystemId' : $($_.Exception.Message)"
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function Convert-DellVendorVersion,Compare-DellVendorVersion,Get-DellCatalogIndex,Get-DellClientModels,Get-DellLatestDriverPackages,Resolve-DellCabUrlFromModel
|
||||
@@ -182,75 +182,35 @@ function Save-DellDriversTask {
|
||||
if ($WindowsRelease -le 11) {
|
||||
$cabUrl = $DriverItemData.CabUrl
|
||||
if ([string]::IsNullOrWhiteSpace($cabUrl)) {
|
||||
WriteLog "CabUrl missing for '$modelDisplay' – falling back to legacy CatalogPC parsing."
|
||||
# Fallback legacy client method
|
||||
$catalogCab = Join-Path $makeDriversPath 'CatalogPC.cab'
|
||||
$catalogXml = Join-Path $makeDriversPath 'CatalogPC.xml'
|
||||
$catalogUrl = 'http://downloads.dell.com/catalog/CatalogPC.cab'
|
||||
$need = $true
|
||||
if (Test-Path $catalogXml) {
|
||||
if (((Get-Date) - (Get-Item $catalogXml).CreationTime).TotalDays -lt 7) { $need = $false }
|
||||
WriteLog "CabUrl missing for '$modelDisplay' – resolving via CatalogIndexPC."
|
||||
$resolved = Resolve-DellCabUrlFromModel -DriversFolder $DriversFolder -ModelDisplay $modelDisplay
|
||||
if ($null -eq $resolved -or [string]::IsNullOrWhiteSpace($resolved.CabUrl)) {
|
||||
throw "Unable to resolve CabUrl for $modelDisplay from CatalogIndexPC."
|
||||
}
|
||||
if ($need) {
|
||||
if (Test-Path $catalogCab) { Remove-SafeFolder $catalogCab }
|
||||
if (Test-Path $catalogXml) { Remove-SafeFolder $catalogXml }
|
||||
Start-BitsTransferWithRetry -Source $catalogUrl -Destination $catalogCab
|
||||
Invoke-Process -FilePath Expand.exe -ArgumentList """$catalogCab"" ""$catalogXml""" | Out-Null
|
||||
Remove-Item $catalogCab -Force -ErrorAction SilentlyContinue
|
||||
$cabUrl = $resolved.CabUrl
|
||||
# Optionally persist back into the incoming object if property exists
|
||||
if ($DriverItemData.PSObject.Properties['CabUrl']) {
|
||||
$DriverItemData.CabUrl = $cabUrl
|
||||
}
|
||||
if (-not (Test-Path $catalogXml)) { throw "Legacy fallback failed; missing $catalogXml" }
|
||||
[xml]$xmlContent = Get-Content -Path $catalogXml -Raw
|
||||
$baseLocation = "https://$($xmlContent.manifest.baseLocation)/"
|
||||
$softwareComponents = $xmlContent.Manifest.SoftwareComponent | Where-Object { $_.ComponentType.value -eq 'DRVR' }
|
||||
|
||||
$latestDrivers = @{}
|
||||
foreach ($component in $softwareComponents) {
|
||||
$models = $component.SupportedSystems.Brand.Model
|
||||
foreach ($m in $models) {
|
||||
if ($m.Display.'#cdata-section' -eq $modelDisplay) {
|
||||
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { $_.osArch -eq $WindowsArch }
|
||||
if (-not $validOS) { continue }
|
||||
$driverPath = $component.path
|
||||
$downloadUrl = $baseLocation + $driverPath
|
||||
$fileName = [IO.Path]::GetFileName($driverPath)
|
||||
$name = $component.Name.Display.'#cdata-section' -replace '[\\\/\:\*\?\"\<\>\| ]','_' -replace '[\,]','-'
|
||||
$category = $component.Category.Display.'#cdata-section' -replace '[\\\/\:\*\?\"\<\>\| ]','_'
|
||||
$version = [version]$component.vendorVersion
|
||||
$namePrefix = ($name -split '-')[0]
|
||||
if (-not $latestDrivers[$category]) { $latestDrivers[$category] = @{} }
|
||||
if (-not $latestDrivers[$category][$namePrefix] -or $latestDrivers[$category][$namePrefix].Version -lt $version) {
|
||||
$latestDrivers[$category][$namePrefix] = [pscustomobject]@{
|
||||
Name = $name
|
||||
DownloadUrl = $downloadUrl
|
||||
DriverFileName = $fileName
|
||||
Version = $version
|
||||
Category = $category
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($cat in $latestDrivers.Keys) { foreach ($drv in $latestDrivers[$cat].Values) { $packages += $drv } }
|
||||
}
|
||||
else {
|
||||
# Normal new model-based workflow
|
||||
$modelCabName = [IO.Path]::GetFileName($cabUrl)
|
||||
if ([string]::IsNullOrWhiteSpace($modelCabName)) { throw "Derived model cab name empty for $modelDisplay" }
|
||||
$modelCabPath = Join-Path $makeDriversPath $modelCabName
|
||||
$modelXmlPath = Join-Path $makeDriversPath ([IO.Path]::GetFileNameWithoutExtension($modelCabName) + '.xml')
|
||||
|
||||
if ($null -ne $ProgressQueue) { Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $modelDisplay -Status 'Downloading catalog...' }
|
||||
if (Test-Path $modelCabPath) { Remove-SafeFolder $modelCabPath }
|
||||
if (Test-Path $modelXmlPath) { Remove-SafeFolder $modelXmlPath }
|
||||
|
||||
Start-BitsTransferWithRetry -Source $cabUrl -Destination $modelCabPath
|
||||
Invoke-Process -FilePath Expand.exe -ArgumentList """$modelCabPath"" ""$modelXmlPath""" | Out-Null
|
||||
Remove-Item $modelCabPath -Force -ErrorAction SilentlyContinue
|
||||
if (-not (Test-Path $modelXmlPath)) { throw "Model XML not found after extraction: $modelXmlPath" }
|
||||
|
||||
if ($null -ne $ProgressQueue) { Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $modelDisplay -Status 'Selecting latest drivers...' }
|
||||
$packages = Get-DellLatestDriverPackages -ModelXmlPath $modelXmlPath -WindowsArch $WindowsArch -WindowsRelease $WindowsRelease
|
||||
}
|
||||
|
||||
# Model-based workflow (always used for client pathway now)
|
||||
$modelCabName = [IO.Path]::GetFileName($cabUrl)
|
||||
if ([string]::IsNullOrWhiteSpace($modelCabName)) { throw "Derived model cab name empty for $modelDisplay" }
|
||||
$modelCabPath = Join-Path $makeDriversPath $modelCabName
|
||||
$modelXmlPath = Join-Path $makeDriversPath ([IO.Path]::GetFileNameWithoutExtension($modelCabName) + '.xml')
|
||||
|
||||
if ($null -ne $ProgressQueue) { Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $modelDisplay -Status 'Downloading catalog...' }
|
||||
if (Test-Path $modelCabPath) { Remove-SafeFolder $modelCabPath }
|
||||
if (Test-Path $modelXmlPath) { Remove-SafeFolder $modelXmlPath }
|
||||
|
||||
Start-BitsTransferWithRetry -Source $cabUrl -Destination $modelCabPath
|
||||
Invoke-Process -FilePath Expand.exe -ArgumentList """$modelCabPath"" ""$modelXmlPath""" | Out-Null
|
||||
Remove-Item $modelCabPath -Force -ErrorAction SilentlyContinue
|
||||
if (-not (Test-Path $modelXmlPath)) { throw "Model XML not found after extraction: $modelXmlPath" }
|
||||
|
||||
if ($null -ne $ProgressQueue) { Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $modelDisplay -Status 'Selecting latest drivers...' }
|
||||
$packages = Get-DellLatestDriverPackages -ModelXmlPath $modelXmlPath -WindowsArch $WindowsArch -WindowsRelease $WindowsRelease
|
||||
}
|
||||
else {
|
||||
# Server legacy logic unchanged (kept as before)
|
||||
|
||||
@@ -225,6 +225,15 @@ function Save-DriversJson {
|
||||
$modelObject = @{
|
||||
Name = $driverItem.Model
|
||||
}
|
||||
if ($driverItem.PSObject.Properties['SystemId'] -and -not [string]::IsNullOrWhiteSpace($driverItem.SystemId)) {
|
||||
$modelObject.SystemId = $driverItem.SystemId
|
||||
}
|
||||
if ($driverItem.PSObject.Properties['CabUrl'] -and -not [string]::IsNullOrWhiteSpace($driverItem.CabUrl)) {
|
||||
$modelObject.CabUrl = $driverItem.CabUrl
|
||||
}
|
||||
if ($driverItem.PSObject.Properties['CabRelativePath'] -and -not [string]::IsNullOrWhiteSpace($driverItem.CabRelativePath)) {
|
||||
$modelObject.CabRelativePath = $driverItem.CabRelativePath
|
||||
}
|
||||
}
|
||||
'HP' {
|
||||
$modelObject = @{
|
||||
@@ -337,7 +346,7 @@ function Import-DriversJson {
|
||||
if ($null -ne $existingModel) {
|
||||
$existingModel.IsSelected = $true
|
||||
$existingModel.DownloadStatus = "Imported"
|
||||
|
||||
|
||||
if ($makeName -eq 'Microsoft' -and $importedModelObject.PSObject.Properties['Link']) {
|
||||
if ($existingModel.Link -ne $importedModelObject.Link) {
|
||||
$existingModel.Link = $importedModelObject.Link
|
||||
@@ -352,13 +361,35 @@ function Import-DriversJson {
|
||||
}
|
||||
if ($importedModelObject.PSObject.Properties['MachineType'] -and $existingModel.PSObject.Properties['MachineType'] -and $existingModel.MachineType -ne $importedModelObject.MachineType) {
|
||||
$existingModel.MachineType = $importedModelObject.MachineType
|
||||
$existingModel.Id = $importedModelObject.MachineType # Update Id as well
|
||||
$existingModel.Id = $importedModelObject.MachineType
|
||||
$updateExistingLenovo = $true
|
||||
}
|
||||
if ($updateExistingLenovo) {
|
||||
WriteLog "Import-DriversJson: Updated ProductName/MachineType/Id for existing Lenovo model '$($existingModel.Model)'."
|
||||
}
|
||||
}
|
||||
elseif ($makeName -eq 'Dell') {
|
||||
# Update Dell extended fields if provided
|
||||
if ($importedModelObject.PSObject.Properties['SystemId'] -and $existingModel.PSObject.Properties['SystemId'] -and -not [string]::IsNullOrWhiteSpace($importedModelObject.SystemId)) {
|
||||
if ($existingModel.SystemId -ne $importedModelObject.SystemId) {
|
||||
$existingModel.SystemId = $importedModelObject.SystemId
|
||||
WriteLog "Import-DriversJson: Updated SystemId for existing Dell model '$($existingModel.Model)'."
|
||||
}
|
||||
}
|
||||
if ($importedModelObject.PSObject.Properties['CabUrl'] -and $existingModel.PSObject.Properties['CabUrl'] -and -not [string]::IsNullOrWhiteSpace($importedModelObject.CabUrl)) {
|
||||
if ($existingModel.CabUrl -ne $importedModelObject.CabUrl) {
|
||||
$existingModel.CabUrl = $importedModelObject.CabUrl
|
||||
WriteLog "Import-DriversJson: Updated CabUrl for existing Dell model '$($existingModel.Model)'."
|
||||
}
|
||||
}
|
||||
if ($importedModelObject.PSObject.Properties['CabRelativePath'] -and $existingModel.PSObject.Properties['CabRelativePath'] -and -not [string]::IsNullOrWhiteSpace($importedModelObject.CabRelativePath)) {
|
||||
if ($existingModel.CabRelativePath -ne $importedModelObject.CabRelativePath) {
|
||||
$existingModel.CabRelativePath = $importedModelObject.CabRelativePath
|
||||
WriteLog "Import-DriversJson: Updated CabRelativePath for existing Dell model '$($existingModel.Model)'."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$existingModelsUpdated++
|
||||
WriteLog "Import-DriversJson: Marked existing model '$($existingModel.Make) - $($existingModel.Model)' as imported."
|
||||
}
|
||||
@@ -395,7 +426,7 @@ function Import-DriversJson {
|
||||
$newDriverModel = [PSCustomObject]@{
|
||||
IsSelected = $true
|
||||
Make = $makeName
|
||||
Model = $importedModelNameFromObject # Full display name
|
||||
Model = $importedModelNameFromObject
|
||||
Link = $importedLink
|
||||
Id = $importedId
|
||||
ProductName = $importedProductName
|
||||
@@ -406,6 +437,18 @@ function Import-DriversJson {
|
||||
Arch = ""
|
||||
DownloadStatus = "Imported"
|
||||
}
|
||||
if ($makeName -eq 'Dell') {
|
||||
# Attach optional Dell extended fields if present
|
||||
if ($importedModelObject.PSObject.Properties['SystemId'] -and -not [string]::IsNullOrWhiteSpace($importedModelObject.SystemId)) {
|
||||
$newDriverModel | Add-Member -NotePropertyName SystemId -NotePropertyValue $importedModelObject.SystemId
|
||||
}
|
||||
if ($importedModelObject.PSObject.Properties['CabUrl'] -and -not [string]::IsNullOrWhiteSpace($importedModelObject.CabUrl)) {
|
||||
$newDriverModel | Add-Member -NotePropertyName CabUrl -NotePropertyValue $importedModelObject.CabUrl
|
||||
}
|
||||
if ($importedModelObject.PSObject.Properties['CabRelativePath'] -and -not [string]::IsNullOrWhiteSpace($importedModelObject.CabRelativePath)) {
|
||||
$newDriverModel | Add-Member -NotePropertyName CabRelativePath -NotePropertyValue $importedModelObject.CabRelativePath
|
||||
}
|
||||
}
|
||||
$State.Data.allDriverModels.Add($newDriverModel)
|
||||
$newModelsAdded++
|
||||
WriteLog "Import-DriversJson: Added new model '$($newDriverModel.Make) - $($newDriverModel.Model)' from import. ID: $($newDriverModel.Id), Link: $($newDriverModel.Link)"
|
||||
@@ -753,7 +796,16 @@ function Invoke-DownloadSelectedDrivers {
|
||||
}
|
||||
'Dell' {
|
||||
$modelObject = @{
|
||||
Name = $driverItem.Model # Model is the display name
|
||||
Name = $driverItem.Model
|
||||
}
|
||||
if ($driverItem.PSObject.Properties['SystemId'] -and -not [string]::IsNullOrWhiteSpace($driverItem.SystemId)) {
|
||||
$modelObject.SystemId = $driverItem.SystemId
|
||||
}
|
||||
if ($driverItem.PSObject.Properties['CabUrl'] -and -not [string]::IsNullOrWhiteSpace($driverItem.CabUrl)) {
|
||||
$modelObject.CabUrl = $driverItem.CabUrl
|
||||
}
|
||||
if ($driverItem.PSObject.Properties['CabRelativePath'] -and -not [string]::IsNullOrWhiteSpace($driverItem.CabRelativePath)) {
|
||||
$modelObject.CabRelativePath = $driverItem.CabRelativePath
|
||||
}
|
||||
}
|
||||
'HP' {
|
||||
|
||||
Reference in New Issue
Block a user