【问题标题】:Uninstalling MSI-Package always gives reboot message卸载 MSI-Package 总是给出重启消息
【发布时间】:2018-05-24 17:53:43
【问题描述】:

我只是为一些新软件编写脚本。因此我必须删除一些旧软件。我正在使用 PS 脚本执行此操作。这几乎可以正常工作。提升的权限正在运行,软件已被删除,但第一次卸载时总会出现一条关于重新启动的消息。此消息只能通过按“确定”来确认。

现在我怎样才能强制消息不出现?

这是我在 PS 脚本中的内容:

start-process msiexec.exe -Wait -ArgumentList '/x "file.msi" /passive /norestart'

我也尝试了 /quiet 标志,但我什么也没看到(d'uh)并且软件仍然存在。

我必须重新启动是合乎逻辑的,但我只是不想看到该消息。我不确定它是来自 MSIEXEC 还是来自 MSI 文件本身的消息。谷歌找不到任何东西。

【问题讨论】:

    标签: windows-installer wmi ps


    【解决方案1】:

    这里可能有两个问题:

    1. 该消息似乎不是标准的 Windows Installer 重新启动请求。这意味着它来自自定义操作,因此它只是一些不关心任何 MSI 选项来控制重启的代码。如果您没有创作 MSI 并且您无法更改它,那么您将无能为力。

    2. 如果您对已安装的产品进行静默卸载,那么您不会被告知它是否失败,因为静默意味着没有 UI。特别是,如果卸载需要提升,那么如果任何地方都需要管理员权限,它将失败。另一方面,它可能由于某些其他原因而失败。如果您在显示一些 UI 或进度条的情况下正常尝试卸载会发生什么?此外,如果您将日志记录添加到您的 uniunstall 中,您可能会看到一个错误。添加类似 /l*vx [路径到日志文件]

    【讨论】:

      【解决方案2】:

      更新:事后想:检查这个对话框是否真的从InstallUISequence显示?如果它仅插入到InstallUISequence 中而不存在于InstallExecuteSequence 中,那么当您为您的设置触发静默安装/卸载时它将永远不会运行,因为在此安装模式下会跳过整个InstallUISequence

      QN 添加到msiexec.exe 命令行以静默运行。请参阅下面的示例。 如果你幸运的话,这可以解决你的整个问题,而无需任何下面提到的小升级或黑客攻击。所以检查一下。还要将 REBOOT=ReallySuppress 添加到所有静默 msiexec.exe 命令行 - 以防止标准 MSI 功能触发突然重启。


      REBOOT=ReallySuppress

      MSI 文件中有一个名为REBOOT 的属性,可以在msiexec.exe 命令行上将其设置为REBOOT=ReallySuppress,以禁止标准 MSI 计划重启。这对于静默安装尤其重要,否则可能会在没有警告的情况下触发自发重启(对于设计错误的非常糟糕的 MSI 文件 - 我在制作供企业使用的软件包时总是禁用 ScheduleRebootForceReboot - 重新启动知识工作者的 PC警告可以消除很多工作):

      msiexec.exe /x {11111111-1111-1111-1111-1111111111GH} REBOOT=ReallySuppress
      

      我还会使用旧式 msiexec.exe 开关:/x/i 等...而不是“便利功能”:/passive/norestart 等...只是我的两美分。

      供参考


      非标准重启

      但是,您发布的对话框似乎不标准。它实际上看起来像是从设置本身的自定义操作中显示的自定义对话框 - 这些将不符合 MSI 标准,您必须根据具体情况处理它们。

      我想这是一个安全的假设,即您要卸载的软件已经“在野外”并安装在您试图从中删除它的许多工作站上?鉴于这是一个正确的假设,我们在谈论清理多少台计算机?许多?数百?数千?如果 MSI 不存在,您可以调整它以在部署前通过转换删除对话框。只是为了将来提到这一点。从技术上讲,您可以通过将自定义操作的条件设置为 0 来做到这一点(如果为 false - 那么自定义操作将永远不会运行)。


      题外话:有一个可怕的“黑客”我从未尝试过,我只会作为支持人员用于单个计算机清理:How to apply a Msi transform at uninstall? 我不会使用它(除非我正在清理一台 PC - 例如开发盒)。

      也可以直接编辑缓存的 MSI(至少先备份):I screwed up, how can I uninstall my program?。也不建议这样做,除非您只有几个盒子需要手动清理。另外,通过修改条件设置自定义动作不运行,不要删除自定义动作。


      清理

      所以我想我们有几个选择:

      1. 找到在自定义操作条件中使用的 PUBLIC 属性,我们可以在 msiexec.exe 命令行上将其硬编码为 0 或取消定义(将其设置为空字符串),以防止自定义操作运行。请注意,在命令行上可能没有要覆盖的条件 - 这取决于设置设计。

        • 这可能有效,但如果该属性也通过 AppSearch、自定义操作或其他一些机制在 MSI 本身内部设置(MSI 具有许多“移动部件”,它们之间的交互方式可以使一个成年人哭泣)。这也可能间歇性地发生 - 换句话说,它可能不会发生在所有系统上。突然间它就炸了。相应地应用适当的偏执狂。只是我的两分钱。
        • 供应商也可以设置该属性,专门允许禁止重新启动对话框 - 在这种情况下,您可以使用它,但如果供应商这样做,我会感到非常惊讶。显示这样一个自定义重启对话框表明缺乏关于如何使用 MSI 的知识。但是请参阅下面ISSCHEDULEREBOOT 的最后一个要点...
        • 条件必须评估为假。因此,如果将DOREBOOT 指定为条件,则必须将其设置为等于命令行上的空字符串。这“取消定义”它 - MSI 会话中不存在该属性。换句话说设置 DOREBOOT=0 不会产生错误的条件! (如果自定义操作仅以 DOREBOOT 为条件 - 那么条件中没有指定值,并且检查属性是否有值。任何分配的值都会将条件评估为真 ):

          msiexec.exe /x {11111111-1111-1111-1111-1111111111GH} DOREBOOT=""
          
        • 如果 DOREBOOT=1 被指定为自定义操作的条件,那么您必须将属性值设置为其他值(以使条件评估为 false):

          msiexec.exe /x {11111111-1111-1111-1111-1111111111GH} DOREBOOT=0
          
        • 更复杂的是 - 好像以上还不够 - 必须将 DOREBOOT 属性列为“安全”属性,方法是将其添加到此类安全自定义属性列表中.保存此列表的属性称为SecureCustomProperties。它是一个分隔的属性列表,允许传递给非管理员用户的延迟安装模式。未能将 DOREBOOT 属性添加到此列表将导致此日志文件警告:“忽略不允许的属性 DOREBOOT” - 您为其设置的任何值都将被忽略并且没有影响。如果按计划进行,重启仍会发生。
        • 更新:在另一个有趣的转折中,看起来从提升的命令提示符启动的msiexec.exe 会话实际上确实接受了命令行上指定的属性值,即使它们没有设置为安全(假设你是以管理员身份运行),但是当您从非提升的命令提示符启动然后通过 UAC 对话框提升时 - 然后属性将被刷新并且不会在会话中应用。 错误或功能?我不知道哪个 - 肯定是出乎意料的和“高惊讶因素”。 Windows Installer 系统策略(如EnableUserControl)也可能与unpredictable results 一起发挥作用。这里有一股真正的 MSI 错误的味道。
        • 所以更新SecureCustomProperties 以包含DOREBOOT(或等效属性)。这是在属性表中完成的。
        • 总之:出于所有实际目的,此选项通常只是“理论上”的选项。俗话说:理论上没有理论和实践的区别,但在实践中有。不过……
        • Installshield 设置似乎有一个名为ISSCHEDULEREBOOT 的属性,用于调节ScheduleReboot 自定义操作。 可能可以使用此属性来禁止重新启动 - 在 Installshield 制作的设置中(仅限),因为它也会被自动标记为安全。
        • 如果您通过部署系统 (SCCM) 进行部署,则部署用户可能拥有所有这些必需的特权和权限,并且上述问题可能不会出现,但在部署更随意的小型公司中可能会有所不同。
        • 题外话太多了,让我们来看看应该可行的选项。
      2. 为问题 MSI 创建次要升级,将其作为次要升级或次要升级补丁包应用(文件更小,制作更复杂)。然后像以前一样使用上面看到的命令行调用包的卸载(也设置了REBOOT=ReallySuppress)。

        • 这将在调用卸载序列之前“修复”系统上缓存的 MSI 数据库。这意味着我们可以禁用相关的自定义操作(通常我们可以覆盖缓存 MSI 中的任何内容)。
        • 我已经多次使用这种方法,并且它是我唯一推荐用于某些范围(多于几台机器)的任何部署的方法。

      实施

      对于大规模部署,我会选择选项 2——尽管它非常麻烦。要开始,get hold of a tool capable of viewing an MSI file 并打开有问题的 MSI。在自定义操作表中查找可能与此类对话框相关的任何自定义操作。也许它说“ShowRebootDialog”或类似的。

      找到候选自定义操作后,在InstallExecuteSequence 表中找到它(我也会检查InstallUISequence - 以防万一您使用最少的GUI 而不是抑制的GUI 运行)。 自定义操作是否有关联条件?如果是这样,您可以通过命令行将此类条件设置为始终为 false,如上面选项 1 中所述 - 在这种情况下,自定义操作将永远不会跑。但正如解释的那样:只有当相关属性未在设置本身中设置时才可靠。

      次要升级需要新的包 GUID 和递增的版本号(通常是第三个版本号)。在您的 MSI 中设置并保存 - 使用与以前相同的文件名。如果您使用 Orca,您可以通过 View => Summary Information... => New GUID 获取 PackageCode 来执行此操作,然后在属性表中调整 ProductVersion 属性。

      1. 在您的清理包/脚本中,您现在必须首先安装次要升级 (some help material) - 此命令以交互方式运行以进行测试(添加 /QN 用于静默模式):

          msiexec.exe /i YourSetup.msi REINSTALLMODE=vomus REINSTALL=ALL
        
      2. 成功安装次要升级后,您可以以正常方式调用卸载序列。噗!如果次要升级运行正常,您最终应该成功地抑制了重新启动对话框 - 此命令以交互方式运行以进行测试(添加 /QN 用于静默模式)。

          msiexec.exe /x {11111111-1111-1111-1111-1111111111GH} REBOOT=ReallySuppress
        

      可能有一种我没有想到的更简单的方法。上面链接的 TRANSFORMS hack 应该可以工作 - 但它太丑了,我无法尝试。当您最不期望时,此类黑客往往会崩溃(例如在 Windows 更新之后 - 新的限制和功能弥补了漏洞)。你的风险。当您在实际受保护的位置和“实施细节”(引擎的内部)中直接写入注册表时,所有可能发生的事情都没有了(例如,不同的行为可能会在不同的操作系统版本上产生,并且更新可以锁定事物的名称,但有两件事 - 您还需要一个包来部署转换本身,破解注册表然后开始卸载 - 通常比使用内置 MSI 功能更复杂和易受攻击。通过 API 去,不要'不要直接走)。

      由于在静默模式下运行时 UAC 提示被隐藏(提升失败且没有警告 - 除了在日志文件中 - 如果已创建),因此在静默运行这些命令行时必须使用管理员权限。将/QN 添加到每个命令行。要添加日志记录,请添加 /L*V "C:\msilog.log"快速示例(记住管理员权限):

      msiexec.exe /x {11111111-1111-1111-1111-1111111111GH} /QN /L*V "C:\msilog.log" REBOOT=ReallySuppress
      

      或者,为所有 MSI 安装启用日志记录。请参阅installsite.org on logging(“机器上的所有设置全局”部分)了解如何执行此操作。我更喜欢为开发盒启用此默认日志记录,但它确实会影响安装性能并将大量日志文件添加到临时文件夹(您可以偶尔删除一次)。通常你会突然看到一个 MSI 错误并且你希望你有一个日志 - 现在你可以,随时准备好在%tmp%.

      【讨论】:

        猜你喜欢
        • 2014-06-04
        • 2016-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-10
        • 2021-09-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多