Query WinGet software installer data with PowerShell

I’m a big fan of WinGet, and the software available in their ecosystem is growing daily. Still, I’m always curious about what WinGet will download and how it does the silent install of the specified software. In this blog post, I will show you an easy way of retrieving that data 🙂

What is WinGet?

“The WinGet command line tool enables users to discover, install, upgrade, remove and configure applications on Windows 10 and Windows 11 computers. This tool is the client interface to the Windows Package Manager service.”

Source: https://learn.microsoft.com/en-us/windows/package-manager/winget/

The WinGet repository and YAML

The WinGet client uses a GitHub repository to query for software, its installation links, and installation commands. That repository can be found here. There, you will find the manifests folder, in which all the software is structured per letter and version. For example, the latest Adobe Acrobat Reader 64-bit version is in the “a/Adobe/Acrobat/Reader/64-bit/24.003.20180” folder. That made me think I could find software based on the name and version using the WinGet PowerShell Module and read the YAML file inside the correct folder to see all the installation details.

An example YAML file, the one from the Adobe Acrobat Reader as mentioned above, looks like this:

# Created using wingetcreate 1.6.5.0
# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.6.0.schema.json

PackageIdentifier: Adobe.Acrobat.Reader.64-bit
PackageVersion: 24.003.20180
MinimumOSVersion: 10.0.0.0
InstallerType: exe
Scope: machine
InstallModes:
- interactive
- silent
- silentWithProgress
InstallerSwitches:
  Silent: /sAll /rs /rps /l /re
  SilentWithProgress: /sAll /rs /rps /l /re
UpgradeBehavior: install
FileExtensions:
- pdf
- pdfa
- pdfx
- xfx
ProductCode: '{AC76BA86-1033-FF00-7760-BC15014EA700}'
AppsAndFeaturesEntries:
- DisplayName: Adobe Acrobat DC (64-bit)
  Publisher: Adobe
  ProductCode: '{AC76BA86-1033-FF00-7760-BC15014EA700}'
  InstallerType: msi
Installers:
- Architecture: x64
  InstallerUrl: https://ardownload2.adobe.com/pub/adobe/acrobat/win/AcrobatDC/2400320180/AcroRdrDCx642400320180_MUI.exe
  InstallerSha256: 8DDE05B5A2F4E8550D54CD071BB9D57D273813B92E22E82124C18C8B948FF609
ManifestType: installer
ManifestVersion: 1.6.0

How the script works

As shown above, the information is in YAML format, so I can use the PowerShell-YAML module to parse that information and create a little report of one or more packages. The script will prompt you to enter the packages that you want to query and if you want the output on your screen (Default in List format, but ConsoleGridView and GridView are available. You can also output the results to a .csv or .xlsx file if needed. All the modules for the script will be installed automatically if required. If the WinGet client was not installed, it will install that, too 🙂

The Parameters that you can use when running the Get-WinGetData.ps1 script:

  • ApplicationName is the default and mandatory Parameter in which you can specify one or more applications you want to query. For example, Get-WinGetData.ps1 -ApplicationName Notepad, Adobe will list all the NotePad and Adobe applications in a ConsoleGridView pane in which you can select the ones that you want by selecting them with the spacebar and hitting Enter. (It will show two different ConsoleGridView panes, one for Notepad and one for Adobe)
  • Output is the Parameter with the ConsoleGridView, GridView, and List (Which is the default) values. For example, Get-WinGetData.ps1 -ApplicationName Notepad, Adobe -Output ConsoleGridView will show the results in a searchable Console GridView. It can be combined with the FilenameParameter.
  • Filename is the parameter to specify a .csv or .xlsx file to which to output the results. For example, Get-WinGetData.ps1 -ApplicationName Notepad, Adobe -Filename c:\temp\WinGet.xlsx will export the results to c:\temp\WinGet.xlsx. It can be combined with the Output Parameter, and the results will be appended to an Excel file if they already exist.

Note: Because I use the ConsoleGridView module, this script can only be run in PowerShell v7. It will exit if you run it in a lower version.

Running the script

Below is an example where I specify Adobe and Notepad as a query. I will select a few results for both and show the output on the screen and in the Excel file WinGet.xlsx. I did this by running:

.\Get-WinGetData.ps1 -ApplicationName Adobe, Notepad -Filename C:\Temp\WinGet.xlsx

In the first screen, I can select the desired Adobe software from the WinGet repository by choosing the items using the spacebar and hitting Enter:

I selected Adobe Acrobat Reader DC (64-bit) and Acrobat Pro (64-bit). On the next screen (After hitting Enter to Accept these two choices), I selected Notepad++ and XML Notepad and hit Enter to Accept those two:

It will show the progress of the four applications and output the information on the screen and where it saved the Excel file (c:\temp\WinGet.xlsx).:

As you can see, not all the software has all the information. Sometimes, the silent and silent with progress switches are unavailable (Depending on the type of software), or not all information was supplied in the YAML file.

The Excel file looks like this:

Wrapping up

In this blog post, I showed you how to query the WinGet repository and output the information about how it installs software on your system. It is easy for creating packages and an excellent reference for install links and installation switches 🙂

The script

Below are the contents of the Get-WinGetData.ps1 script. Save it to c:\scripts, for example, and use it to retrieve all the installation data available through the WinGet repository.

param (
    [Parameter(Mandatory = $true)][string[]]$ApplicationName,
    [Parameter(Mandatory = $false)][validateset('ConsoleGridView', 'GridView', 'List')][string]$Output = 'List',
    [Parameter(Mandatory = $false)][string]$Filename
)

#Check if running in PowerShell 7
if (-not ($PSVersionTable.PSVersion.Major -ge 7)) {
    Write-Warning ("Script is not running in required PowerShell version 7, exiting...")
    return
}
    
#Check if the required modules are installed
foreach ($module in 'Microsoft.WinGet.Client', 'Microsoft.PowerShell.ConsoleGuiTools', 'powershell-yaml', 'cobalt') {
    if (-not (Get-Module -Name $module -ListAvailable)) {
        try {
            Write-Warning ("The required module {0} was not found, installing now..." -f $module) 
            Install-Module -Name $module -Scope CurrentUser -AllowClobber:$true -ErrorAction Stop
            Import-Module -Name $module -ErrorAction Stop
        }
        catch {
            Write-Warning ("Error installing/importing required {0} module, exiting..." -f $module)
            return
        }
    }
    else {    
        try {
            Import-Module -Name $module -ErrorAction Stop
        }
        catch {
            Write-Warning ("Error importing required $module module, exiting...")
            return
        }
    }
}

#Check if WinGet is installed, install if not
if (-not (Get-AppxPackage -Name Microsoft.DesktopAppInstaller)) {
    try {
        $progressPreference = 'silentlyContinue'
        Write-Warning ("WinGet client was not found, installing now...")
        Invoke-WebRequest -Uri https://aka.ms/getwinget -OutFile $env:temp\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -UseBasicParsing -ErrorAction Stop
        Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile $env:temp\Microsoft.VCLibs.x64.14.00.Desktop.appx -UseBasicParsing -ErrorAction Stop
        Invoke-WebRequest -Uri https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx -OutFile $env:temp\Microsoft.UI.Xaml.2.8.x64.appx -UseBasicParsing -ErrorAction Stop
        Add-AppxPackage $env:temp\Microsoft.VCLibs.x64.14.00.Desktop.appx -ErrorAction Stop
        Add-AppxPackage $env:temp\Microsoft.UI.Xaml.2.8.x64.appx -ErrorAction Stop
        Add-AppxPackage $env:temp\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -ErrorAction Stop
        Remove-Item $env:temp\Microsoft.VCLibs.x64.14.00.Desktop.appx -Force:$true -Confirm:$false -ErrorAction Stop
        Remove-Item $env:temp\Microsoft.UI.Xaml.2.8.x64.appx -Force:$true -Confirm:$false -ErrorAction Stop
        Remove-Item $env:temp\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -Force:$true -Confirm:$false -ErrorAction Stop
        $progressPreference = 'silentlyContinue'
    }
    catch {
        Write-Warning ("Error installing WinGet client, exiting...")
        return
    }
}
    
#Check $applicationname, select the application the from Out-ConsoleGridView
$Applications = foreach ($Application in $ApplicationName) {
    try {
        $results = Find-WinGetPackage $Application -Source WinGet -ErrorAction Stop | Out-ConsoleGridView -Title "Select the application from the list for selected $($Application) query" -OutputMode Multiple
        foreach ($result in $results) {
            [PSCustomObject]@{
                ID      = $result.ID
                Version = $result.Version
            }
        }
    }
    catch {
        Write-Warning ("The application(details) could not be found, exiting...")
        return
    }
}
    
#Loop through the applications and collect the details, exit if no applications were found or selected
if ($null -ne $Applications) {    
    $total = foreach ($item in $Applications | Sort-Object ID) {
        Write-Host ("Processing {0}..." -f $item.ID) -ForegroundColor Green
        try {
            $ApplicationYAML = Invoke-RestMethod ("https://raw.githubusercontent.com/microsoft/winget-pkgs/refs/heads/master/manifests/{0}/{1}/{2}/$($Item.ID).installer.yaml" -f $Item.ID.Substring(0, 1).ToLower(), $Item.ID.Replace('.', '/'), $Item.version) -UseBasicParsing -Method Get -ErrorAction Stop | ConvertFrom-Yaml -ErrorAction Stop
            foreach ($installer in $ApplicationYAML.Installers) {
                $applicationdetails = Get-WinGetPackageInfo -Id $item.ID -ErrorAction Stop
                [PSCustomObject]@{
                    'Name'                        = $item.ID
                    'Author'                      = if ($applicationdetails.Author) { $applicationdetails.Author } else { "Not found" }
                    'Version'                     = [version]$item.Version
                    'Release Date'                = if ($applicationdetails.'Release Date') { $applicationdetails.'Release Date' } else { "Not found" }
                    'Install Modes'               = if ($ApplicationYAML.InstallModes) { $ApplicationYAML.InstallModes -join ', ' } else { "Not found" }
                    'Installer Architecture'      = if ($installer.Architecture) { $installer.Architecture } else { "Not found" }
                    'Silent switches'             = if ($applicationYAML.InstallerSwitches.Silent) { $applicationYAML.InstallerSwitches.Silent } else { "Not found" }
                    'SilentWithProgress switches' = if ($applicationYAML.InstallerSwitches.SilentWithProgress) { $applicationYAML.InstallerSwitches.SilentWithProgress } else { "Not found" }
                    'Installer Type'              = if ($applicationYAML.InstallerType) { $applicationYAML.InstallerType } else { "Not found" }
                    'Installer URL'               = if ($installer.Installerurl) { $installer.Installerurl } else { "Not found" }
                    'HomePage'                    = if ($applicationdetails.HomePage) { $applicationdetails.HomePage } else { "Not found" }
                }
            }
        }
        catch {
            Write-Warning ("Error retrieving details for {0}" -f $item.id)
        }
    }
}
else {
    Write-Warning ("No applications were found or selected, exiting...")
    return
}
    
#If $total has items, output it to display or file
if ($null -ne $total) {
    #Display $total to the chosen $ouput value if $FileName was not used
    if ($Output) {
        switch ($Output) {
            ConsoleGridView {
                try {
                    $total | Sort-Object Name, Author, Version, 'Release Date', 'Installer Architecture' | Out-ConsoleGridView -Title 'WinGet Information'
                }
                catch {
                    Write-Warning ("Error sending information to Out-ConsoleGridview, exiting...")
                    return
                }
            }
            GridView { 
                try {
                    $total | Sort-Object Name, Author, Version, 'Release Date', 'Installer Architecture' | Out-GridView -Title 'WinGet Information'
                }
                catch {
                    Write-Warning ("Error sending information to Out-Gridview, exiting...")
                    return
                }
            }
            List { 
                try {
                    $total | Sort-Object Name, Author, Version, 'Release Date', 'Installer Architecture' | Format-List
                }
                catch {
                    Write-Warning ("Error sending information to Format-List, exiting...")
                    return
                }
            }
        }
    }

    #Export to file if $FileName was specified
    if ($Filename) {
        if ($Filename.EndsWith('csv')) {
            try {
                $total | Sort-Object Name, Author, Version, 'Release Date', 'Installer Architecture' | Export-Csv -Path $Filename -Encoding UTF8 -NoTypeInformation -Delimiter ';' -Append:$true -Force:$true -ErrorAction Stop
                Write-Host ('Exported WinGet package information to {0}' -f $Filename) -ForegroundColor Green
            }
            catch {
                Write-Warning ('Could not write {0}, check path and permissions. Exiting...' -f $Filename)
                return
            }
        }
        if ($Filename.EndsWith('xlsx')) {
            if (-not (Get-Module ImportExcel -ListAvailable)) {
                try {
                    Install-Module ImportExcel -Scope CurrentUser -ErrorAction Stop
                    Import-Module ImportExcel -ErrorAction Stop
                    Write-Host ('Installed missing PowerShell Module ImportExcel which is needed for XLSX output') -ForegroundColor Green
                }
                catch {
                    Write-Warning ('Could not install missing PowerShell Module ImportExcel which is needed for XLSX output, exiting...')
                    return
                }
            }
            try {
                $total | Sort-Object Name, Author, Version, 'Release Date', 'Installer Architecture' | Export-Excel -Path $Filename -AutoSize -AutoFilter -Append:$true -ErrorAction Stop
                Write-Host ('Exported WinGet package information to {0}' -f $Filename) -ForegroundColor Green
            }
            catch {
                Write-Warning ('Could not write {0}, check path and permissions. Exiting...' -f $Filename)
                return
            }
        }
    }
}
else {
    Write-Warning ('Specified application(s) were not found, exiting...')
    return
}

Download the script(s) and the Excel file from GitHub here.

6 thoughts on “Query WinGet software installer data with PowerShell

  1. Hi. I’m running the script in PS 7.4.5 and it keeps telling me “WARNING: No applications were found or selected, exiting…”

    What can I check? I’ve tried your sample command and different outputs.

    1. That’s strange, it should only do that if the application name could not be found or if you don’t select anything in the console gridview. (You did select the titles/names that you want information from, right?) If so, and it still doesn’t return anything after running .\get-WinGetData.ps1 -ApplicationName Adobe, Notepad , for example, please run it with -Verbose ( .\get-WinGetData.ps1 -ApplicationName Adobe, Notepad -Verbose) and email me the output of that

      1. Well, I managed to figure this out about a minute before I got your response. Something was wonky with Winget so I did a quick nuke and pave. It’s working now! I’ll be trying a few things out in the morning – thanks so much!

Leave a Reply to Harm VeenstraCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.