From 56a2597818a6caca3bb4419463b46df6c8ad67e7 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Fri, 5 Jun 2026 13:35:07 -0700 Subject: [PATCH] Consolidate WinGet version detection Add a shared WinGet component status helper that uses Get-WinGetVersion through Microsoft.WinGet.Client, and route both the CLI and UI status checks through it. This removes the UI-only winget.exe --version parsing path and adds clearer logging for missing modules, missing cmdlets, parse failures, and caught WinGet version errors. --- .../FFU.Common/FFU.Common.Winget.psm1 | 132 ++++++++++++++++-- .../FFUUI.Core/FFUUI.Core.Winget.psm1 | 79 ++++------- 2 files changed, 145 insertions(+), 66 deletions(-) diff --git a/FFUDevelopment/FFU.Common/FFU.Common.Winget.psm1 b/FFUDevelopment/FFU.Common/FFU.Common.Winget.psm1 index 1e9aecb..7090d19 100644 --- a/FFUDevelopment/FFU.Common/FFU.Common.Winget.psm1 +++ b/FFUDevelopment/FFU.Common/FFU.Common.Winget.psm1 @@ -1023,6 +1023,94 @@ function Install-WinGet { } WriteLog "WinGet installation complete." } + +function Get-WinGetComponentStatus { + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [version]$MinimumVersion = [version]"1.8.1911" + ) + + $moduleName = 'Microsoft.WinGet.Client' + $status = [PSCustomObject]@{ + Success = $false + NeedsUpdate = $true + WinGetInstalled = $false + WinGetNeedsUpdate = $true + WinGetVersion = "Unknown" + WinGetVersionObject = $null + WinGetStatus = "Unknown" + ModuleInstalled = $false + ModuleNeedsUpdate = $true + ModuleVersion = "Not installed" + ModuleVersionObject = $null + CmdletAvailable = $false + ErrorMessage = "" + } + + try { + $installedModule = @(Get-InstalledModule -Name $moduleName -ErrorAction SilentlyContinue) | Sort-Object -Property Version -Descending | Select-Object -First 1 + $availableModule = @(Get-Module -ListAvailable -Name $moduleName -ErrorAction SilentlyContinue) | Sort-Object -Property Version -Descending | Select-Object -First 1 + $wingetModule = if ($null -ne $installedModule) { $installedModule } else { $availableModule } + + if ($null -eq $wingetModule) { + $status.WinGetStatus = "$moduleName module is not installed." + WriteLog $status.WinGetStatus + return $status + } + + $status.ModuleInstalled = $true + $status.ModuleVersion = $wingetModule.Version.ToString() + $status.ModuleVersionObject = [version]$wingetModule.Version + $status.ModuleNeedsUpdate = $status.ModuleVersionObject -lt $MinimumVersion + WriteLog "$moduleName module version detected: $($status.ModuleVersion)" + + Import-Module -Name $moduleName -Force -ErrorAction Stop + $wingetVersionCommand = Get-Command -Name Get-WinGetVersion -ErrorAction SilentlyContinue + if ($null -eq $wingetVersionCommand) { + $status.WinGetStatus = "Get-WinGetVersion cmdlet is not available." + $status.ErrorMessage = $status.WinGetStatus + WriteLog $status.WinGetStatus + return $status + } + + $status.CmdletAvailable = $true + $wingetVersion = Get-WinGetVersion -ErrorAction Stop + $wingetVersionText = [string]$wingetVersion + WriteLog "Get-WinGetVersion returned: $wingetVersionText" + + if ([string]::IsNullOrWhiteSpace($wingetVersionText)) { + $status.WinGetVersion = "Not installed" + $status.WinGetStatus = "WinGet is not installed." + WriteLog $status.WinGetStatus + return $status + } + + if ($wingetVersionText -match 'v?(\d+\.\d+\.\d+)') { + $parsedVersion = [version]$matches[1] + $status.WinGetInstalled = $true + $status.WinGetVersion = $parsedVersion.ToString() + $status.WinGetVersionObject = $parsedVersion + $status.WinGetNeedsUpdate = $parsedVersion -lt $MinimumVersion + $status.WinGetStatus = if ($status.WinGetNeedsUpdate) { "Update required" } else { $parsedVersion.ToString() } + $status.NeedsUpdate = $status.ModuleNeedsUpdate -or $status.WinGetNeedsUpdate + $status.Success = -not $status.NeedsUpdate + return $status + } + + $status.WinGetStatus = "Version check failed." + $status.ErrorMessage = "Could not parse Get-WinGetVersion output: $wingetVersionText" + WriteLog $status.ErrorMessage + return $status + } + catch { + $status.ErrorMessage = $_.Exception.Message + $status.WinGetStatus = "Get-WinGetVersion failed." + WriteLog "Get-WinGetVersion failed: $($status.ErrorMessage)" + return $status + } +} + function Confirm-WinGetInstallation { [CmdletBinding()] param( @@ -1032,12 +1120,11 @@ function Confirm-WinGetInstallation { WriteLog 'Checking if WinGet is installed...' $minVersion = [version]"1.8.1911" - + $wingetStatus = Get-WinGetComponentStatus -MinimumVersion $minVersion + # Check WinGet PowerShell module - $wingetModule = Get-InstalledModule -Name Microsoft.Winget.Client -ErrorAction SilentlyContinue - $wingetModuleVersion = [version]$wingetModule.Version - if ($wingetModuleVersion -lt $minVersion -or -not $wingetModule) { - WriteLog 'Microsoft.Winget.Client module is not installed or is an older version. Installing the latest version...' + if ($wingetStatus.ModuleNeedsUpdate) { + WriteLog 'Microsoft.WinGet.Client module is not installed or is an older version. Installing the latest version...' # Handle PSGallery trust settings $PSGalleryTrust = (Get-PSRepository -Name 'PSGallery').InstallationPolicy @@ -1046,30 +1133,49 @@ function Confirm-WinGetInstallation { Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted } - Install-Module -Name Microsoft.Winget.Client -Force -Repository 'PSGallery' + Install-Module -Name Microsoft.WinGet.Client -Force -Repository 'PSGallery' if ($PSGalleryTrust -eq 'Untrusted') { WriteLog 'Setting PSGallery back to untrusted repository...' Set-PSRepository -Name 'PSGallery' -InstallationPolicy Untrusted WriteLog 'Done' } + + $wingetStatus = Get-WinGetComponentStatus -MinimumVersion $minVersion } else { - WriteLog "Installed Microsoft.Winget.Client module version: $($wingetModule.Version)" + WriteLog "Installed Microsoft.WinGet.Client module version: $($wingetStatus.ModuleVersion)" } + + if ($wingetStatus.ModuleNeedsUpdate) { + $message = "Microsoft.WinGet.Client module version $($wingetStatus.ModuleVersion) does not meet the minimum required version $minVersion." + WriteLog $message + throw $message + } + + if (-not $wingetStatus.CmdletAvailable) { + $message = "Get-WinGetVersion cmdlet is not available from Microsoft.WinGet.Client. $($wingetStatus.ErrorMessage)" + WriteLog $message + throw $message + } + + if (-not [string]::IsNullOrWhiteSpace($wingetStatus.ErrorMessage)) { + $message = "Unable to determine WinGet version by using Get-WinGetVersion. $($wingetStatus.ErrorMessage)" + WriteLog $message + throw $message + } # Check WinGet CLI - $wingetVersion = Get-WinGetVersion - if (-not $wingetVersion) { + if (-not $wingetStatus.WinGetInstalled) { WriteLog "WinGet is not installed. Installing WinGet..." Install-WinGet -Architecture $WindowsArch } - elseif ($wingetVersion -match 'v?(\d+\.\d+\.\d+)' -and [version]$matches[1] -lt $minVersion) { - WriteLog "The installed version of WinGet $($matches[1]) does not support downloading MSStore apps. Installing the latest version of WinGet..." + elseif ($wingetStatus.WinGetNeedsUpdate) { + WriteLog "The installed version of WinGet $($wingetStatus.WinGetVersion) does not support downloading MSStore apps. Installing the latest version of WinGet..." Install-WinGet -Architecture $WindowsArch } else { - WriteLog "Installed WinGet version: $wingetVersion" + WriteLog "Installed WinGet version: $($wingetStatus.WinGetVersion)" } } # -------------------------------------------------------------------------- @@ -1561,4 +1667,4 @@ function Add-Win32SilentInstallCommand { # -------------------------------------------------------------------------- # Export functions needed by both BuildFFUVM and the UI Core module -Export-ModuleMember -Function Get-Application, Get-Apps, Start-WingetAppDownloadTask, Confirm-WinGetInstallation, Add-Win32SilentInstallCommand, Install-Winget \ No newline at end of file +Export-ModuleMember -Function Get-Application, Get-Apps, Start-WingetAppDownloadTask, Confirm-WinGetInstallation, Get-WinGetComponentStatus, Add-Win32SilentInstallCommand, Install-Winget \ No newline at end of file diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Winget.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Winget.psm1 index 579e95f..76da2e6 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Winget.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Winget.psm1 @@ -233,44 +233,6 @@ function Search-WingetPackagesPublic { } } -function Test-WingetCLI { - [CmdletBinding()] - param() - - $minVersion = [version]"1.8.1911" - - # Check Winget CLI - $wingetCmd = Get-Command -Name winget -ErrorAction SilentlyContinue - if (-not $wingetCmd) { - return @{ - Version = "Not installed" - Status = "Not installed - Install from Microsoft Store" - } - } - - # Get and check version - $wingetVersion = & winget.exe --version - if ($wingetVersion -match 'v?(\d+\.\d+.\d+)') { - $version = [version]$matches[1] - if ($version -lt $minVersion) { - return @{ - Version = $version.ToString() - Status = "Update required - Install from Microsoft Store" - } - } - return @{ - Version = $version.ToString() - Status = $version.ToString() - } - } - - return @{ - Version = "Unknown" - Status = "Version check failed" - } -} - - function Install-WingetComponents { [CmdletBinding()] param( @@ -339,19 +301,22 @@ function Confirm-WingetInstallationUI { try { # Initial Check WriteLog "Confirm-WingetInstallationUI: Starting checks..." - $cliStatus = Test-WingetCLI - $module = @(Get-InstalledModule -Name Microsoft.WinGet.Client -ErrorAction SilentlyContinue) | Sort-Object -Top 1 -Descending Version -ErrorAction SilentlyContinue + $wingetStatus = Get-WinGetComponentStatus -MinimumVersion $minVersion - $result.CliVersion = $cliStatus.Version - $result.ModuleVersion = if ($null -ne $module) { $module.Version.ToString() } else { "Not installed" } + $result.CliVersion = $wingetStatus.WinGetVersion + $result.ModuleVersion = $wingetStatus.ModuleVersion # Use callback for initial status display & $UiUpdateCallback $result.CliVersion $result.ModuleVersion # Determine if install/update is needed - $needsCliUpdate = $cliStatus.Status -notmatch '^\d+\.\d+\.\d+$' -or ([version]$cliStatus.Version -lt $minVersion) - $needsModuleUpdate = ($null -eq $module) -or ([version]$module.Version -lt $minVersion) - $result.NeedsUpdate = $needsCliUpdate -or $needsModuleUpdate + $needsCliUpdate = $wingetStatus.WinGetNeedsUpdate + $needsModuleUpdate = $wingetStatus.ModuleNeedsUpdate + $result.NeedsUpdate = $wingetStatus.NeedsUpdate + + if (-not [string]::IsNullOrWhiteSpace($wingetStatus.ErrorMessage)) { + WriteLog "Confirm-WingetInstallationUI: WinGet status error - $($wingetStatus.ErrorMessage)" + } if ($result.NeedsUpdate) { WriteLog "Confirm-WingetInstallationUI: Update needed. CLI Needs Update: $needsCliUpdate, Module Needs Update: $needsModuleUpdate" @@ -361,21 +326,29 @@ function Confirm-WingetInstallationUI { & $UiUpdateCallback $result.CliVersion "Installing/Updating..." # Attempt to install/update Winget CLI and module - $installedModule = Install-WingetComponents -UiUpdateCallback $UiUpdateCallback + Install-WingetComponents -UiUpdateCallback $UiUpdateCallback | Out-Null # Re-check status after attempt WriteLog "Confirm-WingetInstallationUI: Re-checking status after update attempt..." - $cliStatus = Test-WingetCLI - $result.CliVersion = $cliStatus.Version - $result.ModuleVersion = if ($null -ne $installedModule) { $installedModule.Version } else { "Install Failed" } + $wingetStatus = Get-WinGetComponentStatus -MinimumVersion $minVersion + $result.CliVersion = $wingetStatus.WinGetVersion + $result.ModuleVersion = $wingetStatus.ModuleVersion # Use callback for final status display after update attempt & $UiUpdateCallback $result.CliVersion $result.ModuleVersion # Check if update was successful - $cliOk = $cliStatus.Status -match '^\d+\.\d+\.\d+$' -and ([version]$cliStatus.Version -ge $minVersion) - $moduleOk = ($null -ne $installedModule) -and ([version]$installedModule.Version -ge $minVersion) - $result.Success = $cliOk -and $moduleOk - $result.Message = if ($result.Success) { "Winget components installed/updated successfully." } else { "Winget component installation/update failed or is incomplete." } + $cliOk = $wingetStatus.WinGetInstalled -and -not $wingetStatus.WinGetNeedsUpdate + $moduleOk = $wingetStatus.ModuleInstalled -and -not $wingetStatus.ModuleNeedsUpdate + $result.Success = $cliOk -and $moduleOk -and [string]::IsNullOrWhiteSpace($wingetStatus.ErrorMessage) + $result.Message = if ($result.Success) { + "Winget components installed/updated successfully." + } + elseif (-not [string]::IsNullOrWhiteSpace($wingetStatus.ErrorMessage)) { + "Winget component installation/update failed: $($wingetStatus.ErrorMessage)" + } + else { + "Winget component installation/update failed or is incomplete." + } WriteLog "Confirm-WingetInstallationUI: Update attempt finished. Success: $($result.Success). Message: $($result.Message)" } else {