PAYATHON 2026

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。

备注:内容仅供参考。