mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
Improves Winget installer selection logic
Refines the post-download cleanup process for applications with multiple installers. When multiple installers are downloaded for an application, this change introduces logic to select the most appropriate one based on the target Windows architecture. It prioritizes universal installers first, then architecture-specific installers, before falling back to the previous method of selecting the newest file by signature date. This ensures a more accurate installer is chosen, especially when Winget provides multiple architecture options for a single package.
This commit is contained in:
@@ -163,6 +163,7 @@ function Invoke-ParallelProcessing {
|
|||||||
AppsPath = $localJobArgs['AppsPath']
|
AppsPath = $localJobArgs['AppsPath']
|
||||||
OrchestrationPath = $localJobArgs['OrchestrationPath']
|
OrchestrationPath = $localJobArgs['OrchestrationPath']
|
||||||
ProgressQueue = $localProgressQueue
|
ProgressQueue = $localProgressQueue
|
||||||
|
SelectedWindowsArch = $localJobArgs['SelectedWindowsArch']
|
||||||
}
|
}
|
||||||
$taskResult = Start-WingetAppDownloadTask @wingetTaskArgs
|
$taskResult = Start-WingetAppDownloadTask @wingetTaskArgs
|
||||||
if ($null -ne $taskResult) {
|
if ($null -ne $taskResult) {
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ function Get-Application {
|
|||||||
[string]$WindowsArch,
|
[string]$WindowsArch,
|
||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
[string]$OrchestrationPath,
|
[string]$OrchestrationPath,
|
||||||
[switch]$SkipWin32Json
|
[switch]$SkipWin32Json,
|
||||||
|
[string]$SelectedWindowsArch
|
||||||
)
|
)
|
||||||
|
|
||||||
# Block Company Portal from winget source
|
# Block Company Portal from winget source
|
||||||
@@ -252,15 +253,52 @@ function Get-Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Clean up multiple versions (keep only the latest)
|
# Clean up multiple versions honoring SelectedWindowsArch (keep only one installer)
|
||||||
WriteLog "$AppName has completed downloading. Identifying the latest version of $AppName."
|
WriteLog "$AppName has completed downloading. Evaluating installer set for pruning."
|
||||||
$packages = Get-ChildItem -Path "$appFolderPath\*" -Exclude "Dependencies\*", "*.xml", "*.yaml" -File -ErrorAction Stop
|
$packages = Get-ChildItem -Path "$appFolderPath\*" -Exclude "Dependencies\*", "*.xml", "*.yaml" -File -ErrorAction Stop
|
||||||
|
if ($packages.Count -gt 1 -and $SelectedWindowsArch) {
|
||||||
# Find latest version based on signature date
|
WriteLog "SelectedWindowsArch provided for pruning: $SelectedWindowsArch"
|
||||||
$latestPackage = $packages | Sort-Object { (Get-AuthenticodeSignature $_.FullName).SignerCertificate.NotBefore } -Descending | Select-Object -First 1
|
# Detect universal bundles (contain x86,x64,arm64 in name)
|
||||||
|
$universalCandidates = $packages | Where-Object {
|
||||||
# Remove older versions
|
$base = $_.BaseName
|
||||||
WriteLog "Latest version of $AppName has been identified as $latestPackage. Removing old versions of $AppName that may have downloaded."
|
# Split base name into tokens to avoid partial matches (e.g. arm inside arm64)
|
||||||
|
$tokens = ($base -split '[\.\-_]') | ForEach-Object { $_.ToLower() }
|
||||||
|
# Architecture tokens we recognize
|
||||||
|
$archTokens = @('x86', 'x64', 'arm', 'arm64')
|
||||||
|
# Distinct matched architecture tokens
|
||||||
|
$matched = $tokens | Where-Object { $_ -in $archTokens } | Select-Object -Unique
|
||||||
|
if ($matched.Count -ge 2) {
|
||||||
|
WriteLog "Multi-architecture bundle detected: $base (tokens: $($matched -join ', '))"
|
||||||
|
$true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($universalCandidates) {
|
||||||
|
WriteLog "Universal bundle candidate(s) detected: $($universalCandidates.Name -join ', ')"
|
||||||
|
$candidateSet = $universalCandidates
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$archToken = switch -Regex ($SelectedWindowsArch.ToLower()) {
|
||||||
|
'^x64$' { 'x64' ; break }
|
||||||
|
'^x86$' { 'x86' ; break }
|
||||||
|
'^arm64$' { 'arm64' ; break }
|
||||||
|
default { $SelectedWindowsArch.ToLower() }
|
||||||
|
}
|
||||||
|
$archMatches = $packages | Where-Object { $_.BaseName -match "(?i)$archToken" }
|
||||||
|
if ($archMatches) {
|
||||||
|
WriteLog "Architecture-specific candidates matching '$archToken': $($archMatches.Name -join ', ')"
|
||||||
|
$candidateSet = $archMatches
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WriteLog "No installer filename matched '$archToken'. Falling back to all installers."
|
||||||
|
$candidateSet = $packages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# From candidate set, choose latest by signature date
|
||||||
|
$latestPackage = $candidateSet | Sort-Object { (Get-AuthenticodeSignature $_.FullName).SignerCertificate.NotBefore } -Descending | Select-Object -First 1
|
||||||
|
WriteLog "Retaining installer: $($latestPackage.Name)"
|
||||||
foreach ($package in $packages) {
|
foreach ($package in $packages) {
|
||||||
if ($package.FullName -ne $latestPackage.FullName) {
|
if ($package.FullName -ne $latestPackage.FullName) {
|
||||||
try {
|
try {
|
||||||
@@ -274,6 +312,27 @@ function Get-Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elseif ($packages.Count -gt 1) {
|
||||||
|
WriteLog "Multiple installers present but no SelectedWindowsArch supplied. Using original latest-version logic."
|
||||||
|
$latestPackage = $packages | Sort-Object { (Get-AuthenticodeSignature $_.FullName).SignerCertificate.NotBefore } -Descending | Select-Object -First 1
|
||||||
|
WriteLog "Retaining latest by signature date: $($latestPackage.Name)"
|
||||||
|
foreach ($package in $packages) {
|
||||||
|
if ($package.FullName -ne $latestPackage.FullName) {
|
||||||
|
try {
|
||||||
|
WriteLog "Removing $($package.FullName)"
|
||||||
|
Remove-Item -Path $package.FullName -Force
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
WriteLog "Failed to delete: $($package.FullName) - $_"
|
||||||
|
throw $_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WriteLog "Single installer present; no pruning required."
|
||||||
|
}
|
||||||
|
}
|
||||||
} # End foreach ($arch in $architecturesToDownload)
|
} # End foreach ($arch in $architecturesToDownload)
|
||||||
|
|
||||||
return $overallResult
|
return $overallResult
|
||||||
@@ -348,7 +407,7 @@ function Get-Apps {
|
|||||||
foreach ($storeApp in $StoreApps) {
|
foreach ($storeApp in $StoreApps) {
|
||||||
try {
|
try {
|
||||||
$appArch = if ($storeApp.PSObject.Properties['architecture']) { $storeApp.architecture } else { $WindowsArch }
|
$appArch = if ($storeApp.PSObject.Properties['architecture']) { $storeApp.architecture } else { $WindowsArch }
|
||||||
Get-Application -AppName $storeApp.Name -AppId $storeApp.Id -Source 'msstore' -AppsPath $AppsPath -WindowsArch $appArch -OrchestrationPath $OrchestrationPath
|
Get-Application -AppName $storeApp.Name -AppId $storeApp.Id -Source 'msstore' -AppsPath $AppsPath -WindowsArch $appArch -OrchestrationPath $OrchestrationPath -SelectedWindowsArch $WindowsArch
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
WriteLog "Error occurred while processing $($storeApp.Name): $_"
|
WriteLog "Error occurred while processing $($storeApp.Name): $_"
|
||||||
|
|||||||
@@ -385,7 +385,8 @@ function Start-WingetAppDownloadTask {
|
|||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
[string]$OrchestrationPath,
|
[string]$OrchestrationPath,
|
||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
[System.Collections.Concurrent.ConcurrentQueue[hashtable]]$ProgressQueue # Add queue parameter
|
[System.Collections.Concurrent.ConcurrentQueue[hashtable]]$ProgressQueue, # Add queue parameter
|
||||||
|
[string]$SelectedWindowsArch
|
||||||
)
|
)
|
||||||
|
|
||||||
$appName = $ApplicationItemData.Name
|
$appName = $ApplicationItemData.Name
|
||||||
@@ -398,10 +399,6 @@ function Start-WingetAppDownloadTask {
|
|||||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appId -Status $status
|
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appId -Status $status
|
||||||
|
|
||||||
WriteLog "Starting download task for $($appName) with ID $($appId) from source $($source)."
|
WriteLog "Starting download task for $($appName) with ID $($appId) from source $($source)."
|
||||||
# WriteLog "Apps Path: $($AppsPath)"
|
|
||||||
# WriteLog "AppList JSON Path: $($AppListJsonPath)"
|
|
||||||
# WriteLog "Windows Architecture: $($ApplicationItemData.Architecture)"
|
|
||||||
# WriteLog "Orchestration Path: $($OrchestrationPath)"
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# Define paths
|
# Define paths
|
||||||
@@ -599,7 +596,7 @@ function Start-WingetAppDownloadTask {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
# Call Get-Application
|
# Call Get-Application
|
||||||
$resultCode = Get-Application -AppName $appName -AppId $appId -Source $source -AppsPath $AppsPath -WindowsArch $ApplicationItemData.Architecture -OrchestrationPath $OrchestrationPath -SkipWin32Json -ErrorAction Stop
|
$resultCode = Get-Application -AppName $appName -AppId $appId -Source $source -AppsPath $AppsPath -WindowsArch $ApplicationItemData.Architecture -OrchestrationPath $OrchestrationPath -SkipWin32Json -SelectedWindowsArch $SelectedWindowsArch -ErrorAction Stop
|
||||||
|
|
||||||
# Determine status based on result code
|
# Determine status based on result code
|
||||||
switch ($resultCode) {
|
switch ($resultCode) {
|
||||||
@@ -721,6 +718,7 @@ function Invoke-WingetDownload {
|
|||||||
AppsPath = $localAppsPath
|
AppsPath = $localAppsPath
|
||||||
AppListJsonPath = $localAppListJsonPath
|
AppListJsonPath = $localAppListJsonPath
|
||||||
OrchestrationPath = $localOrchestrationPath
|
OrchestrationPath = $localOrchestrationPath
|
||||||
|
SelectedWindowsArch = $localWindowsArch
|
||||||
}
|
}
|
||||||
|
|
||||||
# Select only necessary properties before passing to Invoke-ParallelProcessing
|
# Select only necessary properties before passing to Invoke-ParallelProcessing
|
||||||
|
|||||||
Reference in New Issue
Block a user