【问题标题】:Determine msiexec exit code when msi file already installed在已安装 msi 文件时确定 msiexec 退出代码
【发布时间】:2014-09-09 07:54:41
【问题描述】:

我在另一个进程中启动 msiexec 并等待退出:

var p = new Process
{
    StartInfo =
    {
        FileName = "msiexec",
        Arguments = string.Format("/i \"{0}\" /qb", @"c:\install\setup.msi"),
        Verb = "runas"
    }
};
p.Start();
p.WaitForExit();
int exitCode = p.ExitCode;

如果 setup.msi 之前没有安装,它会安装到静默模式并返回 0。正常。

但如果 setup.msi 已经安装(第二次启动此代码),安装不会开始并返回代码 0 - 成功结果!但实际上,文件并没有建立,因为产品已经安装好了。我如何确定这种情况?

【问题讨论】:

  • 如果该产品已安装,您应该得到 1638 作为错误代码,您是否尝试手动安装此 MSI 并查看您是否获得 产品已经存在 消息?
  • 当我手动开始安装时,我看到该产品已安装。有两个选项:修复和删除。但是,如果我在静默模式下使用参数启动 msiexec 返回成功代码 (0)。
  • 尝试 /passive 打开 msiexec
  • 添加了关于如何使用 MSI COM API 以 2 行检查安装状态的答案。

标签: c# .net windows-installer


【解决方案1】:

您收到了退出代码0,因为该产品已经安装并且您没有尝试安装新版本。换句话说,您的 MSI 没有新的产品代码和版本号,因此 MSIExec 安装程序将其视为重新配置并退出。我通过打开 /log switch 并在安装我的一个 MSI 文件两次后读取输出来对此进行了测试。

MSI (c) (98:EC) [15:19:27:912]:产品:产品名称 -- 配置 顺利完成。 MSI (c) (98:EC) [15:19:27:912]:Windows 安装人员重新配置了产品。产品名称:产品名称。 产品版本:4.8.22。产品语言:1033。制造商:制造商。重配置成功或错误状态:0。

如果您尝试安装产品的新版本并且未将 MSI 配置为删除以前的版本,您将收到错误代码 1638。在此处查看错误代码列表:MSDN

如果您想检查产品是否已经安装了现有的 MSI 信息(不是升级),您需要检查注册表:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\YourProductCode

如果事实证明它已安装(根据系统/注册表 - 可能文件已被删除但仍被认为已安装),您可以尝试使用 /x/uninstall switch 卸载它,然后重新安装.您也可以使用/fa 开关进行修复并重新安装所有文件。

msiexec.exe /x ProductCode 将卸载它。然后您可以在此之后再次运行安装。 msiexec.exe /fa ProductCode 将修复所有文件。 /f 开关对于如何重新安装文件有很多不同的选项,因此您最好阅读我在上面发布的 msiexec 开关文章的链接。

关于 msiexec 的一些其他说明:

/qb 显示基本用户界面。你可能想要/qn。 当我设置我的实时更新软件时,我遇到了一堆问题,我必须确保我使用

从 system32 调用 msiexec
p.StartInfo.FileName == Path.Combine(System.Environment.ExpandEnvironmentVariables("%windir%\\system32"), "MSIExec.exe"); 

【讨论】:

  • 添加了关于如何使用 MSI COM API 在 2 行中检查产品安装状态的快速答案。
【解决方案2】:

首先,关于 1638 返回码的其他评论有点误导。 当您第二次安装确切的 MSI 文件时,您会得到一个返回代码 0,就像您已经(并且正确地)观察到的那样。这是“正确”的行为,或者换句话说:这就是 MSI 的设计方式。 此外,在这种情况下,您现有的设置没有任何更改。如果您在第二次安装之前删除所有文件,尽管 MSI 返回零,但您最终将一无所有。 因此,仅返回代码并不能帮助您解决这种情况。

简而言之,你有以下几种可能:

  1. 简单但看起来不正常:只需在安装之前卸载(可能是静默)产品:

    msiexec /x {yourproductcode} /qn

(因为静默参数“/qn”,即使之前没有安装过产品也不会报错

  1. 如果您觉得够用,建议:如果您想再次安装,只需使用修复模式即可: 示例:

    msiexec /i ... REINSTALL=ALL REINSTALLMODE=vemus

  2. 最佳:使用启动器(boot-strapper 或其他名称是相同的东西)来测试产品是否已安装等。这样您可以自动化以前的选项(预卸载或添加修复参数)。这也可以用脚本来完成,但在每种情况下,这都是编程,所以不是最简单的方法。

现在我们来到其他答案中提到的 1638 返回码: 如果(且仅当)您的构建系统(如默认情况下 InstallShield 所做的那样)在每个构建中更改所谓的 MSI PackageCode)并且您尝试将这个略有不同的构建 (MSI) 更新为以前安装的, 你会得到 1638 返回码。

这些事情经常被误解。 为每个构建更改 PackageCode 是非常推荐的做法。 另一方面,如果您将此类 MSI 发布给您的客户,这不仅会使您的事情变得复杂一点。此更新类型的名称是“small update or minor upgrade”(它们的区别在这里并不重要,因为它对您有相同的限制。 如果你真的想用返回码解决你的问题,你可以使用它。但如前所述,您不会在第二次安装完全相同的 MSI 时获得 1638!

要继续关于更新的建议,还有更多方法:最容易处理的方法(对于初学者)是重大升级。这就是另一个答案中所谓的“新版本”,它没有错,但不是那么准确。 对于重大升级,您必须至少更改 MSI PackageCode 和 MSI ProductCode,建议同时更改 ProductVersion。 (另一种方法是使用 MSI 补丁作为增量更新,但这也不容易)。

【讨论】:

    【解决方案3】:

    MSI COM API:如果您可以使用 MSI COM API,您可以使用ProductState property。换句话说,如果您有实际的产品代码 (How can I find the product GUID of an installed MSI setup?),则可以使用两行代码检查已安装的产品:

    Dim installer : Set installer = CreateObject("WindowsInstaller.Installer")
    MsgBox installer.ProductState("{00000000-0000-0000-0000-000000000001}") ' <= PRODUCT CODE
    

    结果:正常状态是 5 表示已安装或 -1 表示未安装:

    INSTALLSTATE_UNKNOWN   -1  The product is neither advertised or installed.
    INSTALLSTATE_ADVERTISED 1  The product is advertised but not installed.
    INSTALLSTATE_ABSENT     2  The product is installed for a different user.
    INSTALLSTATE_DEFAULT    5  The product is installed for the current user.
    

    交互式 VBScript:这是一个更大版本的 VBScript,在 InputBox 中交互式输入产品 GUID - 以特别的方式与任何产品 GUID 一起使用:CheckProductState-Interactive.vbs


    链接

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-20
      • 1970-01-01
      • 2012-10-28
      • 1970-01-01
      相关资源
      最近更新 更多