PowerShell 卸载应用成功后,为什么 if 仍输出失败?
应用已经卸载成功,却输出 Removal Failed,是因为 Remove-AppxPackage 成功时不返回输出对象。原来的 if 判断的是管道输出转换后的布尔值,无法据此判断卸载操作是否成功。
可以将卸载命令放在 try/catch 中,并加上 -ErrorAction Stop。命令正常执行完毕后输出成功信息;发生错误时进入 catch。
为什么原来的 if 会进入 else
问题出在这一行:
if ((Get-AppxPackage -Name $AppName | Remove-AppxPackage -AllUsers))
PowerShell 会执行括号中的管道,再将它的成功输出转换成布尔值。Remove-AppxPackage 成功卸载时不返回对象,因此这里得到的是空输出,条件判定为假,程序进入 else。
如果 Get-AppxPackage 没有找到匹配的应用,管道同样没有输出,也会进入 else。因此,这个条件无法区分“卸载成功”和“没有找到应用”。
移除 Provisioned package 的命令放在 if 分支中。出现上述空输出时,这一步也不会执行。
使用 try/catch 处理卸载结果
下面的写法分别查询已安装的应用和 Provisioned package,处理没有匹配项的情况,再依次执行移除操作:
foreach ($AppName in $AppsToRemove) {
Write-Host "Attempting to remove $AppName..."
try {
# Find installed packages for all users.
$packages = @(
Get-AppxPackage -Name $AppName -AllUsers -ErrorAction Stop
)
# Find provisioned packages in the online Windows image.
$provisionedPackages = @(
Get-AppxProvisionedPackage -Online -ErrorAction Stop |
Where-Object { $_.DisplayName -like $AppName }
)
if ($packages.Count -eq 0 -and $provisionedPackages.Count -eq 0) {
Write-Host "No matching package found: $AppName"
continue
}
foreach ($package in $packages) {
Remove-AppxPackage `
-Package $package.PackageFullName `
-AllUsers `
-ErrorAction Stop
}
foreach ($package in $provisionedPackages) {
Remove-AppxProvisionedPackage `
-Online `
-PackageName $package.PackageName `
-ErrorAction Stop | Out-Null
}
Write-Host "Removal Successful: $AppName"
}
catch {
Write-Warning "Removal Failed for ${AppName}: $($_.Exception.Message)"
}
}
这段代码中:
-ErrorAction Stop将这些命令产生的非终止错误提升为终止错误,使catch能够捕获。只添加try/catch,可能仍然捕获不到这类错误。@(...)将查询结果收集为数组,方便在结果为零个、一个或多个时统一检查.Count。Out-Null用于丢弃Remove-AppxProvisionedPackage的正常输出,不会隐藏错误。- 成功提示放在所有移除命令之后,表示本轮匹配到的移除操作均已执行完,且没有抛出被捕获的错误。
注意查询范围和部分成功的情况
原代码中的 Get-AppxPackage -Name $AppName 只查询当前用户,后面的卸载却使用了 -AllUsers。示例将查询也改为 -AllUsers,使其与原来的卸载范围一致。执行涉及所有用户和在线 Windows 映像的操作时,需要以管理员身份运行 PowerShell。
已安装的 Appx package 和 Provisioned package 是两类处理对象。移除 Provisioned package 主要用于阻止该应用自动安装到以后创建的用户账户,并不等于已经移除了现有用户安装的应用。
try/catch 不提供回滚。如果已安装应用移除成功,但 Provisioned package 移除失败,脚本会输出失败信息,已经完成的操作仍然有效。排查时应查看具体错误;如果需要确认最终状态,应重新查询相应的已安装包和 Provisioned package。
备注:内容仅供参考。
