Public/Initialize-Winget.ps1
|
function Initialize-Winget { <# .SYNOPSIS Initializes winget and Microsoft.WinGet.Client module .DESCRIPTION Ensures winget is available by installing the Microsoft.WinGet.Client PowerShell module and bootstrapping winget if necessary. Works in both user and SYSTEM context. .PARAMETER Force Force reinstall even if already installed .EXAMPLE Initialize-Winget Ensures winget is available for use .EXAMPLE Initialize-Winget -Force Reinstalls/repairs winget components #> [CmdletBinding()] param( [Parameter()] [switch]$Force ) Write-PatchLog "Initializing winget..." -Type Info try { # Check if Microsoft.WinGet.Client module is installed $module = Get-Module -Name 'Microsoft.WinGet.Client' -ListAvailable -ErrorAction SilentlyContinue if (-not $module -or $Force) { Write-PatchLog "Installing Microsoft.WinGet.Client module..." -Type Info # Ensure NuGet provider is available $nuget = Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue if (-not $nuget -or $nuget.Version -lt [Version]'2.8.5.201') { Write-PatchLog "Installing NuGet provider..." -Type Info Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope AllUsers | Out-Null } # Set PSGallery as trusted if not already $repo = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue if ($repo.InstallationPolicy -ne 'Trusted') { Set-PSRepository -Name PSGallery -InstallationPolicy Trusted } # Install the module Install-Module -Name Microsoft.WinGet.Client -Force -Scope AllUsers -AllowClobber -ErrorAction Stop Write-PatchLog "Microsoft.WinGet.Client module installed successfully" -Type Info } else { Write-PatchLog "Microsoft.WinGet.Client module already installed (v$($module.Version))" -Type Info } # Import the module Import-Module Microsoft.WinGet.Client -Force -ErrorAction Stop # Bootstrap/repair winget package manager Write-PatchLog "Repairing WinGet package manager..." -Type Info Repair-WinGetPackageManager -AllUsers -Force -ErrorAction SilentlyContinue # Verify winget is working $testResult = Get-WinGetVersion -ErrorAction SilentlyContinue if ($testResult) { Write-PatchLog "Winget initialized successfully (v$testResult)" -Type Info return $true } else { throw "Winget verification failed" } } catch { Write-PatchLog "Failed to initialize winget: $_" -Type Error return $false } } function Test-WingetAvailable { <# .SYNOPSIS Tests if winget is available and functional .DESCRIPTION Checks if the Microsoft.WinGet.Client module is installed and winget is working .PARAMETER AutoInstall Automatically install winget if not available .EXAMPLE if (Test-WingetAvailable) { Get-WingetUpdates } .EXAMPLE Test-WingetAvailable -AutoInstall #> [CmdletBinding()] [OutputType([bool])] param( [Parameter()] [switch]$AutoInstall ) try { # Check for module $module = Get-Module -Name 'Microsoft.WinGet.Client' -ListAvailable -ErrorAction SilentlyContinue if (-not $module) { if ($AutoInstall) { return Initialize-Winget } return $false } # Import and test Import-Module Microsoft.WinGet.Client -Force -ErrorAction SilentlyContinue $version = Get-WinGetVersion -ErrorAction SilentlyContinue return ($null -ne $version) } catch { Write-Verbose "Winget check failed: $_" return $false } } function Get-WingetUpdates { <# .SYNOPSIS Gets available winget package updates .DESCRIPTION Returns a list of packages with available updates .PARAMETER IncludeUnknown Include packages with unknown versions (always show as update available) .EXAMPLE Get-WingetUpdates Lists all available updates .EXAMPLE Get-WingetUpdates -IncludeUnknown Lists all updates including those with unknown version info #> [CmdletBinding()] param( [Parameter()] [switch]$IncludeUnknown ) if (-not (Test-WingetAvailable -AutoInstall)) { Write-PatchLog "Winget not available" -Type Error return @() } try { Write-PatchLog "Checking for winget package updates..." -Type Info $packages = Get-WinGetPackage -ErrorAction Stop | Where-Object { $_.IsUpdateAvailable -or ($IncludeUnknown -and $_.InstalledVersion -eq 'Unknown') } $updates = foreach ($pkg in $packages) { [PSCustomObject]@{ Id = $pkg.Id Name = $pkg.Name InstalledVersion = $pkg.InstalledVersion AvailableVersion = $pkg.AvailableVersion Source = $pkg.Source } } Write-PatchLog "Found $($updates.Count) packages with updates available" -Type Info return $updates } catch { Write-PatchLog "Failed to get winget updates: $_" -Type Error return @() } } function Install-WingetUpdate { <# .SYNOPSIS Installs a winget package update .DESCRIPTION Updates a specific package using winget .PARAMETER Id The winget package ID to update .PARAMETER Silent Install silently without user interaction .PARAMETER AcceptPackageAgreements Automatically accept package license agreements .EXAMPLE Install-WingetUpdate -Id 'Google.Chrome' .EXAMPLE Install-WingetUpdate -Id 'Mozilla.Firefox' -Silent #> [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [string]$Id, [Parameter()] [switch]$Silent, [Parameter()] [switch]$AcceptPackageAgreements ) process { if (-not (Test-WingetAvailable)) { Write-PatchLog "Winget not available" -Type Error return [PSCustomObject]@{ Id = $Id Success = $false Message = 'Winget not available' } } try { Write-PatchLog "Updating package: $Id" -Type Info $updateParams = @{ Id = $Id } if ($Silent) { $updateParams['Mode'] = 'Silent' } $result = Update-WinGetPackage @updateParams -ErrorAction Stop $success = $result.Status -eq 'Ok' $message = if ($success) { "Successfully updated $Id" } else { "Update failed: $($result.Status)" } Write-PatchLog $message -Type $(if ($success) { 'Info' } else { 'Error' }) return [PSCustomObject]@{ Id = $Id Success = $success Message = $message RebootRequired = $result.RebootRequired } } catch { Write-PatchLog "Failed to update $Id : $_" -Type Error return [PSCustomObject]@{ Id = $Id Success = $false Message = $_.Exception.Message } } } } function Add-WingetSource { <# .SYNOPSIS Adds a custom winget source .DESCRIPTION Adds a private or custom winget repository source .PARAMETER Name Name for the source .PARAMETER Url URL of the source .PARAMETER Type Source type (default: Microsoft.Rest) .EXAMPLE Add-WingetSource -Name 'PrivateRepo' -Url 'https://winget.contoso.com/api' #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Name, [Parameter(Mandatory)] [string]$Url, [Parameter()] [string]$Type = 'Microsoft.Rest' ) try { # Check environment variable override if ($env:PSPMPC_WINGET_SOURCE) { $Url = $env:PSPMPC_WINGET_SOURCE Write-PatchLog "Using winget source from environment: $Url" -Type Info } Write-PatchLog "Adding winget source: $Name ($Url)" -Type Info # Use winget CLI for source management (not available in PowerShell module) $result = & winget source add --name $Name --arg $Url --type $Type --accept-source-agreements 2>&1 if ($LASTEXITCODE -eq 0) { Write-PatchLog "Successfully added winget source: $Name" -Type Info return $true } else { Write-PatchLog "Failed to add winget source: $result" -Type Warning return $false } } catch { Write-PatchLog "Failed to add winget source: $_" -Type Error return $false } } |