mirror of
https://github.com/Raphire/Win11Debloat.git
synced 2026-08-22 07:36:25 +00:00
feat: add timeout for WinGet uninstall to prevent hanging (#731)
This commit is contained in:
@@ -96,24 +96,42 @@ function Remove-SelectedApps {
|
||||
Uninstalls an app via WinGet and/or schedules its removal.
|
||||
|
||||
.DESCRIPTION
|
||||
Runs winget uninstall for a single app. If the User or Sysprep
|
||||
parameter was passed, also schedules removal for future logins.
|
||||
Runs winget uninstall for a single app, with a bounded execution time.
|
||||
If the User or Sysprep parameter was passed, also schedules removal for
|
||||
future logins.
|
||||
|
||||
.PARAMETER app
|
||||
The WinGet package ID to uninstall (e.g. 'Microsoft.BingNews').
|
||||
|
||||
.PARAMETER TimeoutSeconds
|
||||
Maximum time to allow the foreground WinGet uninstall to run. Defaults
|
||||
to 120 seconds.
|
||||
#>
|
||||
function Remove-WinGetApp {
|
||||
param([string]$app)
|
||||
param(
|
||||
[string]$app,
|
||||
[int]$TimeoutSeconds = 120
|
||||
)
|
||||
|
||||
if (-not $script:WingetInstalled) {
|
||||
Write-Host "ERROR: WinGet is either not installed or is outdated, $app could not be removed" -ForegroundColor Red
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
Invoke-NonBlocking -ScriptBlock {
|
||||
param($appId)
|
||||
winget uninstall --accept-source-agreements --disable-interactivity --id $appId
|
||||
} -ArgumentList $app
|
||||
} -ArgumentList $app -TimeoutSeconds $TimeoutSeconds
|
||||
}
|
||||
catch {
|
||||
if ($_.Exception.Message -like 'Operation timed out after *') {
|
||||
Write-Host "WinGet uninstall for $app did not complete within $TimeoutSeconds seconds: $_" -ForegroundColor Red
|
||||
}
|
||||
else {
|
||||
Write-Host "WinGet uninstall for $app failed: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
if ($script:Params.ContainsKey("User")) {
|
||||
Write-Host "Adding scheduled task to uninstall $app for user $(Get-UserName)..."
|
||||
|
||||
@@ -2,7 +2,7 @@ BeforeAll {
|
||||
function Get-TargetUserForAppRemoval { 'AllUsers' }
|
||||
function Get-WingetInstalledApps { param($TimeOut, [switch]$NonBlocking) @() }
|
||||
function Test-AppInWingetList { param($appId, $InstalledList) $false }
|
||||
function Invoke-NonBlocking { param($ScriptBlock, $ArgumentList) }
|
||||
function Invoke-NonBlocking { param($ScriptBlock, $ArgumentList, $TimeoutSeconds) }
|
||||
function Get-UserName { 'Alice' }
|
||||
function Invoke-ForceRemoveEdge {}
|
||||
function Show-MessageBox { 'No' }
|
||||
@@ -109,6 +109,31 @@ Describe 'Remove-WinGetApp' {
|
||||
Should -Invoke Invoke-NonBlocking -Times 1 -Exactly -ParameterFilter { $ArgumentList -eq 'One.App' }
|
||||
Should -Invoke Set-RunOnceWingetTask -Times $Scheduled -Exactly -ParameterFilter { $appId -eq 'One.App' }
|
||||
}
|
||||
|
||||
It 'limits a foreground winget uninstall to two minutes' {
|
||||
Remove-WinGetApp -app 'One.App'
|
||||
Should -Invoke Invoke-NonBlocking -Times 1 -Exactly -ParameterFilter {
|
||||
$ArgumentList -eq 'One.App' -and $TimeoutSeconds -eq 120
|
||||
}
|
||||
}
|
||||
|
||||
It 'passes a specified foreground winget uninstall timeout' {
|
||||
Remove-WinGetApp -app 'One.App' -TimeoutSeconds 30
|
||||
Should -Invoke Invoke-NonBlocking -Times 1 -Exactly -ParameterFilter {
|
||||
$ArgumentList -eq 'One.App' -and $TimeoutSeconds -eq 30
|
||||
}
|
||||
}
|
||||
|
||||
It 'reports a timed-out winget uninstall and continues' {
|
||||
$script:Params = @{ User = 'Alice' }
|
||||
Mock Invoke-NonBlocking { throw 'Operation timed out after 120 seconds' }
|
||||
|
||||
{ Remove-WinGetApp -app 'One.App' } | Should -Not -Throw
|
||||
Should -Invoke Set-RunOnceWingetTask -Times 1 -Exactly
|
||||
Should -Invoke Write-Host -Times 1 -Exactly -ParameterFilter {
|
||||
$Object -like '*did not complete within 120 seconds*' -and $ForegroundColor -eq 'Red'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Remove-AppxApp' {
|
||||
|
||||
Reference in New Issue
Block a user