Public/Get-WingetUpdates.ps1
|
function Get-WingetUpdates { <# .SYNOPSIS Check for and install available winget package updates. .DESCRIPTION Displays a list of all installed winget packages that have updates available, with an interactive selection to choose which ones to update. Uses the Microsoft.WinGet.Client COM API for reliable package enumeration. .PARAMETER Force Skip the cache and force a fresh check for updates. .EXAMPLE Get-WingetUpdates Shows available updates and allows you to select which to install. .EXAMPLE Get-WingetUpdates -Force Forces a fresh check for updates. #> [CmdletBinding()] param( [Parameter()] [switch]$Force, [Parameter()] [switch]$IWantToLiterallyUpdateAllFuckingResults, [Parameter()] [switch]$ExportHtml ) # Ensure PwshSpectreConsole is available if (-not (Get-Module -Name PwshSpectreConsole)) { if (Get-Module -ListAvailable -Name PwshSpectreConsole) { Import-Module PwshSpectreConsole -ErrorAction SilentlyContinue } } # Ensure Microsoft.WinGet.Client is available if (-not (Get-Module -Name Microsoft.WinGet.Client)) { try { Import-Module Microsoft.WinGet.Client -ErrorAction Stop } catch { Write-Error "Microsoft.WinGet.Client module is required. Install it with: Install-Module Microsoft.WinGet.Client -Force" return } } Write-Host "Checking for winget package updates..." -ForegroundColor Cyan # Check cache first $cacheFile = Join-Path (Get-WingetBatchConfigDir) "update_cache.json" $useCache = $false if (-not $Force -and (Test-Path $cacheFile)) { try { $cache = Get-Content $cacheFile -Raw | ConvertFrom-Json $cacheAge = ((Get-Date) - [DateTime]::Parse($cache.LastChecked)).TotalMinutes if ($cacheAge -lt 30 -and $cache.Updates.Count -gt 0) { $useCache = $true $updatesAvailable = [System.Collections.Generic.List[Object]]::new() foreach ($u in $cache.Updates) { $updatesAvailable.Add($u) } Write-Host "Using cached results (checked $([Math]::Round($cacheAge, 0)) minutes ago)" -ForegroundColor DarkGray } } catch { # Cache is corrupt, ignore } } if (-not $useCache) { # Use COM API to get packages with updates available Write-Host "Querying installed packages via COM API..." -ForegroundColor DarkGray $installed = Get-WinGetPackage -ErrorAction SilentlyContinue $updatesAvailable = [System.Collections.Generic.List[Object]]::new() foreach ($pkg in $installed) { if ($pkg.IsUpdateAvailable) { $updatesAvailable.Add(@{ Id = $pkg.Id Name = $pkg.Name InstalledVersion = $pkg.Version Source = $pkg.Source DisplayLine = "$($pkg.Name) ($($pkg.Id)) $($pkg.Version)" }) } } # Save to cache try { $cacheData = @{ LastChecked = (Get-Date).ToString('o') Updates = @($updatesAvailable) } | ConvertTo-Json -Depth 5 [System.IO.File]::WriteAllText($cacheFile, $cacheData, [System.Text.Encoding]::UTF8) } catch { Write-Verbose "Failed to save update cache: $_" } } if ($updatesAvailable.Count -eq 0) { Write-Host "[OK] All packages are up to date!" -ForegroundColor Green return } Write-Host "" Write-Host " - " -ForegroundColor Green -NoNewline Write-Host "$($updatesAvailable.Count)" -ForegroundColor White -NoNewline Write-Host " update(s) available" -ForegroundColor Green Write-Host "" # HTML Export if ($ExportHtml) { Write-Host "`n[HTML] Exporting HTML report..." -ForegroundColor Cyan $timestamp = (Get-Date).ToString("yyyyMMdd_HHmmss") $defaultPath = "C:\temp\WingetBatch_Updates_$timestamp.html".Replace(' ', '_') $exportPath = Read-Host "Enter path for HTML report [Default: $defaultPath]" if (-not $exportPath) { $exportPath = $defaultPath } if (-not $exportPath.EndsWith(".html")) { $exportPath += ".html" } try { Export-WingetHtmlReport -Data $updatesAvailable -ReportTitle "Updates" -FilePath $exportPath if (Test-Path $exportPath) { Write-Host "[OK] Report successfully saved to $exportPath" -ForegroundColor Green Invoke-Item $exportPath } } catch { Write-Host "[FAIL] Failed to generate HTML report: $_" -ForegroundColor Red } } # Interactive selection if ($IWantToLiterallyUpdateAllFuckingResults) { $selectedPackages = $updatesAvailable | ForEach-Object { $_.Id } } elseif (Get-Module -Name PwshSpectreConsole) { try { $displayToId = @{} $displayLines = $updatesAvailable | ForEach-Object { $display = $_.DisplayLine $displayToId[$display] = $_.Id $display } $selectedLines = Read-SpectreMultiSelection -Title "[cyan]Select packages to update (Space to toggle, Enter to confirm)[/]" ` -Choices $displayLines ` -PageSize 20 ` -Color "Green" if ($selectedLines.Count -eq 0) { Write-Host "No packages selected." -ForegroundColor Yellow return } $selectedPackages = $selectedLines | ForEach-Object { $displayToId[$_] } } catch { Write-Warning "Interactive selection error: $_" Write-Host "Packages with updates available:" -ForegroundColor Cyan $updatesAvailable | ForEach-Object { Write-Host " - $($_.Id)" -ForegroundColor White } Write-Host "" Write-Host "Use 'Update-WinGetPackage -Id <PackageName>' to update manually." -ForegroundColor Yellow return } } else { # Fallback without interactive selection Write-Host "Packages with updates available:" -ForegroundColor Cyan $updatesAvailable | ForEach-Object { Write-Host " - $($_.Id)" -ForegroundColor White } Write-Host "" Write-Host "To update a package: " -ForegroundColor Cyan -NoNewline Write-Host "Update-WinGetPackage -Id <PackageName>" -ForegroundColor Yellow Write-Host "To update all: " -ForegroundColor Cyan -NoNewline Write-Host "Get-WingetUpdates -IWantToLiterallyUpdateAllFuckingResults" -ForegroundColor Yellow return } Write-Host "" Write-Host "Updating " -ForegroundColor Cyan -NoNewline Write-Host "$($selectedPackages.Count)" -ForegroundColor White -NoNewline Write-Host " package(s)..." -ForegroundColor Cyan Write-Host "" $successCount = 0 $failCount = 0 foreach ($packageId in $selectedPackages) { Write-Host ">>> Updating: " -ForegroundColor Magenta -NoNewline Write-Host $packageId -ForegroundColor White try { $result = Update-WinGetPackage -Id $packageId -Mode Silent -ErrorAction Stop Write-Host "[OK] Successfully updated " -ForegroundColor Green -NoNewline Write-Host $packageId -ForegroundColor White $successCount++ } catch { Write-Host "[FAIL] Failed to update " -ForegroundColor Red -NoNewline Write-Host $packageId -ForegroundColor White -NoNewline Write-Host " ($_)" -ForegroundColor Red $failCount++ } Write-Host "" } Write-Host ("=" * 60) -ForegroundColor Green Write-Host "Update Complete" -ForegroundColor Green Write-Host ("=" * 60) -ForegroundColor Green Write-Host " - " -ForegroundColor Green -NoNewline Write-Host $successCount -ForegroundColor White -NoNewline Write-Host " | Failed: " -ForegroundColor Red -NoNewline Write-Host $failCount -ForegroundColor White # Clear cache after updates if (Test-Path $cacheFile) { Remove-Item $cacheFile -Force } } |