feat: Add per-app architecture selection and multi-arch downloads

Introduces the ability to specify and download multiple architectures for a single application.

- Adds an "Architecture" dropdown column to the Winget UI, allowing users to select the desired architecture(s) for each app (e.g., x86, x64, arm64, or 'x86 x64').
- Updates the download logic to process each specified architecture, creating separate subfolders for multi-architecture Win32 apps.
- Modifies the app list format to save and load the selected architecture for each application.
- Improves the download process by checking if an application has already been downloaded before attempting a new download.
This commit is contained in:
rbalsleyMSFT
2025-07-18 20:12:05 -07:00
parent 9df663dc9b
commit 721f93d82d
4 changed files with 243 additions and 149 deletions
@@ -157,12 +157,14 @@ function Invoke-ParallelProcessing {
switch ($localTaskType) { switch ($localTaskType) {
'WingetDownload' { 'WingetDownload' {
# Pass the progress queue to the task function # Pass the progress queue to the task function
$taskResult = Start-WingetAppDownloadTask -ApplicationItemData $currentItem ` $wingetTaskArgs = @{
-AppListJsonPath $localJobArgs['AppListJsonPath'] ` ApplicationItemData = $currentItem
-AppsPath $localJobArgs['AppsPath'] ` AppListJsonPath = $localJobArgs['AppListJsonPath']
-WindowsArch $localJobArgs['WindowsArch'] ` AppsPath = $localJobArgs['AppsPath']
-OrchestrationPath $localJobArgs['OrchestrationPath'] ` OrchestrationPath = $localJobArgs['OrchestrationPath']
-ProgressQueue $localProgressQueue ProgressQueue = $localProgressQueue
}
$taskResult = Start-WingetAppDownloadTask @wingetTaskArgs
if ($null -ne $taskResult) { if ($null -ne $taskResult) {
$resultIdentifier = $taskResult.Id $resultIdentifier = $taskResult.Id
$resultStatus = $taskResult.Status $resultStatus = $taskResult.Status
@@ -25,6 +25,26 @@ function Get-Application {
[string]$OrchestrationPath [string]$OrchestrationPath
) )
# Determine base folder path for checking existence
$appIsWin32ForCheck = ($Source -eq 'msstore' -and $AppId.StartsWith("XP"))
$appBaseFolderPathForCheck = ""
if ($Source -eq 'winget' -or $appIsWin32ForCheck) {
$appBaseFolderPathForCheck = Join-Path -Path "$AppsPath\Win32" -ChildPath $AppName
}
else {
$appBaseFolderPathForCheck = Join-Path -Path "$AppsPath\MSStore" -ChildPath $AppName
}
# Check if the app (any architecture) has already been downloaded by checking for its content folder.
# This prevents re-downloading if BuildFFUVM.ps1 is run after downloading via the UI.
if (Test-Path -Path $appBaseFolderPathForCheck -PathType Container) {
# Check if the folder is not empty.
if (Get-ChildItem -Path $appBaseFolderPathForCheck -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1) {
WriteLog "Application '$AppName' appears to be already downloaded as content exists in '$appBaseFolderPathForCheck'. Skipping download."
return 0 # Success, already present
}
}
# Validate app exists in repository # Validate app exists in repository
$wingetSearchResult = Find-WinGetPackage -id $AppId -MatchOption Equals -Source $Source $wingetSearchResult = Find-WinGetPackage -id $AppId -MatchOption Equals -Source $Source
if (-not $wingetSearchResult) { if (-not $wingetSearchResult) {
@@ -34,36 +54,51 @@ function Get-Application {
} }
WriteLog "$AppName not found in $Source repository." WriteLog "$AppName not found in $Source repository."
WriteLog "Check the AppList.json file and make sure the AppID is correct." WriteLog "Check the AppList.json file and make sure the AppID is correct."
Exit 1 return 1 # Return error code
} }
# Determine architectures to download
$architecturesToDownload = if ($WindowsArch -eq 'x86 x64') { @('x86', 'x64') } else { @($WindowsArch) }
$overallResult = 0
foreach ($arch in $architecturesToDownload) {
WriteLog "Processing '$AppName' for architecture '$arch'."
# Determine app type and folder path # Determine app type and folder path
$appIsWin32 = ($Source -eq 'msstore' -and $AppId.StartsWith("XP")) $appIsWin32 = ($Source -eq 'msstore' -and $AppId.StartsWith("XP"))
if ($Source -eq 'winget' -or $appIsWin32) { if ($Source -eq 'winget' -or $appIsWin32) {
$appFolderPath = Join-Path -Path "$AppsPath\Win32" -ChildPath $AppName $appBaseFolderPath = Join-Path -Path "$AppsPath\Win32" -ChildPath $AppName
} }
else { else {
$appFolderPath = Join-Path -Path "$AppsPath\MSStore" -ChildPath $AppName $appBaseFolderPath = Join-Path -Path "$AppsPath\MSStore" -ChildPath $AppName
}
# If downloading multiple archs for a Win32 app, create a subfolder
$appFolderPath = $appBaseFolderPath
$subFolderForCommand = $null
if ($architecturesToDownload.Count -gt 1 -and ($Source -eq 'winget' -or $appIsWin32)) {
$appFolderPath = Join-Path -Path $appBaseFolderPath -ChildPath $arch
$subFolderForCommand = $arch
} }
# Create app folder # Create app folder
New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null
# Log download information # Log download information
WriteLog "Downloading $AppName for $WindowsArch architecture..." WriteLog "Downloading $AppName for $arch architecture..."
if ($Source -eq 'msstore') { if ($Source -eq 'msstore') {
WriteLog 'MSStore app downloads require authentication with an Entra ID account. You may be prompted twice for credentials, once for the app and another for the license file.' WriteLog 'MSStore app downloads require authentication with an Entra ID account. You may be prompted twice for credentials, once for the app and another for the license file.'
} }
WriteLog "WinGet command: Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Architecture $WindowsArch -Source $Source" WriteLog "WinGet command: Export-WinGetPackage -id $AppId -DownloadDirectory `"$appFolderPath`" -Architecture $arch -Source $Source"
# Download the app # Download the app
$wingetDownloadResult = Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Architecture $WindowsArch -Source $Source $wingetDownloadResult = Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Architecture $arch -Source $Source
# Handle download status # Handle download status
if ($wingetDownloadResult.status -ne 'Ok') { if ($wingetDownloadResult.status -ne 'Ok') {
# Try downloading without architecture if no applicable installer found # Try downloading without architecture if no applicable installer found
if ($wingetDownloadResult.status -eq 'NoApplicableInstallers' -or $wingetDownloadResult.status -eq 'NoApplicableInstallerFound') { if ($wingetDownloadResult.status -eq 'NoApplicableInstallers' -or $wingetDownloadResult.status -eq 'NoApplicableInstallerFound') {
WriteLog "No installer found for $WindowsArch architecture. Attempting to download without specifying architecture..." WriteLog "No installer found for $arch architecture. Attempting to download without specifying architecture..."
$wingetDownloadResult = Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Source $Source $wingetDownloadResult = Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Source $Source
if ($wingetDownloadResult.status -eq 'Ok') { if ($wingetDownloadResult.status -eq 'Ok') {
WriteLog "Downloaded $AppName without specifying architecture." WriteLog "Downloaded $AppName without specifying architecture."
@@ -71,17 +106,18 @@ function Get-Application {
else { else {
WriteLog "ERROR: No installer found for $AppName. Exiting" WriteLog "ERROR: No installer found for $AppName. Exiting"
Remove-Item -Path $appFolderPath -Recurse -Force Remove-Item -Path $appFolderPath -Recurse -Force
Exit 1 return 1 # Return error code
} }
} }
# Handle Store-specific errors # Handle Store-specific errors
elseif ($Source -eq 'msstore') { elseif ($Source -eq 'msstore') {
# If download not supported by publisher # If download not supported by publisher
if ($wingetDownloadResult.ExtendedErrorCode -match '0x8A150084') { if ($wingetDownloadResult.ExtendedErrorCode -match '0x8A150084') {
WriteLog "ERROR: The Microsoft Store app $AppName does not support downloads by the publisher. Please remove it from the AppList.json. If there's a winget source version of the application, try using that instead. Exiting." $errorMessage = "ERROR: The Microsoft Store app $AppName does not support downloads by the publisher. Please remove it from the AppList.json. If there's a winget source version of the application, try using that instead. Exiting."
WriteLog $errorMessage
Remove-Item -Path $appFolderPath -Recurse -Force Remove-Item -Path $appFolderPath -Recurse -Force
Write-Error "ERROR: The Microsoft Store app $AppName does not support downloads by the publisher. Please remove it from the AppList.json. If there's a winget source version of the application, try using that instead. Exiting." Write-Error $errorMessage
Exit 1 return 1 # Return error code
} }
} }
else { else {
@@ -89,11 +125,11 @@ function Get-Application {
WriteLog $errormsg WriteLog $errormsg
Remove-Item -Path $appFolderPath -Recurse -Force Remove-Item -Path $appFolderPath -Recurse -Force
Write-Error $errormsg Write-Error $errormsg
Exit 1 return 1 # Return error code
} }
} }
WriteLog "$AppName downloaded to $appFolderPath" WriteLog "$AppName ($arch) downloaded to $appFolderPath"
# Handle winget source apps that have appx, appxbundle, msix, or msixbundle extensions but were downloaded to the Win32 folder # Handle winget source apps that have appx, appxbundle, msix, or msixbundle extensions but were downloaded to the Win32 folder
$installerPath = Get-ChildItem -Path "$appFolderPath\*" -Exclude "*.yaml", "*.xml" -File -ErrorAction Stop $installerPath = Get-ChildItem -Path "$appFolderPath\*" -Exclude "*.yaml", "*.xml" -File -ErrorAction Stop
@@ -110,25 +146,24 @@ function Get-Application {
WriteLog "Removing $appFolderPath" WriteLog "Removing $appFolderPath"
Remove-Item -Path $appFolderPath -Force -Recurse Remove-Item -Path $appFolderPath -Force -Recurse
WriteLog "$AppName moved to $NewAppPath" WriteLog "$AppName moved to $NewAppPath"
# Set-InstallStoreAppsFlag
$result = 0 # Success for UWP app $result = 0 # Success for UWP app
} }
# If app is in Win32 folder, add the silent install command to the WinGetWin32Apps.json file # If app is in Win32 folder, add the silent install command to the WinGetWin32Apps.json file
elseif ($appFolderPath -match 'Win32') { elseif ($appFolderPath -match 'Win32') {
WriteLog "$AppName is a Win32 app. Adding silent install command to $OrchestrationPath\WinGetWin32Apps.json" WriteLog "$AppName is a Win32 app. Adding silent install command to $OrchestrationPath\WinGetWin32Apps.json"
$result = Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $appFolderPath -OrchestrationPath $OrchestrationPath $result = Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $appFolderPath -OrchestrationPath $OrchestrationPath -SubFolder $subFolderForCommand
} }
else { else {
# For any other case, set result to 0 (success) # For any other case, set result to 0 (success)
$result = 0 $result = 0
} }
if ($result -ne 0) { $overallResult = $result }
# Handle MSStore specific post-processing # Handle MSStore specific post-processing
if ($Source -eq 'msstore' -and $appFolderPath -match 'MSStore') { if ($Source -eq 'msstore' -and $appFolderPath -match 'MSStore') {
# Set-InstallStoreAppsFlag
# Handle ARM64-specific dependencies # Handle ARM64-specific dependencies
if ($WindowsArch -eq 'ARM64') { if ($arch -eq 'ARM64') {
WriteLog 'Windows architecture is ARM64. Removing dependencies that are not ARM64.' WriteLog 'Windows architecture is ARM64. Removing dependencies that are not ARM64.'
$dependencies = Get-ChildItem -Path "$appFolderPath\Dependencies" -ErrorAction SilentlyContinue $dependencies = Get-ChildItem -Path "$appFolderPath\Dependencies" -ErrorAction SilentlyContinue
if ($dependencies) { if ($dependencies) {
@@ -151,7 +186,7 @@ function Get-Application {
# Remove older versions # Remove older versions
WriteLog "Latest version of $AppName has been identified as $latestPackage. Removing old versions of $AppName that may have downloaded." WriteLog "Latest version of $AppName has been identified as $latestPackage. Removing old versions of $AppName that may have downloaded."
foreach ($package in $packages) { foreach ($package in $packages) {
if ($package.FullName -ne $latestPackage) { if ($package.FullName -ne $latestPackage.FullName) {
try { try {
WriteLog "Removing $($package.FullName)" WriteLog "Removing $($package.FullName)"
Remove-Item -Path $package.FullName -Force Remove-Item -Path $package.FullName -Force
@@ -163,8 +198,9 @@ function Get-Application {
} }
} }
} }
} # End foreach ($arch in $architecturesToDownload)
return $result return $overallResult
} }
function Get-Apps { function Get-Apps {
[CmdletBinding()] [CmdletBinding()]
@@ -217,7 +253,8 @@ function Get-Apps {
foreach ($wingetApp in $wingetApps) { foreach ($wingetApp in $wingetApps) {
try { try {
Get-Application -AppName $wingetApp.Name -AppId $wingetApp.Id -Source 'winget' -AppsPath $AppsPath -WindowsArch $WindowsArch -OrchestrationPath $OrchestrationPath $appArch = if ($wingetApp.PSObject.Properties['architecture']) { $wingetApp.architecture } else { $WindowsArch }
Get-Application -AppName $wingetApp.Name -AppId $wingetApp.Id -Source 'winget' -AppsPath $AppsPath -WindowsArch $appArch -OrchestrationPath $OrchestrationPath
} }
catch { catch {
WriteLog "Error occurred while processing $($wingetApp.Name): $_" WriteLog "Error occurred while processing $($wingetApp.Name): $_"
@@ -234,7 +271,8 @@ function Get-Apps {
foreach ($storeApp in $StoreApps) { foreach ($storeApp in $StoreApps) {
try { try {
Get-Application -AppName $storeApp.Name -AppId $storeApp.Id -Source 'msstore' -AppsPath $AppsPath -WindowsArch $WindowsArch -OrchestrationPath $OrchestrationPath $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
} }
catch { catch {
WriteLog "Error occurred while processing $($storeApp.Name): $_" WriteLog "Error occurred while processing $($storeApp.Name): $_"
@@ -321,7 +359,8 @@ function Add-Win32SilentInstallCommand {
[string]$AppFolder, [string]$AppFolder,
[string]$AppFolderPath, [string]$AppFolderPath,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$OrchestrationPath [string]$OrchestrationPath,
[string]$SubFolder
) )
$appName = $AppFolder $appName = $AppFolder
$installerPath = Get-ChildItem -Path "$appFolderPath\*" -Include "*.exe", "*.msi" -File -ErrorAction Stop $installerPath = Get-ChildItem -Path "$appFolderPath\*" -Include "*.exe", "*.msi" -File -ErrorAction Stop
@@ -339,12 +378,18 @@ function Add-Win32SilentInstallCommand {
return 2 return 2
} }
$installer = Split-Path -Path $installerPath -Leaf $installer = Split-Path -Path $installerPath -Leaf
$basePath = "D:\win32\$AppFolder"
if (-not [string]::IsNullOrEmpty($SubFolder)) {
$basePath = "$basePath\$SubFolder"
}
if ($installerPath.Extension -eq ".exe") { if ($installerPath.Extension -eq ".exe") {
$silentInstallCommand = "D:\win32\$appFolder\$installer" $silentInstallCommand = "$basePath\$installer"
} }
elseif ($installerPath.Extension -eq ".msi") { elseif ($installerPath.Extension -eq ".msi") {
$silentInstallCommand = "msiexec" $silentInstallCommand = "msiexec"
$silentInstallSwitch = "/i `"D:\win32\$appFolder\$installer`" $silentInstallSwitch" $silentInstallSwitch = "/i `"$basePath\$installer`" $silentInstallSwitch"
} }
# Path to the JSON file # Path to the JSON file
@@ -367,7 +412,7 @@ function Add-Win32SilentInstallCommand {
# Create new app entry # Create new app entry
$newApp = [PSCustomObject]@{ $newApp = [PSCustomObject]@{
Priority = $highestPriority Priority = $highestPriority
Name = $appName Name = if (-not [string]::IsNullOrEmpty($SubFolder)) { "$appName ($SubFolder)" } else { $appName }
CommandLine = $silentInstallCommand CommandLine = $silentInstallCommand
Arguments = $silentInstallSwitch Arguments = $silentInstallSwitch
} }
@@ -375,7 +420,7 @@ function Add-Win32SilentInstallCommand {
$appsData += $newApp $appsData += $newApp
$appsData | ConvertTo-Json -Depth 10 | Set-Content -Path $wingetWin32AppsJson $appsData | ConvertTo-Json -Depth 10 | Set-Content -Path $wingetWin32AppsJson
WriteLog "Added $appName to WinGetWin32Apps.json with priority $highestPriority" WriteLog "Added $($newApp.Name) to WinGetWin32Apps.json with priority $highestPriority"
# Return 0 for success # Return 0 for success
return 0 return 0
@@ -384,8 +384,48 @@ function Initialize-DynamicUIElements {
Add-SortableColumn -gridView $wingetGridView -header "Id" -binding "Id" -width 200 -headerHorizontalAlignment Left Add-SortableColumn -gridView $wingetGridView -header "Id" -binding "Id" -width 200 -headerHorizontalAlignment Left
Add-SortableColumn -gridView $wingetGridView -header "Version" -binding "Version" -width 100 -headerHorizontalAlignment Left Add-SortableColumn -gridView $wingetGridView -header "Version" -binding "Version" -width 100 -headerHorizontalAlignment Left
Add-SortableColumn -gridView $wingetGridView -header "Source" -binding "Source" -width 100 -headerHorizontalAlignment Left Add-SortableColumn -gridView $wingetGridView -header "Source" -binding "Source" -width 100 -headerHorizontalAlignment Left
Add-SortableColumn -gridView $wingetGridView -header "Download Status" -binding "DownloadStatus" -width 150 -headerHorizontalAlignment Left
# --- START: Add Architecture Column ---
$archColumn = New-Object System.Windows.Controls.GridViewColumn
$archHeader = New-Object System.Windows.Controls.GridViewColumnHeader
$archHeader.Tag = "Architecture" # For sorting
$archHeader.HorizontalContentAlignment = [System.Windows.HorizontalAlignment]::Left
# Create header content with correct padding to match other columns
$commonPaddingForHeader = New-Object System.Windows.Thickness(5, 2, 5, 2)
$headerTextElementFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.TextBlock])
$headerTextElementFactory.SetValue([System.Windows.Controls.TextBlock]::TextProperty, "Architecture")
$headerTextBlockPadding = New-Object System.Windows.Thickness($commonPaddingForHeader.Left, $commonPaddingForHeader.Top, $commonPaddingForHeader.Right, $commonPaddingForHeader.Bottom)
$headerTextElementFactory.SetValue([System.Windows.Controls.TextBlock]::PaddingProperty, $headerTextBlockPadding)
$headerTextElementFactory.SetValue([System.Windows.FrameworkElement]::VerticalAlignmentProperty, [System.Windows.VerticalAlignment]::Center)
$headerDataTemplate = New-Object System.Windows.DataTemplate
$headerDataTemplate.VisualTree = $headerTextElementFactory
$archHeader.ContentTemplate = $headerDataTemplate
$archColumn.Header = $archHeader
$archColumn.Width = 120
# Create the CellTemplate with a ComboBox
$archCellTemplate = New-Object System.Windows.DataTemplate
$comboBoxFactory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.ComboBox])
# The ItemsSource for the ComboBox
$availableArchitectures = @('x86', 'x64', 'arm64', 'x86 x64')
$comboBoxFactory.SetValue([System.Windows.Controls.ItemsControl]::ItemsSourceProperty, $availableArchitectures)
# Bind the text property to the 'Architecture' property of the data item.
# This ensures the initial value is displayed correctly.
$binding = New-Object System.Windows.Data.Binding("Architecture")
$binding.Mode = [System.Windows.Data.BindingMode]::TwoWay
$comboBoxFactory.SetBinding([System.Windows.Controls.ComboBox]::TextProperty, $binding)
$archCellTemplate.VisualTree = $comboBoxFactory
$archColumn.CellTemplate = $archCellTemplate
$wingetGridView.Columns.Add($archColumn)
# --- END: Add Architecture Column ---
Add-SortableColumn -gridView $wingetGridView -header "Download Status" -binding "DownloadStatus" -width 150 -headerHorizontalAlignment Left
$State.Controls.lstWingetResults.AddHandler( $State.Controls.lstWingetResults.AddHandler(
[System.Windows.Controls.GridViewColumnHeader]::ClickEvent, [System.Windows.Controls.GridViewColumnHeader]::ClickEvent,
[System.Windows.RoutedEventHandler] { [System.Windows.RoutedEventHandler] {
@@ -27,9 +27,12 @@ function Search-WingetApps {
# Store selected apps from the current view # Store selected apps from the current view
$selectedAppsFromView = @($currentItemsInListView | Where-Object { $_.IsSelected }) $selectedAppsFromView = @($currentItemsInListView | Where-Object { $_.IsSelected })
# Get default architecture from the UI
$defaultArch = $State.Controls.cmbWindowsArch.SelectedItem
# Search for new apps, which are streamed directly as PSCustomObjects # Search for new apps, which are streamed directly as PSCustomObjects
# with the required properties for performance. # with the required properties for performance.
$searchedAppResults = Search-WingetPackagesPublic -Query $searchQuery $searchedAppResults = Search-WingetPackagesPublic -Query $searchQuery -DefaultArchitecture $defaultArch
WriteLog "Found $($searchedAppResults.Count) apps matching query '$searchQuery'." WriteLog "Found $($searchedAppResults.Count) apps matching query '$searchQuery'."
$finalAppList = [System.Collections.Generic.List[object]]::new() $finalAppList = [System.Collections.Generic.List[object]]::new()
@@ -76,6 +79,7 @@ function Save-WingetList {
name = $_.Name name = $_.Name
id = $_.Id id = $_.Id
source = $_.Source.ToLower() source = $_.Source.ToLower()
architecture = $_.Architecture
} }
}) })
} }
@@ -116,6 +120,9 @@ function Import-WingetList {
$newAppListForItemsSource = [System.Collections.Generic.List[object]]::new() $newAppListForItemsSource = [System.Collections.Generic.List[object]]::new()
if ($null -ne $importedAppsData.apps) { if ($null -ne $importedAppsData.apps) {
# Get default architecture from the UI for fallback
$defaultArch = $State.Controls.cmbWindowsArch.SelectedItem
foreach ($appInfo in $importedAppsData.apps) { foreach ($appInfo in $importedAppsData.apps) {
$newAppListForItemsSource.Add([PSCustomObject]@{ $newAppListForItemsSource.Add([PSCustomObject]@{
IsSelected = $true # Imported apps are marked as selected IsSelected = $true # Imported apps are marked as selected
@@ -123,6 +130,7 @@ function Import-WingetList {
Id = $appInfo.id Id = $appInfo.id
Version = "" # Will be populated when searching or if data exists Version = "" # Will be populated when searching or if data exists
Source = $appInfo.source Source = $appInfo.source
Architecture = if ($appInfo.PSObject.Properties['architecture']) { $appInfo.architecture } else { $defaultArch }
DownloadStatus = "" DownloadStatus = ""
}) })
} }
@@ -145,7 +153,9 @@ function Search-WingetPackagesPublic {
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$Query [string]$Query,
[Parameter(Mandatory = $true)]
[string]$DefaultArchitecture
) )
WriteLog "Searching Winget packages with query: '$Query'" WriteLog "Searching Winget packages with query: '$Query'"
@@ -160,6 +170,7 @@ function Search-WingetPackagesPublic {
Id, Id,
Version, Version,
Source, Source,
@{Name = 'Architecture'; Expression = { $DefaultArchitecture } },
@{Name = 'DownloadStatus'; Expression = { '' } } @{Name = 'DownloadStatus'; Expression = { '' } }
} }
catch { catch {
@@ -342,8 +353,6 @@ function Start-WingetAppDownloadTask {
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$AppsPath, # Pass necessary paths [string]$AppsPath, # Pass necessary paths
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$WindowsArch,
[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
@@ -361,7 +370,7 @@ function Start-WingetAppDownloadTask {
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 "Apps Path: $($AppsPath)"
# WriteLog "AppList JSON Path: $($AppListJsonPath)" # WriteLog "AppList JSON Path: $($AppListJsonPath)"
# WriteLog "Windows Architecture: $($WindowsArch)" # WriteLog "Windows Architecture: $($ApplicationItemData.Architecture)"
# WriteLog "Orchestration Path: $($OrchestrationPath)" # WriteLog "Orchestration Path: $($OrchestrationPath)"
try { try {
@@ -449,7 +458,7 @@ function Start-WingetAppDownloadTask {
} }
# For now, assuming Get-Application uses $global variables set in the main script or $using: scope. # For now, assuming Get-Application uses $global variables set in the main script or $using: scope.
# $global:AppsPath = $AppsPath # Potentially redundant if set globally before parallel call # $global:AppsPath = $AppsPath # Potentially redundant if set globally before parallel call
# $global:WindowsArch = $WindowsArch # Potentially redundant # $global:WindowsArch = $ApplicationItemData.Architecture # Potentially redundant
# $global:orchestrationPath = $OrchestrationPath # Potentially redundant # $global:orchestrationPath = $OrchestrationPath # Potentially redundant
$wingetWin32jsonFile = Join-Path -Path $OrchestrationPath -ChildPath "WinGetWin32Apps.json" $wingetWin32jsonFile = Join-Path -Path $OrchestrationPath -ChildPath "WinGetWin32Apps.json"
@@ -577,7 +586,7 @@ function Start-WingetAppDownloadTask {
# Ensure variables needed by Get-Application are accessible # Ensure variables needed by Get-Application are accessible
# (Assuming they are available via $using: scope or global scope from main script) # (Assuming they are available via $using: scope or global scope from main script)
# $global:AppsPath = $AppsPath # Potentially redundant # $global:AppsPath = $AppsPath # Potentially redundant
# $global:WindowsArch = $WindowsArch # Potentially redundant # $global:WindowsArch = $ApplicationItemData.Architecture # Potentially redundant
# $global:orchestrationPath = $OrchestrationPath # Potentially redundant" # $global:orchestrationPath = $OrchestrationPath # Potentially redundant"
WriteLog "Orchestration Path: $($OrchestrationPath)" WriteLog "Orchestration Path: $($OrchestrationPath)"
if (-not (Test-Path -Path $OrchestrationPath -PathType Container)) { if (-not (Test-Path -Path $OrchestrationPath -PathType Container)) {
@@ -594,7 +603,7 @@ function Start-WingetAppDownloadTask {
try { try {
# Call Get-Application # Call Get-Application
$resultCode = Get-Application -AppName $appName -AppId $appId -Source $source -AppsPath $AppsPath -WindowsArch $WindowsArch -OrchestrationPath $OrchestrationPath -ErrorAction Stop $resultCode = Get-Application -AppName $appName -AppId $appId -Source $source -AppsPath $AppsPath -WindowsArch $ApplicationItemData.Architecture -OrchestrationPath $OrchestrationPath -ErrorAction Stop
# Determine status based on result code # Determine status based on result code
switch ($resultCode) { switch ($resultCode) {
@@ -713,13 +722,11 @@ function Invoke-WingetDownload {
$taskArguments = @{ $taskArguments = @{
AppsPath = $localAppsPath AppsPath = $localAppsPath
AppListJsonPath = $localAppListJsonPath AppListJsonPath = $localAppListJsonPath
WindowsArch = $localWindowsArch
OrchestrationPath = $localOrchestrationPath OrchestrationPath = $localOrchestrationPath
} }
# Select only necessary properties before passing to Invoke-ParallelProcessing # Select only necessary properties before passing to Invoke-ParallelProcessing
$itemsToProcess = $selectedApps | Select-Object Name, Id, Source, Version # Include Version if needed $itemsToProcess = $selectedApps | Select-Object Name, Id, Source, Version, Architecture # Include Version and Architecture if needed
# Invoke the centralized parallel processing function # Invoke the centralized parallel processing function
# Pass task type and task-specific arguments # Pass task type and task-specific arguments
Invoke-ParallelProcessing -ItemsToProcess $itemsToProcess ` Invoke-ParallelProcessing -ItemsToProcess $itemsToProcess `