是否可以检查哪些 MSI 包依赖于特定包?

Is it possible to check which MSI packages depend on a specific package?

如标题所示,当我有一些 MSI 包时,是否可以查看哪些其他包依赖于它?如果是,如何?

如果那不可能,是否至少可以告诉 Msiexec 根据需要卸载所有依赖包?

两者都不是。 Windows 安装程序跟踪包对组件的依赖性,但不跟踪包之间的依赖性。在某些情况下,您可能能够推断出包级别的依赖关系,例如通过阅读系统搜索,但这里没有 Windows 安装程序的原生内容。

这就是您看到建议将 Visual C++ 作为单独的 .msi(或 .exe)安装 运行 次的人与建议通过合并其合并模块安装它的人之间存在紧张关系的部分原因.前者更容易推理,但只有后者才能对依赖它的包进行适当的引用计数。

简而言之:是和否。我猜。可以按顺序安装几个 MSI 文件,但没有任何可靠的方法可以判断它们是否实际上与产品相关,但它们也可以通过各种机制捆绑在一起,因此它们可以作为 "single unit"(套件或引导程序,见下文),但安装后它们可能仍然 "tagged" 不属于一起。


将 MSI 设置捆绑在一起(启动器、引导程序、套件)

Installshield 等商业工具有“setup suites”,我认为它们被称为。我相信他们甚至可以在 Add/Remove 程序中拥有一个条目,但我不确定(我们并不总是能够访问所有最新版本的商业工具)。

WiX - 用于交付 MSI 文件的开源框架 - 具有称为 Burn 的功能(甚至可能是其他机制跟不上)。它允许您使用启动器 GUI 按顺序 运行 多个 MSI 文件。

还有其他解决方案,或 bootstrappers as I call them (here is one,未经我测试),用于按顺序安装 MSI 文件或安装先决条件 运行time 组件。

人们还可以滚动他们自己的启动器或安装程序 GUI,运行 MSI 安装程序或其他安装类型 "under the hood" 以任何需要的顺序。 The installer for Visual Studio 带有这样一个 GUI,您可以在其中 select 安装不同的包。

重点是,通过 运行 安装这些启动器并检查它们安装的内容,您可以了解 "belong together". 检查供应商的设置下载站点并查看捆绑包中包含的内容。


相关 MSI 设置(升级 Table 和安装位置)

当 MSI 文件相互关联时,还有一些其他线索。 里面的“升级 table” MSI 将指定相关产品(以及用于安装它们的相关 MSI 文件)作为新 MSI 文件安装的一部分仅被检测或被检测和卸载。这是 Windows 安装程序升级机制的一部分,被称为 重大升级 。此 table 具有很大的灵活性,因此您可以检测产品而不卸载它们而是继续,或者您可以检测产品并拒绝安装(例如,如果发现安装了更高版本的 MSI)。 请注意,升级 table 通常不会检测其他相关产品(尽管它可以),而是检测同一产品的不同版本,这些产品将作为主要升级操作的一部分进行升级。 作为技术花絮,我在下面添加了一个部分,介绍如何查找指定升级代码的所有相关产品代码。

最后,这可能是最简单的"clue" - 您可以检查 ProgramFilesFolder 下 MSI 的主要安装位置等级制度。该位置通常会按照以下几行显示公司名称和产品名称:ProgramFilesFolder\Company Name\Product Name - 您可以向其中添加一个可能的主要版本名称。安装到同一 Company Name 文件夹的 MSI 文件可能是相关的。

并检查此答案的底部是否有可能使用 MSI 软件包的“安装日期”来确定同时安装了哪些软件包(表明相关).同样,MSI 文件的“制造商/出版商”可以指示 "common descent"。可能还有“Install Source”(磁盘上最初安装 运行 或启动的位置)。


我希望这能回答您的问题。正如 Urman 指出的那样,很难判断已安装的 MSI 需要哪些先决条件包,但您可以使用依赖项扫描器来确定 运行 次主应用程序二进制文件必须获得线索。 这完全取决于您真正的问题是什么以及您想要弄清楚什么。

Urman 提到的合并模块被编译到每个 MSI 中——我想是一种静态链接形式——因此你可以看到嵌入它的 MSI 需要这个先决条件。


技术花絮:查找相关产品代码

您可以通过 运行ning 以下 VBScript 找到共享相同升级代码的所有已安装 MSI 文件。您必须输入有效的升级代码(在您要为其查找相关产品的 MSI 属性 table 中找到)。

实际的 MSI API 调用是 Set upgrades = installer.RelatedProducts(upgradecode) - 其余代码是支持结构。您可以尝试的示例升级代码可能是 {AA783A14-A7A3-3D33-95F0-9A351D530011} - Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148(如果您安装了它)。它是 3 个相关的 MSI 软件包之一,因此您可以获得 3 个产品代码 - 前提是首先安装了该软件包:

Dim relatedproductcodes, upgradecode : relatedproductcodes = "No related product codes found"
Dim installer : Set installer = CreateObject("WindowsInstaller.Installer")
upgradecode = InputBox("Please paste or type in the upgrade code you want to find all related product codes for." + _
              vbNewLine + vbNewLine + "Upgrade codes are found in an MSI's Property table, if it has been defined.", + _ 
              "Find Related Product Codes:")
If upgradecode = vbCancel Or Trim(upgradecode) = "" Then
   WScript.Quit(0)
End If

On Error Resume Next
Set upgrades = installer.RelatedProducts(upgradecode)
If (Err.number <> 0) Then
   MsgBox "Invalid upgrade code - aborting.", vbCritical, "Fatal error."
   WScript.Quit(2) ' Following exit code "standard" from MSI SDK automation samples
End If

If upgrades.Count > 0 Then relatedproductcodes = ""

For Each u In upgrades
    relatedproductcodes = relatedproductcodes & u & vbNewLine
Next

MsgBox "The related product codes for the specified Upgrade Code: " + vbNewLine + vbNewLine + relatedproductcodes

我怀疑这对你有多大用处,我只是想告诉你它是如何有用的。如果是,那么我有一个更全面的脚本供我自己使用,它将生成一个完整的 MSI 相关信息列表作为 html 导出 - 包括相关的产品代码。

UPGRADE:事实上,查看这样的 html 导出我可以看到“Install Date”列表显示包装盒上每个 MSI 软件包的安装顺序差不多 - 这是 软件包安装在一起的另一个指示,因此可以相关 。应该注意的是,这个日期不一定是安装的原始日期,而是它的最新日期 "modify operation"。所以不靠谱。

示例输出: