You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Get-WmiObject Win32_Product远程卸载应用遇致命错误求助

远程卸载工具使用Get-WmiObject Win32_Product超时报错的问题分析与解决

问题原因分析

  • Win32_Product类的固有缺陷:调用这个WMI类时,系统会自动对所有已安装的MSI包执行一致性检查(验证文件完整性、修复损坏项),当目标机器安装了大量MSI包时,这个过程会耗时极长,甚至触发系统级的资源耗尽或超时。
  • Get-WmiObject的默认超时限制:该命令默认的连接超时为30秒,操作超时也有隐性限制,当WMI查询无法在限定时间内完成所有包的枚举与检查时,就会抛出无详细说明的致命错误。

解决办法

1. 替换Win32_Product,改用注册表读取已安装程序

Win32_Product不仅运行缓慢,还可能意外修改系统状态,读取注册表是更安全高效的方案。已安装程序的信息存储在以下注册表路径:

  • 32位程序:HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
  • 64位程序:HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*

远程读取注册表的示例代码:

$ComputerName = Read-Host -Prompt 'Input the computer name'

# 远程读取注册表获取已安装程序
$regPaths = @(
    "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
    "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)

$allApps = Invoke-Command -ComputerName $ComputerName -ScriptBlock {
    param($Paths)
    Get-ItemProperty -Path $Paths | Where-Object { $_.DisplayName -ne $null } | Select-Object DisplayName
} -ArgumentList $regPaths

$allApps | Select-Object DisplayName | Out-GridView -Title "All apps on destination Computer"

$Name = Read-Host -Prompt 'Input name of the application (has to be exact name)'
$appToUninstall = Invoke-Command -ComputerName $ComputerName -ScriptBlock {
    param($AppName)
    $uninstallPaths = @(
        "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
        "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
    )
    Get-ItemProperty -Path $uninstallPaths | Where-Object { $_.DisplayName -eq $AppName -and $_.UninstallString -ne $null }
} -ArgumentList $Name

if ($appToUninstall) {
    # 处理卸载字符串,适配msiexec参数格式
    $uninstallCmd = $appToUninstall.UninstallString -replace '^"([^"]+)"(.*)', '$1 $2' -replace '/I', '/X'
    Invoke-Command -ComputerName $ComputerName -ScriptBlock {
        param($Cmd)
        Start-Process -FilePath "msiexec.exe" -ArgumentList $Cmd -Wait -NoNewWindow
    } -ArgumentList $uninstallCmd
    "The removal was successful"
}
else {
    "$Name is not installed on $ComputerName"
}
Start-Sleep -Seconds 10

2. 调整WMI查询的超时参数(若坚持使用WMI)

如果必须保留WMI方式,可以使用PowerShell推荐的Get-CimInstance替代Get-WmiObject,它的超时设置更直观:

$ComputerName = Read-Host -Prompt 'Input the computer name'

# 设置操作超时为300秒(5分钟)
$allProducts = Get-CimInstance -ClassName Win32_Product -ComputerName $ComputerName -OperationTimeoutSec 300
$allProducts | Select-Object Name | Out-GridView -Title "All apps on destination Computer"

$Name = Read-Host -Prompt 'Input name of the application (has to be exact name)'
$Application = $allProducts | Where-Object {$_.Name -eq $Name}

if ($Application) {
    $Application | Invoke-CimMethod -MethodName Uninstall
    "The removal was successful"
}
else {
    "$Name is not installed on $ComputerName"
}
Start-Sleep -Seconds 10

3. 优化代码逻辑,避免重复查询

原代码两次调用WMI查询,会重复触发MSI一致性检查,可将第一次查询结果缓存,后续直接从缓存中筛选:

$ComputerName = Read-Host -Prompt 'Input the computer name'

# 仅执行一次WMI查询并缓存结果
$allProducts = Get-CimInstance -ClassName Win32_Product -ComputerName $ComputerName -OperationTimeoutSec 300
$allProducts | Select-Object Name | Out-GridView -Title "All apps on destination Computer"

$Name = Read-Host -Prompt 'Input name of the application (has to be exact name)'
$Application = $allProducts | Where-Object {$_.Name -eq $Name}

if ($Application) {
    $Application | Invoke-CimMethod -MethodName Uninstall
    "The removal was successful"
}
else {
    "$Name is not installed on $ComputerName"
}
Start-Sleep -Seconds 10

内容的提问来源于stack exchange,提问作者Minus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 10:30:29