diff --git a/FFUDevelopment/FFU.Common/FFU.Common.Parallel.psm1 b/FFUDevelopment/FFU.Common/FFU.Common.Parallel.psm1 index 8388b36..fde80cb 100644 --- a/FFUDevelopment/FFU.Common/FFU.Common.Parallel.psm1 +++ b/FFUDevelopment/FFU.Common/FFU.Common.Parallel.psm1 @@ -157,12 +157,14 @@ function Invoke-ParallelProcessing { switch ($localTaskType) { 'WingetDownload' { # Pass the progress queue to the task function - $taskResult = Start-WingetAppDownloadTask -ApplicationItemData $currentItem ` - -AppListJsonPath $localJobArgs['AppListJsonPath'] ` - -AppsPath $localJobArgs['AppsPath'] ` - -WindowsArch $localJobArgs['WindowsArch'] ` - -OrchestrationPath $localJobArgs['OrchestrationPath'] ` - -ProgressQueue $localProgressQueue + $wingetTaskArgs = @{ + ApplicationItemData = $currentItem + AppListJsonPath = $localJobArgs['AppListJsonPath'] + AppsPath = $localJobArgs['AppsPath'] + OrchestrationPath = $localJobArgs['OrchestrationPath'] + ProgressQueue = $localProgressQueue + } + $taskResult = Start-WingetAppDownloadTask @wingetTaskArgs if ($null -ne $taskResult) { $resultIdentifier = $taskResult.Id $resultStatus = $taskResult.Status diff --git a/FFUDevelopment/FFU.Common/FFU.Common.Winget.psm1 b/FFUDevelopment/FFU.Common/FFU.Common.Winget.psm1 index d33b3c2..ee8aec5 100644 --- a/FFUDevelopment/FFU.Common/FFU.Common.Winget.psm1 +++ b/FFUDevelopment/FFU.Common/FFU.Common.Winget.psm1 @@ -24,6 +24,26 @@ function Get-Application { [Parameter(Mandatory = $true)] [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 $wingetSearchResult = Find-WinGetPackage -id $AppId -MatchOption Equals -Source $Source @@ -34,137 +54,153 @@ function Get-Application { } WriteLog "$AppName not found in $Source repository." WriteLog "Check the AppList.json file and make sure the AppID is correct." - Exit 1 + return 1 # Return error code } - - # Determine app type and folder path - $appIsWin32 = ($Source -eq 'msstore' -and $AppId.StartsWith("XP")) - if ($Source -eq 'winget' -or $appIsWin32) { - $appFolderPath = Join-Path -Path "$AppsPath\Win32" -ChildPath $AppName - } - else { - $appFolderPath = Join-Path -Path "$AppsPath\MSStore" -ChildPath $AppName - } - - # Create app folder - New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null - - # Log download information - WriteLog "Downloading $AppName for $WindowsArch architecture..." - 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 "WinGet command: Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Architecture $WindowsArch -Source $Source" - - # Download the app - $wingetDownloadResult = Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Architecture $WindowsArch -Source $Source - - # Handle download status - if ($wingetDownloadResult.status -ne 'Ok') { - # Try downloading without architecture if no applicable installer found - if ($wingetDownloadResult.status -eq 'NoApplicableInstallers' -or $wingetDownloadResult.status -eq 'NoApplicableInstallerFound') { - WriteLog "No installer found for $WindowsArch architecture. Attempting to download without specifying architecture..." - $wingetDownloadResult = Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Source $Source - if ($wingetDownloadResult.status -eq 'Ok') { - WriteLog "Downloaded $AppName without specifying architecture." - } - else { - WriteLog "ERROR: No installer found for $AppName. Exiting" - Remove-Item -Path $appFolderPath -Recurse -Force - Exit 1 - } - } - # Handle Store-specific errors - elseif ($Source -eq 'msstore') { - # If download not supported by publisher - 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." - 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." - Exit 1 - } + + # 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 + $appIsWin32 = ($Source -eq 'msstore' -and $AppId.StartsWith("XP")) + if ($Source -eq 'winget' -or $appIsWin32) { + $appBaseFolderPath = Join-Path -Path "$AppsPath\Win32" -ChildPath $AppName } else { - $errormsg = "ERROR: Download failed for $AppName with status: $($wingetDownloadResult.status) $($wingetDownloadResult.ExtendedErrorCode)" - WriteLog $errormsg - Remove-Item -Path $appFolderPath -Recurse -Force - Write-Error $errormsg - Exit 1 + $appBaseFolderPath = Join-Path -Path "$AppsPath\MSStore" -ChildPath $AppName } - } - - WriteLog "$AppName downloaded to $appFolderPath" - - # 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 - $uwpExtensions = @(".appx", ".appxbundle", ".msix", ".msixbundle") - - if ($uwpExtensions -contains $installerPath.Extension -and $appFolderPath -match 'Win32') { - # Handle UWP apps - $NewAppPath = "$AppsPath\MSStore\$AppName" - WriteLog "$AppName is a UWP app. Moving to $NewAppPath" - WriteLog "Creating $NewAppPath" - New-Item -Path "$AppsPath\MSStore\$AppName" -ItemType Directory -Force | Out-Null - WriteLog "Moving $AppName to $NewAppPath" - Move-Item -Path "$appFolderPath\*" -Destination "$AppsPath\MSStore\$AppName" -Force - WriteLog "Removing $appFolderPath" - Remove-Item -Path $appFolderPath -Force -Recurse - WriteLog "$AppName moved to $NewAppPath" - # Set-InstallStoreAppsFlag - $result = 0 # Success for UWP app - } - # If app is in Win32 folder, add the silent install command to the WinGetWin32Apps.json file - elseif ($appFolderPath -match 'Win32') { - WriteLog "$AppName is a Win32 app. Adding silent install command to $OrchestrationPath\WinGetWin32Apps.json" - $result = Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $appFolderPath -OrchestrationPath $OrchestrationPath - } - else { - # For any other case, set result to 0 (success) - $result = 0 - } - - # Handle MSStore specific post-processing - if ($Source -eq 'msstore' -and $appFolderPath -match 'MSStore') { - # Set-InstallStoreAppsFlag - # Handle ARM64-specific dependencies - if ($WindowsArch -eq 'ARM64') { - WriteLog 'Windows architecture is ARM64. Removing dependencies that are not ARM64.' - $dependencies = Get-ChildItem -Path "$appFolderPath\Dependencies" -ErrorAction SilentlyContinue - if ($dependencies) { - foreach ($dependency in $dependencies) { - if ($dependency.Name -notmatch 'ARM64') { - WriteLog "Removing dependency file $($dependency.FullName)" - Remove-Item -Path $dependency.FullName -Recurse -Force + # 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 + New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null + + # Log download information + WriteLog "Downloading $AppName for $arch architecture..." + 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 "WinGet command: Export-WinGetPackage -id $AppId -DownloadDirectory `"$appFolderPath`" -Architecture $arch -Source $Source" + + # Download the app + $wingetDownloadResult = Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Architecture $arch -Source $Source + + # Handle download status + if ($wingetDownloadResult.status -ne 'Ok') { + # Try downloading without architecture if no applicable installer found + if ($wingetDownloadResult.status -eq 'NoApplicableInstallers' -or $wingetDownloadResult.status -eq 'NoApplicableInstallerFound') { + WriteLog "No installer found for $arch architecture. Attempting to download without specifying architecture..." + $wingetDownloadResult = Export-WinGetPackage -id $AppId -DownloadDirectory $appFolderPath -Source $Source + if ($wingetDownloadResult.status -eq 'Ok') { + WriteLog "Downloaded $AppName without specifying architecture." + } + else { + WriteLog "ERROR: No installer found for $AppName. Exiting" + Remove-Item -Path $appFolderPath -Recurse -Force + return 1 # Return error code + } + } + # Handle Store-specific errors + elseif ($Source -eq 'msstore') { + # If download not supported by publisher + if ($wingetDownloadResult.ExtendedErrorCode -match '0x8A150084') { + $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 + Write-Error $errorMessage + return 1 # Return error code + } + } + else { + $errormsg = "ERROR: Download failed for $AppName with status: $($wingetDownloadResult.status) $($wingetDownloadResult.ExtendedErrorCode)" + WriteLog $errormsg + Remove-Item -Path $appFolderPath -Recurse -Force + Write-Error $errormsg + return 1 # Return error code + } + } + + 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 + $installerPath = Get-ChildItem -Path "$appFolderPath\*" -Exclude "*.yaml", "*.xml" -File -ErrorAction Stop + $uwpExtensions = @(".appx", ".appxbundle", ".msix", ".msixbundle") + + if ($uwpExtensions -contains $installerPath.Extension -and $appFolderPath -match 'Win32') { + # Handle UWP apps + $NewAppPath = "$AppsPath\MSStore\$AppName" + WriteLog "$AppName is a UWP app. Moving to $NewAppPath" + WriteLog "Creating $NewAppPath" + New-Item -Path "$AppsPath\MSStore\$AppName" -ItemType Directory -Force | Out-Null + WriteLog "Moving $AppName to $NewAppPath" + Move-Item -Path "$appFolderPath\*" -Destination "$AppsPath\MSStore\$AppName" -Force + WriteLog "Removing $appFolderPath" + Remove-Item -Path $appFolderPath -Force -Recurse + WriteLog "$AppName moved to $NewAppPath" + $result = 0 # Success for UWP app + } + # If app is in Win32 folder, add the silent install command to the WinGetWin32Apps.json file + elseif ($appFolderPath -match 'Win32') { + WriteLog "$AppName is a Win32 app. Adding silent install command to $OrchestrationPath\WinGetWin32Apps.json" + $result = Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $appFolderPath -OrchestrationPath $OrchestrationPath -SubFolder $subFolderForCommand + } + else { + # For any other case, set result to 0 (success) + $result = 0 + } + + if ($result -ne 0) { $overallResult = $result } + + # Handle MSStore specific post-processing + if ($Source -eq 'msstore' -and $appFolderPath -match 'MSStore') { + # Handle ARM64-specific dependencies + if ($arch -eq 'ARM64') { + WriteLog 'Windows architecture is ARM64. Removing dependencies that are not ARM64.' + $dependencies = Get-ChildItem -Path "$appFolderPath\Dependencies" -ErrorAction SilentlyContinue + if ($dependencies) { + foreach ($dependency in $dependencies) { + if ($dependency.Name -notmatch 'ARM64') { + WriteLog "Removing dependency file $($dependency.FullName)" + Remove-Item -Path $dependency.FullName -Recurse -Force + } + } + } + } + + # Clean up multiple versions (keep only the latest) + WriteLog "$AppName has completed downloading. Identifying the latest version of $AppName." + $packages = Get-ChildItem -Path "$appFolderPath\*" -Exclude "Dependencies\*", "*.xml", "*.yaml" -File -ErrorAction Stop + + # Find latest version based on signature date + $latestPackage = $packages | Sort-Object { (Get-AuthenticodeSignature $_.FullName).SignerCertificate.NotBefore } -Descending | Select-Object -First 1 + + # Remove older versions + WriteLog "Latest version of $AppName has been identified as $latestPackage. Removing old versions of $AppName that may have downloaded." + 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 $_ } } } } - - # Clean up multiple versions (keep only the latest) - WriteLog "$AppName has completed downloading. Identifying the latest version of $AppName." - $packages = Get-ChildItem -Path "$appFolderPath\*" -Exclude "Dependencies\*", "*.xml", "*.yaml" -File -ErrorAction Stop - - # Find latest version based on signature date - $latestPackage = $packages | Sort-Object { (Get-AuthenticodeSignature $_.FullName).SignerCertificate.NotBefore } -Descending | Select-Object -First 1 - - # Remove older versions - WriteLog "Latest version of $AppName has been identified as $latestPackage. Removing old versions of $AppName that may have downloaded." - foreach ($package in $packages) { - if ($package.FullName -ne $latestPackage) { - try { - WriteLog "Removing $($package.FullName)" - Remove-Item -Path $package.FullName -Force - } - catch { - WriteLog "Failed to delete: $($package.FullName) - $_" - throw $_ - } - } - } - } + } # End foreach ($arch in $architecturesToDownload) - return $result + return $overallResult } function Get-Apps { [CmdletBinding()] @@ -217,7 +253,8 @@ function Get-Apps { foreach ($wingetApp in $wingetApps) { 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 { WriteLog "Error occurred while processing $($wingetApp.Name): $_" @@ -234,7 +271,8 @@ function Get-Apps { foreach ($storeApp in $StoreApps) { 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 { WriteLog "Error occurred while processing $($storeApp.Name): $_" @@ -321,7 +359,8 @@ function Add-Win32SilentInstallCommand { [string]$AppFolder, [string]$AppFolderPath, [Parameter(Mandatory = $true)] - [string]$OrchestrationPath + [string]$OrchestrationPath, + [string]$SubFolder ) $appName = $AppFolder $installerPath = Get-ChildItem -Path "$appFolderPath\*" -Include "*.exe", "*.msi" -File -ErrorAction Stop @@ -339,12 +378,18 @@ function Add-Win32SilentInstallCommand { return 2 } $installer = Split-Path -Path $installerPath -Leaf + + $basePath = "D:\win32\$AppFolder" + if (-not [string]::IsNullOrEmpty($SubFolder)) { + $basePath = "$basePath\$SubFolder" + } + if ($installerPath.Extension -eq ".exe") { - $silentInstallCommand = "D:\win32\$appFolder\$installer" + $silentInstallCommand = "$basePath\$installer" } elseif ($installerPath.Extension -eq ".msi") { $silentInstallCommand = "msiexec" - $silentInstallSwitch = "/i `"D:\win32\$appFolder\$installer`" $silentInstallSwitch" + $silentInstallSwitch = "/i `"$basePath\$installer`" $silentInstallSwitch" } # Path to the JSON file @@ -367,7 +412,7 @@ function Add-Win32SilentInstallCommand { # Create new app entry $newApp = [PSCustomObject]@{ Priority = $highestPriority - Name = $appName + Name = if (-not [string]::IsNullOrEmpty($SubFolder)) { "$appName ($SubFolder)" } else { $appName } CommandLine = $silentInstallCommand Arguments = $silentInstallSwitch } @@ -375,7 +420,7 @@ function Add-Win32SilentInstallCommand { $appsData += $newApp $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 diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Initialize.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Initialize.psm1 index a704732..d97c732 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Initialize.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Initialize.psm1 @@ -384,8 +384,48 @@ function Initialize-DynamicUIElements { 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 "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( [System.Windows.Controls.GridViewColumnHeader]::ClickEvent, [System.Windows.RoutedEventHandler] { diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Winget.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Winget.psm1 index aff001d..d4ca99d 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Winget.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Winget.psm1 @@ -27,9 +27,12 @@ function Search-WingetApps { # Store selected apps from the current view $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 # 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'." $finalAppList = [System.Collections.Generic.List[object]]::new() @@ -73,9 +76,10 @@ function Save-WingetList { $appList = @{ apps = @($selectedApps | ForEach-Object { [ordered]@{ - name = $_.Name - id = $_.Id - source = $_.Source.ToLower() + name = $_.Name + id = $_.Id + source = $_.Source.ToLower() + architecture = $_.Architecture } }) } @@ -116,6 +120,9 @@ function Import-WingetList { $newAppListForItemsSource = [System.Collections.Generic.List[object]]::new() if ($null -ne $importedAppsData.apps) { + # Get default architecture from the UI for fallback + $defaultArch = $State.Controls.cmbWindowsArch.SelectedItem + foreach ($appInfo in $importedAppsData.apps) { $newAppListForItemsSource.Add([PSCustomObject]@{ IsSelected = $true # Imported apps are marked as selected @@ -123,6 +130,7 @@ function Import-WingetList { Id = $appInfo.id Version = "" # Will be populated when searching or if data exists Source = $appInfo.source + Architecture = if ($appInfo.PSObject.Properties['architecture']) { $appInfo.architecture } else { $defaultArch } DownloadStatus = "" }) } @@ -145,7 +153,9 @@ function Search-WingetPackagesPublic { [CmdletBinding()] param( [Parameter(Mandatory = $true)] - [string]$Query + [string]$Query, + [Parameter(Mandatory = $true)] + [string]$DefaultArchitecture ) WriteLog "Searching Winget packages with query: '$Query'" @@ -160,6 +170,7 @@ function Search-WingetPackagesPublic { Id, Version, Source, + @{Name = 'Architecture'; Expression = { $DefaultArchitecture } }, @{Name = 'DownloadStatus'; Expression = { '' } } } catch { @@ -342,8 +353,6 @@ function Start-WingetAppDownloadTask { [Parameter(Mandatory = $true)] [string]$AppsPath, # Pass necessary paths [Parameter(Mandatory = $true)] - [string]$WindowsArch, - [Parameter(Mandatory = $true)] [string]$OrchestrationPath, [Parameter(Mandatory = $true)] [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 "Apps Path: $($AppsPath)" # WriteLog "AppList JSON Path: $($AppListJsonPath)" - # WriteLog "Windows Architecture: $($WindowsArch)" + # WriteLog "Windows Architecture: $($ApplicationItemData.Architecture)" # WriteLog "Orchestration Path: $($OrchestrationPath)" try { @@ -449,7 +458,7 @@ function Start-WingetAppDownloadTask { } # 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:WindowsArch = $WindowsArch # Potentially redundant + # $global:WindowsArch = $ApplicationItemData.Architecture # Potentially redundant # $global:orchestrationPath = $OrchestrationPath # Potentially redundant $wingetWin32jsonFile = Join-Path -Path $OrchestrationPath -ChildPath "WinGetWin32Apps.json" @@ -577,7 +586,7 @@ function Start-WingetAppDownloadTask { # Ensure variables needed by Get-Application are accessible # (Assuming they are available via $using: scope or global scope from main script) # $global:AppsPath = $AppsPath # Potentially redundant - # $global:WindowsArch = $WindowsArch # Potentially redundant + # $global:WindowsArch = $ApplicationItemData.Architecture # Potentially redundant # $global:orchestrationPath = $OrchestrationPath # Potentially redundant" WriteLog "Orchestration Path: $($OrchestrationPath)" if (-not (Test-Path -Path $OrchestrationPath -PathType Container)) { @@ -594,7 +603,7 @@ function Start-WingetAppDownloadTask { try { # 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 switch ($resultCode) { @@ -713,13 +722,11 @@ function Invoke-WingetDownload { $taskArguments = @{ AppsPath = $localAppsPath AppListJsonPath = $localAppListJsonPath - WindowsArch = $localWindowsArch OrchestrationPath = $localOrchestrationPath } # 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 # Pass task type and task-specific arguments Invoke-ParallelProcessing -ItemsToProcess $itemsToProcess `