microsoft / microsoft/winget-cli

Previous Versions not removing on Winget update

Open
#6,474 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Command-Upgrade Issue-Bug PowerShell
Dominant language
C++
Stars
26.4k
Forks
1.8k
Avg merge
1d 11h
Merged PRs (30d)
15

Description

Relevant area(s)

PowerShell Module

Relevant command(s)

winget upgrade

Brief description of your issue

Hi,

Owing to CVE-2026-68821 where we need to update Winget/DesktopAppInstaller, I've been running through some upgrades in my lab environment and noticed some unusual behaviour.

First off, DesktopAppInstaller is not able to be uninstalled, from what I can see, it's by design.
When I update a device to the latest release, I can see both the old and new installed when using Get-AppXPackage, when I check which is provisioned, I can only see the latest version.

This then means, the updated version goes through completely fine, but it's not overwriting the older installed versions, leaving the vulnerability on the devices.

I've also tried to Set-NonRemovableAppsPolicy against the family, which doesnt work, and force register against the appxmanifest, which goes through, but the old version still lives on the device.

Since were utilising the likes of SCCM paired with either an application deployment (using the MSIX directly) or via a script install, Is there a suggested way to upgrade the application and force remove the older versions?

Steps to reproduce

Install Latest MSIX from GH Repo
Use - Get-AppxPackage -AllUsers | Where-Object {$_.Name -Like 'DesktopAppInstaller'}
Both old and new versions show in output

Try using the following script to install and register the software, however both versions still show when using the above query.

<#
.SYNOPSIS
Installs and registers the Windows Desktop App Installer.
.DESCRIPTION
Checks if Windows Desktop App Installer is present, compares the installed
version against the required version, If installed is not present or less
than required. The script will install all dependencies, install
Windows Desktop App Installer and then register the package.
.NOTES
Script Name: Install-WindowsDesktopAppInstaller.ps1
Author: Daniel Fletcher - 2026-08-18
Requires: Requires the following files "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle",
"AppXManifest.xml", "Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_Universal_X64.appx",
"Microsoft.VCLibs.140.00_14.0.33519.0_Universal_X64.appx", "Microsoft.WindowsAppRuntime.1.8_8000.879.2017.0_Universal_X64.msix"
.HISTORY
Version 1.0 - Script inception
#>

######################

MARK: Functions

######################

Log file path and name

$logFilePath = "C:\Windows\fndr\logs"
$logFileName = "$logFilePath\Install-WindowsDesktopAppInstaller.log"

Function to write logs

function Write-Log {
# Write-Log function version: 1.2
param (
[string]$message
)

$timestamp  = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logMessage = "$timestamp FNDR - $message"
Write-Output $logMessage

# Ensure log file path exists
if (-not (Test-Path $logFilePath)) {
    New-Item -Path $logFilePath -ItemType Directory | Out-Null
}

# Write log message to log file
Add-Content -Path $logFileName -Value $logMessage

# Prune log entries older than 90 days once per script execution
if (-not $script:LogPrunedThisRun -and (Test-Path $logFileName)) {
    $cutoff = (Get-Date).AddDays(-90)
    $lines  = Get-Content $logFileName | Where-Object {
        try {
            ([datetime]($_.Substring(0,19))) -ge $cutoff
        } catch {
            $true
        }
    }
    Set-Content -Path $logFileName -Value $lines
    $script:LogPrunedThisRun = $true
}

}

######################

MARK: Variables

######################

MSIX Variables

$dependencyPath = "C:\AppInstaller\Dependencies"
$msixPath = "C:\AppInstaller\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
$appName = "Microsoft.DesktopAppInstaller"

System Variables

$newInstall = $false

######################

MARK: Pre-Check

######################

Check if dependencies and MSIX bundle exist

if (-not (Test-Path -Path $dependencyPath)){
Write-Log "Dependency path does not exist. Exiting script."
exit 1
}

if (-not (Test-Path -Path $msixPath)){
Write-Log "MSIX Bundle is missing. Exiting script."
exit 1
}

Write-Log "Checking if $appName is installed"

$isInstalled = Get-AppxPackage -AllUsers | Where-Object {$_.Name -like "$appName"} | Sort-Object Version -Descending | Select-Object -First 1

if($isInstalled)
{
Write-Log "$appName is installed."
Write-Log "Current Installed Version: $($isInstalled.Version)"
}

Check if Desktop App is at the required version.

$requiredVersion = "1.30.100.0"

if ($isInstalled -and [version]$isInstalled.Version -eq [version]$requiredVersion) {
Write-Log "$appName is already at the required version. No action needed."
Exit 0
}

######################

MARK: Installation

######################

Install Dependencies

foreach($dependency in Get-ChildItem $dependencyPath){
Write-Log "attempting to install dependency: $($dependency.FullName)"
try{
Add-AppxPackage -Path $dependency.FullName -ErrorAction Stop
Write-Log "Dependency: $($dependency.FullName) installed"
}catch{
Write-Log "Failed to install dependency: $($dependency.FullName). ERROR: $_"
}
}

Start-Sleep 10

Write-Log "attempting to install $appName"
try{
Add-AppxPackage -Path $msixPath -AllUsers -ErrorAction Stop
Write-Log "$appName installed successfully"
$newInstall = $true
}catch{
Write-Log "Failed to install $appName. ERROR: $_"
}

Start-Sleep 10

######################
#MARK: Registration
######################

Attempting to register package

if ($newInstall -eq $true){
$manifest = Get-AppxPackage -AllUsers | Where-Object {$.Name -like "$appName"} | Sort-Object Version -Descending | Select-Object -First 1
$regParams =@{
Register ="$($manifest.InstallLocation)\AppXManifest.xml"
DisableDevelopmentMode = $true
ForceApplicationShutdown = $true
ForceUpdateFromAnyVersion = $true
ErrorAction = 'Stop'
}
Write-Log "Attempting to register $appName..."
try {
Add-AppxPackage @regParams
Write-Log "$appName registered successfully"
}catch{
Write-Log "Failed to register $appName. ERROR: $
"
}
}else{
Write-Log "Failed to install $appName, skipping registration"
exit 1
}

Expected behavior

Only latest version to show after an upgrade from the MSIX

Actual behavior

Both old and new versions show after installation of the MSIX

Environment
<#
.SYNOPSIS
    Installs and registers the Windows Desktop App Installer.
.DESCRIPTION
    Checks if Windows Desktop App Installer is present, compares the installed
    version against the required version, If installed is not present or less
    than required. The script will install all dependencies, install
    Windows Desktop App Installer and then register the package.
.NOTES
    Script Name: Install-WindowsDesktopAppInstaller.ps1
    Author: Daniel Fletcher - 2026-08-18
    Requires: Requires the following files "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle",
                "AppXManifest.xml", "Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_Universal_X64.appx",
                "Microsoft.VCLibs.140.00_14.0.33519.0_Universal_X64.appx", "Microsoft.WindowsAppRuntime.1.8_8000.879.2017.0_Universal_X64.msix"
.HISTORY
    Version 1.0 - Script inception
#>

######################
# MARK: Functions
######################

# Log file path and name
$logFilePath = "C:\Windows\fndr\logs"
$logFileName = "$logFilePath\Install-WindowsDesktopAppInstaller.log"

# Function to write logs
function Write-Log {
    # Write-Log function version: 1.2
    param (
        [string]$message
    )

    $timestamp  = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp FNDR - $message"
    Write-Output $logMessage

    # Ensure log file path exists
    if (-not (Test-Path $logFilePath)) {
        New-Item -Path $logFilePath -ItemType Directory | Out-Null
    }

    # Write log message to log file
    Add-Content -Path $logFileName -Value $logMessage

    # Prune log entries older than 90 days once per script execution
    if (-not $script:LogPrunedThisRun -and (Test-Path $logFileName)) {
        $cutoff = (Get-Date).AddDays(-90)
        $lines  = Get-Content $logFileName | Where-Object {
            try {
                ([datetime]($_.Substring(0,19))) -ge $cutoff
            } catch {
                $true
            }
        }
        Set-Content -Path $logFileName -Value $lines
        $script:LogPrunedThisRun = $true
    }
}

######################
# MARK: Variables
######################

# MSIX Variables
$dependencyPath = "C:\AppInstaller\Dependencies\"
$msixPath = "C:\AppInstaller\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
$appName = "Microsoft.DesktopAppInstaller"

# System Variables
$newInstall = $false

######################
# MARK: Pre-Check
######################

# Check if dependencies and MSIX bundle exist

if (-not (Test-Path -Path $dependencyPath)){
    Write-Log "Dependency path does not exist. Exiting script."
    exit 1
}

if (-not (Test-Path -Path $msixPath)){
    Write-Log "MSIX Bundle is missing. Exiting script."
    exit 1
}

Write-Log "Checking if $appName is installed"

$isInstalled = Get-AppxPackage -AllUsers | Where-Object {$_.Name -like "*$appName*"} | Sort-Object Version -Descending | Select-Object -First 1

if($isInstalled)
{
    Write-Log "$appName is installed."
    Write-Log "Current Installed Version: $($isInstalled.Version)"
}

# Check if Desktop App is at the required version.

$requiredVersion = "1.30.100.0"

if ($isInstalled -and [version]$isInstalled.Version -eq [version]$requiredVersion) {
    Write-Log "$appName is already at the required version. No action needed."
    Exit 0
}

######################
# MARK: Installation
######################

# Install Dependencies
foreach($dependency in Get-ChildItem $dependencyPath){
    Write-Log "attempting to install dependency: $($dependency.FullName)"
    try{
        Add-AppxPackage -Path $dependency.FullName -ErrorAction Stop 
        Write-Log "Dependency: $($dependency.FullName) installed"
    }catch{
        Write-Log "Failed to install dependency: $($dependency.FullName). ERROR: $_"
    }   
}

Start-Sleep 10

Write-Log "attempting to install $appName"
try{
    Add-AppxPackage -Path $msixPath -AllUsers -ErrorAction Stop
    Write-Log "$appName installed successfully"
    $newInstall = $true
}catch{
    Write-Log "Failed to install $appName. ERROR: $_"
}

Start-Sleep 10

######################
#MARK: Registration
######################

# Attempting to register package
if ($newInstall -eq $true){
    $manifest = Get-AppxPackage -AllUsers | Where-Object {$_.Name -like "*$appName*"} | Sort-Object Version -Descending | Select-Object -First 1
    $regParams =@{
        Register    ="$($manifest.InstallLocation)\AppXManifest.xml"
        DisableDevelopmentMode  = $true
        ForceApplicationShutdown    = $true
        ForceUpdateFromAnyVersion   = $true
        ErrorAction = 'Stop'
    }
    Write-Log "Attempting to register $appName..."
    try {
        Add-AppxPackage @regParams
        Write-Log "$appName registered successfully"
    }catch{
        Write-Log "Failed to register $appName. ERROR: $_"
    }
}else{
    Write-Log "Failed to install $appName, skipping registration"
    exit 1
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the upgrade with the provided MSIX and PowerShell commands, especially Get-AppxPackage -AllUsers, Add-AppxPackage, and registration through AppXManifest.xml. Compare the provisioned and installed package versions and document the supported upgrade or removal path; done means the old DesktopAppInstaller version no longer remains after the upgrade.

Written by the indexing model from the issue text.

Assessment

Tech stack
powershell
Domain
cli, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.