环境:Windows 11、VMware Workstation Pro 17.6.4。本文记录一次真实卸载故障:通过日志定位到虚拟网络注册表权限异常,修复后成功卸载。
适用范围:卸载日志停在
VM_UninstallNetworking,且 VMware 日志出现VMnetBridge权限异常。其他原因引起的 1603,需要另行排查。
一、问题现象
卸载 VMware Workstation Pro 时,向导弹出:
text
VMware Workstation 安装向导提前结束
由于发生错误,VMware Workstation Pro 安装向导提前结束。
您的系统尚未修改。
明明在卸载,为什么提示"安装向导"?因为安装、修改和卸载共用 Windows Installer 安装包及相关向导。这段提示只能说明操作失败,无法直接指出原因。
本次故障中,没有正在运行的虚拟机进程;以管理员身份执行卸载,仍然返回错误 1603。
二、先看日志,1603 只是结果
1603 是 Windows Installer 的通用失败代码,不能仅凭这个数字判断故障原因。需要结合失败步骤和组件日志定位。
1. 找到安装记录和产品代码
在 PowerShell 中查询卸载注册表,避免使用可能触发 MSI 一致性检查的 Win32_Product:
powershell
$paths = @(
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
Get-ItemProperty $paths -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -match 'VMware Workstation' } |
Select-Object DisplayName, DisplayVersion, PSChildName,
UninstallString, InstallSource
本机查到的版本为 17.6.4,产品代码为:
text
{6EC7759F-B700-4743-BB65-BD3ED905D545}
产品代码来自本机安装记录,不同版本或安装包可能不同,不要直接套用。
2. 生成详细卸载日志
关闭 VMware 和虚拟机,在"以管理员身份运行"的 PowerShell 中执行:
powershell
# 替换为你查到的产品代码
$productCode = '{6EC7759F-B700-4743-BB65-BD3ED905D545}'
$logPath = Join-Path $env:TEMP 'vmware-uninstall.log'
$arguments = '/x {0} /qn /norestart /L*v "{1}"' -f $productCode, $logPath
$process = Start-Process msiexec.exe -ArgumentList $arguments -Wait -PassThru
$process.ExitCode
参数含义:
| 参数 | 用途 |
|---|---|
/x |
卸载指定产品 |
/qn |
静默执行,不显示安装界面 |
/norestart |
不自动重启电脑 |
/L*v |
输出详细日志 |
本次日志中的关键内容是:
text
CustomAction VM_UninstallNetworking returned actual error code 1603
失败点明确落在 VM_UninstallNetworking,也就是 VMware 虚拟网络组件的卸载步骤。
中文系统的 MSI 日志可能使用"返回值 3",英文日志中通常为 Return value 3。搜索这些标记并查看前面的内容,有助于找到失败操作。
3. 查看 VMware 组件日志
本次 VMware 的详细日志位于当前用户临时目录:
powershell
Select-String -Path "$env:TEMP\vminst.log" `
-Pattern 'VNLCopyBridgeConfiguration', 'bogus', 'VMnetBridge' |
Select-Object -Last 20
关键警告指向 VMnetLib\VMnetBridge,并包含:
text
permissions ... appear to be bogus
这比单独一个 1603 更有价值:它把排查范围缩小到了 VMware 虚拟网络配置的注册表访问权限。
如果当前临时目录没有该文件,应结合实际运行账户、日志时间和安装程序输出寻找,不能把旧日志当作本次故障证据。
三、根因:32 位注册表视图中的权限异常
64 位 Windows 同时提供 32 位和 64 位注册表视图。同样的逻辑路径:
text
HKLM\SOFTWARE\VMware, Inc.\VMnetLib
在不同视图下可以对应不同的配置。32 位视图通常可在注册表编辑器中通过以下路径看到:
text
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\VMware, Inc.\VMnetLib
本次排查先处理了 64 位视图,卸载仍然失败。随后通过 .NET 注册表 API 显式检查两个视图,才发现 32 位视图中的 VMnetBridge 权限异常。
该项的访问规则只保留了当前用户的一条受限授权,缺少供系统账户和管理员组使用的显式完整控制规则。修复这一视图后,卸载程序顺利通过了此前失败的网络清理步骤。
因此,本次故障可以确认的直接阻塞点是相关注册表权限。至于权限最初由什么操作或程序改变,现有日志无法确定。
四、解决方案:备份配置,修复权限,再正常卸载
下面给出根据本次排查整理的修复示例。它只处理日志指向的 32 位 VMware 网络配置项,不要用于没有相同日志证据的其他故障。
1. 备份两个注册表视图
在管理员 PowerShell 中执行:
powershell
$backupDir = Join-Path $env:TEMP (
'VMware-Uninstall-Backup-' + (Get-Date -Format 'yyyyMMdd-HHmmss')
)
New-Item -ItemType Directory -Path $backupDir -Force | Out-Null
& reg.exe export 'HKLM\SOFTWARE\VMware, Inc.\VMnetLib' `
(Join-Path $backupDir 'VMnetLib-32.reg') /y /reg:32
& reg.exe export 'HKLM\SOFTWARE\VMware, Inc.\VMnetLib' `
(Join-Path $backupDir 'VMnetLib-64.reg') /y /reg:64
.reg 导出保存键和值,不保存访问权限。下面的脚本还会单独保存修改前的权限描述符。
2. 显式打开 32 位视图并修复访问规则
继续在同一个管理员 PowerShell 窗口中执行:
powershell
$ErrorActionPreference = 'Stop'
$subKeys = @(
'SOFTWARE\VMware, Inc.\VMnetLib'
'SOFTWARE\VMware, Inc.\VMnetLib\VMnetBridge'
)
$root = [Microsoft.Win32.RegistryKey]::OpenBaseKey(
[Microsoft.Win32.RegistryHive]::LocalMachine,
[Microsoft.Win32.RegistryView]::Registry32
)
try {
foreach ($subKey in $subKeys) {
$key = $root.OpenSubKey(
$subKey,
[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
[System.Security.AccessControl.RegistryRights]::ReadPermissions -bor
[System.Security.AccessControl.RegistryRights]::ChangePermissions
)
if ($null -eq $key) {
throw "注册表项不存在:$subKey;请重新核对日志与注册表视图。"
}
try {
$acl = $key.GetAccessControl()
# 单独备份原权限描述符;.reg 文件不包含权限。
$sddl = $acl.GetSecurityDescriptorSddlForm(
[System.Security.AccessControl.AccessControlSections]::Access
)
[pscustomobject]@{
View = 'Registry32'
Key = $subKey
Dacl = $sddl
} | ConvertTo-Json -Compress |
Add-Content -Path (Join-Path $backupDir 'permissions.jsonl')
# 使用 SID,避免不同 Windows 显示语言造成账户名称不匹配。
foreach ($sidText in @('S-1-5-18', 'S-1-5-32-544')) {
$sid = [System.Security.Principal.SecurityIdentifier]::new($sidText)
$rule = [System.Security.AccessControl.RegistryAccessRule]::new(
$sid,
[System.Security.AccessControl.RegistryRights]::FullControl,
[System.Security.AccessControl.InheritanceFlags]::ContainerInherit,
[System.Security.AccessControl.PropagationFlags]::None,
[System.Security.AccessControl.AccessControlType]::Allow
)
$acl.SetAccessRule($rule)
}
$key.SetAccessControl($acl)
Write-Host "已修复:Registry32\$subKey"
}
finally {
$key.Dispose()
}
}
}
finally {
$root.Dispose()
}
两个 SID 的含义是:
| SID | 账户或组 |
|---|---|
S-1-5-18 |
本地系统账户 SYSTEM |
S-1-5-32-544 |
本地 Administrators 管理员组 |
脚本补充这两个主体的完整控制权限,并保留其他现有规则。如果执行时报"拒绝访问",应继续检查该键的所有者和拒绝规则,不要直接对整个注册表批量修改权限。
3. 重新卸载并检查返回码
重新执行前面的 msiexec /x 命令,建议使用新的日志文件名。
本次实际卸载最终返回:
text
UninstallExitCode=0
MainEngineThread is returning 0
说明 Windows Installer 已成功完成卸载。如果返回 3010,则表示操作成功,但需要重启;是否重启以实际结果为准。
五、如何确认已经卸载成功
除了查看成功返回码,还应核对安装记录和实际文件:
powershell
Get-ItemProperty $paths -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -match 'VMware Workstation' } |
Select-Object DisplayName, DisplayVersion
# 替换为自己的原安装路径
Test-Path -LiteralPath 'E:\vmware\vmware.exe'
Get-Service -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -match 'VMware' } |
Select-Object Name, Status
本机验证结果:
- VMware Workstation 安装记录已消失。
- 原路径下的
vmware.exe已移除。 - 此前发现的 VMware 相关服务已移除。
- 未手动删除虚拟机目录,虚拟机文件保留。
如果电脑还安装了其他 VMware 产品,仍有 VMware 服务不一定代表 Workstation 卸载失败,应核对服务所属产品。
六、这次排查的几个经验
- 先找失败步骤。
1603范围太大,VM_UninstallNetworking才能指明排查方向。 - 管理员权限不等于目标项权限正常。 提升运行权限无法自动修复注册表中已有的异常访问规则。
- 明确注册表视图。 只看 64 位视图,可能漏掉实际被组件访问的 32 位配置。
- 修复后走正常卸载流程。 直接删除安装目录可能留下驱动、服务和安装记录。
- 成功要有证据。 返回码、安装记录、主程序文件和相关服务共同验证,比只看向导关闭更可靠。
本次的故障链路是:32 位 VMware 网络配置权限异常 → 虚拟网络卸载动作失败 → MSI 返回 1603 → 向导提前结束。修复对应权限后,正常卸载流程即可完成。
参考资料
该资料用于理解 1603 与权限故障的关系;本文对 VMnetBridge 和注册表视图的判断依据为本机实际卸载日志与修复结果。