mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-08-09 09:31:15 +10:00
fix: resolve silent failures in AppX removal and PS7 DISM bugs (#4822)
* fix: resolve silent failures in AppX removal and PS7 DISM bugs
- Fixed a bug where Remove-AppxPackage failed silently in PowerShell 7 due to pipeline binding issues. We now explicitly loop through Get-AppxPackage results and pass PackageFullName directly.
- Added wildcard matching to Get-AppxPackage and Get-AppxProvisionedPackage to reliably locate packages regardless of short name vs family name variations.
- Offloaded Get-AppxProvisionedPackage and Remove-AppxProvisionedPackage execution to Windows PowerShell 5.1 (powershell.exe) to bypass PowerShell 7 DISM COM exceptions ("Class not registered") and performance hangs.
- Deduplicated AppX removal logic by calling Remove-WinUtilAPPX directly from Invoke-WPFAppxRemoval instead of copying the implementation.
* refactor(Remove-WinUtilAPPX): use script block to improve readability
* feat: enhance AppX removal process and add provisioned package removal function
* fix(tests): update AppX removal tests
This also adds tests for the new Remove-WinUtilProvisionedAPPX functionality
* Move AppX removal under Tweaks
* Address AppX removal review feedback
* Complete AppX removal error handling
* Prevent AppX cleanup confirmation prompts
---------
Co-authored-by: Chris Titus <contact@christitus.com>
This commit is contained in:
@@ -78,6 +78,7 @@ function Invoke-WinUtilTweaks {
|
||||
$sync.configs.tweaks.$CheckBox.appx | ForEach-Object {
|
||||
Remove-WinUtilAPPX -Name $psitem
|
||||
}
|
||||
Remove-WinUtilProvisionedAPPX -PackageList $sync.configs.tweaks.$CheckBox.appx
|
||||
}
|
||||
}
|
||||
Write-WinUtilLog -Component "Tweaks" -Message "$action tweak completed: $CheckBox"
|
||||
|
||||
@@ -17,7 +17,20 @@ function Remove-WinUtilAPPX {
|
||||
|
||||
Write-Host "Removing $Name"
|
||||
Write-WinUtilLog -Component "AppX" -Message "Removing AppX package pattern: $Name"
|
||||
Get-AppxPackage $Name -AllUsers | Remove-AppxPackage -AllUsers
|
||||
Get-AppxProvisionedPackage -Online | Where-Object DisplayName -like $Name | Remove-AppxProvisionedPackage -Online
|
||||
|
||||
# We explicitly loop through packages instead of using the pipeline because PowerShell 7 pipeline binding
|
||||
# for Remove-AppxPackage fails silently, and Get-AppxPackage -AllUsers returns duplicate objects for each user profile.
|
||||
$pkgs = Get-AppxPackage "*$Name*" -AllUsers | Sort-Object -Property PackageFullName -Unique
|
||||
if ($null -ne $pkgs) {
|
||||
foreach ($pkg in $pkgs) {
|
||||
try {
|
||||
Remove-AppxPackage -Package $pkg.PackageFullName -AllUsers -ErrorAction Stop
|
||||
}
|
||||
catch {
|
||||
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message "Failed to remove AppX package $($pkg.PackageFullName): $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-WinUtilLog -Component "AppX" -Message "AppX removal completed for package pattern: $Name"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
function Remove-WinUtilProvisionedAPPX {
|
||||
<#
|
||||
|
||||
.SYNOPSIS
|
||||
Removes all AppX provisioned packages that match the given names
|
||||
|
||||
.PARAMETER PackageList
|
||||
An array of names of the APPX packages to remove
|
||||
|
||||
.EXAMPLE
|
||||
Remove-WinUtilProvisionedAPPX -PackageList @("Microsoft.Microsoft3DViewer", "Microsoft.WindowsCalculator")
|
||||
|
||||
#>
|
||||
param (
|
||||
[string[]]$PackageList
|
||||
)
|
||||
|
||||
if ($null -eq $PackageList -or $PackageList.Count -eq 0) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "`nRemoving provisioned packages..."
|
||||
Write-WinUtilLog -Component "AppX" -Message "Removing AppX provisioned packages: $($PackageList -join ', ')"
|
||||
|
||||
# DISM cmdlets like Get-AppxProvisionedPackage often fail with "Class not registered" or hang in PowerShell 7.
|
||||
# We shell out to Windows PowerShell 5.1 (powershell.exe) to reliably remove the provisioned packages.
|
||||
$ps5Command = {
|
||||
$pkgs = $args
|
||||
$provisionedPackages = Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue
|
||||
$failures = [System.Collections.Generic.List[string]]::new()
|
||||
|
||||
foreach ($Package in $pkgs) {
|
||||
$provs = $provisionedPackages |
|
||||
Where-Object DisplayName -Like "*$Package*"
|
||||
|
||||
if ($null -ne $provs) {
|
||||
foreach ($prov in $provs) {
|
||||
try {
|
||||
Remove-AppxProvisionedPackage -Online -PackageName $prov.PackageName -ErrorAction Stop | Out-Null
|
||||
}
|
||||
catch {
|
||||
$failures.Add("Failed to remove provisioned AppX package $($prov.PackageName): $($_.Exception.Message)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($failures.Count -gt 0) {
|
||||
throw ($failures -join [Environment]::NewLine)
|
||||
}
|
||||
}
|
||||
|
||||
$removalOutput = powershell.exe -NoProfile -NonInteractive -Command $ps5Command -args $PackageList 2>&1
|
||||
if ($LASTEXITCODE -ne 0 -or $null -ne $removalOutput) {
|
||||
$failureDetails = ($removalOutput | Out-String).Trim()
|
||||
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message "AppX provisioned package removal failed: $failureDetails"
|
||||
return
|
||||
}
|
||||
|
||||
Write-WinUtilLog -Component "AppX" -Message "AppX provisioned package removal completed."
|
||||
}
|
||||
Reference in New Issue
Block a user