winget-cli
winget-cli copied to clipboard
Add ability to list installed packages by `--installer-type` with `winget list`
Description of the new feature / enhancement
Just now I wondered what portable packages I've installed with Winget, and found that winget list doesn't really have such filtering capabilities.
Here's the current options with winget list:
- https://learn.microsoft.com/en-us/windows/package-manager/winget/list
- https://github.com/microsoft/winget-cli/blob/master/doc/windows/package-manager/winget/list.md
Here's the supported installer types:
- https://learn.microsoft.com/en-us/windows/package-manager/winget/#supported-installer-formats
Here's an example portable package:
- https://github.com/microsoft/winget-pkgs/blob/master/manifests/g/Gyan/FFmpeg/6.1/Gyan.FFmpeg.installer.yaml
Proposed technical implementation details
Add option to specify --installer-type with winget list.
Referencing a related issue:
- #1155
Here's a powershell script which takes a stab this, with a bunch of help from github copilot:
# Check if the Microsoft.WinGet.Client module is installed, and install it if not
if (-not (Get-Module -ListAvailable -Name Microsoft.WinGet.Client)) {
Write-Host "Microsoft.WinGet.Client module not found. Installing..."
Install-Module -Name Microsoft.WinGet.Client -Scope CurrentUser -Force -AllowClobber
}
Import-Module Microsoft.WinGet.Client
# Function to get the installer type of a package
function Get-InstallerType {
param (
[string]$packageId
)
# Run the winget show command and capture the output
$output = winget show $packageId
# Parse the output to find the installer type
$installerType = $output | Select-String -Pattern "Installer type" | ForEach-Object {
$_ -replace "Installer type\s*:\s*", ""
}
return $installerType
}
# Function to get information about non-standard IDs from the registry
function Get-NonStandardPackageInfo {
param (
[string]$packageId
)
$installerType = "Unknown"
# Extract the unique identifier at the end of the packageId
if ($packageId -match 'ARP\\Machine\\X64\\{(.+?)}') {
$uniqueId = $matches[1]
} elseif ($packageId -match 'ARP\\Machine\\X86\\(.+?)') {
$uniqueId = $matches[1]
} else {
$uniqueId = $packageId -replace '.*\\', ''
}
# Add braces if the unique identifier is a GUID
if ($uniqueId -match '^[0-9a-fA-F-]{36}$') {
$uniqueId = "{$uniqueId}"
}
$registryPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$uniqueId",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$uniqueId",
"HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$uniqueId"
)
foreach ($registryPath in $registryPaths) {
try {
$packageInfo = Get-ItemProperty -Path $registryPath -ErrorAction Stop
if ($packageInfo) {
$installerType = "MSI" # Default to MSI for ARP entries, adjust as needed
break
}
} catch {
Write-Host "Registry path not found: $registryPath"
}
}
return $installerType
}
# Function to get information about MSIX packages from the registry
function Get-MSIXPackageInfo {
param (
[string]$packageId
)
$installerType = "Unknown"
$uniqueId = $packageId -replace 'MSIX\\', ''
$registryPath = "HKLM:\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\$uniqueId"
try {
$packageInfo = Get-ItemProperty -Path $registryPath -ErrorAction Stop
if ($packageInfo) {
$installerType = "MSIX"
}
} catch {
Write-Host "Registry path not found: $registryPath"
}
return $installerType
}
# Get the list of installed packages
$installedPackages = Get-WinGetPackage
# Loop through each installed package
foreach ($package in $installedPackages) {
Write-Host "Processing package: $($package.Id)"
# Determine the installer type
if ($package.Id -match "^ARP") {
$installerType = Get-NonStandardPackageInfo -packageId $package.Id
} elseif ($package.Id -match "^MSIX") {
$installerType = Get-MSIXPackageInfo -packageId $package.Id
} else {
try {
# Get the installer type for the package and trim the result
$installerType = (Get-InstallerType -packageId $package.Id).Trim()
} catch {
# Log the error and set the installer type to "Error"
Write-Host "Error processing package $($package.Id): $_"
$installerType = "Error"
}
}
Write-Host "Installer Type: $installerType"
# Print the package details
Write-Output "Name: $($package.Name), Id: $($package.Id), Installer Type: $installerType"
}