通过 msiexec 卸载 msi 失败并显示 'only valid for applications installed' 消息

Uninstalling msi via msiexec fails with a 'only valid for applications installed' message

我们有一个遗留软件安装,我们正试图从我们的组织中删除。我们有不同的版本,并正在尝试为所有版本创建一个通用的卸载程序。我们遇到了一个似乎无法通过命令行卸载的特定版本。事实证明很难创建解决方法。

我通过

在注册表中找到了应用程序的 GUID
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

而我运行的命令是:

msiexec /x {080FDF44-6D15-4D2E-977E-74D5168198E7}

我收到一个应用程序提示,询问我是否要卸载该产品,所以我单击 'Yes'。然后它看起来像是开始了,但实际上什么也没做。所以我翻遍了注册表并在以下位置找到了另一个 GUID:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\Userdata\S-1-5-18\ProductsFDF08051D6E2D479E7475D6118897E

如果我 运行 使用不同的 GUID 执行与上面相同的命令,我会收到要求卸载的应用程序确认框,然后在单击“确定”后,我会收到一条错误消息:

The installation package could not be opened. Verify the package exists and you can access it.......

我进入了 C:\Windows\Installer 到具有上述 GUID 的文件夹,里面只有一个图标和一个 *.mst 文件。在C:\Windows\Installer的根目录中,有一个*.msi,在详细信息中称为相同的产品,但版本ID为:

8A2C4F93-4B31-4474-B9F2-2E51BF5D71A8

如果我 运行 msiexec 针对该 ID 然后我再次收到一个确认框然后另一个错误说

The action is only valid for products that are currently installed.

如果我 运行 卸载程序,它可以很好地从程序和功能中卸载并使用生成的 *.msi 来卸载(例如 C:\Windows\Installer\241a6.msi 并匹配8A2C4F93-4B31-4474-B9F2-2E51BF5D71A8 的产品 ID)。这将改变机器的形式。关于如何以一种整洁和有管理的方式解决这个问题还有其他想法吗?

您无法挖掘 ProductCode guid 的注册表,因为它们已被混淆。如果您真的不知道 ProductCode,请查看枚举已安装产品的方法。例如,直接的 C++ 方式是 MsiEnumerateProducts 和 C# pinvoke 等价物,如下所示:

MSI Interop using MSIEnumRelatedProducts and MSIGetProductInfo

然后您将获得实际的 ProductCode,并可以通过它获取其他信息。

如果有时当您完全确定 ProductCode 时它不起作用,那么它可能安装在与您 运行 程序所使用的不同的每个用户上下文中。

此外,对于 MSI 安装的产品 Windows 不使用卸载字符串,它直接使用 ProductCode。同样,当存在专门用于枚举已安装 MSI 产品的实际 API 时,注册表疏浚不是正确的做法。

如果卸载需要访问安装它的原始 MSI,那么至少有两个原因:

  1. MSI 有一个无条件的 ResolveSource 操作,强制它请求原始 MSI 文件。

  2. MSI 文件的缓存版本已从 C:\windows\installer 中删除。