Wix Tools更新使用旧的自定义操作

时间:2017-12-22 12:09:31

标签: wix windows-installer

我们发现了一些使用WIX设置工具的奇怪行为。 我们已经部署了一些主要版本(2.2.0 - 到2.2.4)。对于2.2.5,我们在自定义操作中更改了一些小东西(在我们使用XCOPY之前,现在我们使用RoboCopy,因为它有一个“MOVE”命令而不仅仅是一个副本)。

但是当我们现在从2.2.4更新到2.2.5时,设置仍然使用旧的Copy命令而不是新的MOVE命令,但这不可能是因为2.2.5没有任何Copy命令。 如果我部署2.2.6(与2.2.5相同)并从2.2.5更新它使用新的更新过程... 看起来更新使用旧的MSI。

Found this on SO

有没有办法阻止这种行为?这会完全中断更新过程,因为在更新时未正确复制现有配置文件。

我们无法强制客户清理注册表或通过GUID删除任何MSI文件格式缓存...

任何帮助表示赞赏。 提前致谢

更新: Product.wxs中的新自定义操作

<Property Id="C_TEMP" Value="C:\Temp" />
      <Property Id="ROBOCOPY_EXE">robocopy.exe</Property>
      <CustomAction Id="CopyToTemp" Property="ROBOCOPY_EXE" Return="ignore" ExeCommand='"[INSTALLDIR]\Configuration" "[C_TEMP]\ServerSettings" ServerSettings.json' />
      <CustomAction Id="CopyFromTemp" Property="ROBOCOPY_EXE" Return="ignore" ExeCommand='"[C_TEMP]\ServerSettings" "[INSTALLDIR]\Configuration" ServerSettings.json /MOVE /IS' />

旧自定义操作

<Property Id="C_TEMP" Value="C:\Temp" />
  <Property Id="XCOPY_EXE">xcopy.exe</Property>
  <CustomAction Id="CopyToTemp" Property="XCOPY_EXE" Return="ignore" ExeCommand='"[INSTALLDIR]\Configuration\ServerSettings.json" "[C_TEMP]\ServerSettings.json.bak*" /YIR' />
  <CustomAction Id="CopyFromTemp" Property="XCOPY_EXE" Return="ignore" ExeCommand='"[C_TEMP]\ServerSettings.json.bak" "[INSTALLDIR]\Configuration\ServerSettings.json*" /YIR' />

之后代码到目前为止没有改变

<InstallExecuteSequence>
  <Custom Action="CopyToTemp" Before="InstallInitialize">Installed AND (NOT REMOVE="ALL" OR UPGRADINGPRODUCTCODE)</Custom>
  <Custom Action="CopyFromTemp" Before="SetVersionsInRegistry">NOT Installed OR Installed AND (NOT REMOVE="ALL" OR UPGRADINGPRODUCTCODE)</Custom>

.....
</InstallExecuteSequence>

2 个答案:

答案 0 :(得分:1)

测试条件

条件#1:

Installed AND (NOT REMOVE="ALL" OR UPGRADINGPRODUCTCODE)

这个相当奇怪的条件星座将导致有问题的自定义操作在全新安装期间不运行,也不会进行手动卸载。看来这个自定义操作将在以下期间运行:主要升级(这是一种特殊类型的卸载),修改和修复。我想这可以完成备份设置文件的工作。但是......

在重大升级期间,这确实看起来像旧的自定义操作正在运行,因为正在运行的是主要升级模式中的旧包(这是一种特殊类型的卸载) - 因此具有旧包和#39;自定义操作正在运行的是您之前安装的旧缓存数据库 - 它将自身卸载为主要升级的一部分)。这些自定义操作在程序包的初始安装期间从未运行过。但是你要从temp复制的其他自定义动作。这可能不是正确的行为。

总结:

  • 运行:主要升级(通过卸载的旧MSI运行,但不在新的MSI中运行),修改,修复
  • 不运行:首次安装,卸载。

条件#2:

NOT Installed OR Installed AND (NOT REMOVE="ALL" OR UPGRADINGPRODUCTCODE)

第二个条件,也有点异国情调,似乎只在新安装和主要升级上运行。您可能只需要在主要升级期间运行它,但是您是否也应该在修复和修改期间运行? (在某些情况下,这些模式也可以覆盖设置文件,例如 REINSTALLMODE 设置为&#34; amus &#34;强制覆盖文件时)。< / p>

总结:

  • 运行:首次安装,重大升级
  • 不运行:卸载,修改,修复

标准条件

我并不完全掌握您的整个方案,但您可以找到一些资源链接,以便在此处找到常见条件Is it possible to run a custom action only in repair mode。我假设您要在主要升级,修复和修改时备份设置文件以避免被覆盖。看起来应该稍微修改条件来实现这个目标吗?

我建议完全避免自定义操作,以下是建议的方法来实现此目的。

使用应用程序管理设置文件

设置文件的管理和设置一直是部署的难题。我写了几天前处理用户设置文件的不同方法的简短摘要: Create folder and file on Current user profile, from Admin Profile (这是部署设置文件的不同方法的一点参考 - 推荐,请如果不清楚,请告诉我。)

从上面的链接答案中可以看出,使用您的应用程序将设置安装的模板副本中的设置文件初始化为INSTALLDIR中的只读位置通常是个好主意。然后,您可以保持模板不变,但是在启动时,您的应用程序会将模板设置文件复制到每个用户的用户配置文件中,或者只是在INSTALLDIR中创建一个安装过程永远不会触及的副本(您需要应用ACL)允许所有用户都可以写入此设置文件 - 不是很棒的设计,但它确实有效。 此基于模板的方法将设置文件与部署注意事项分离。从现在开始,它永远不会被重置,卸载或插入,因为它从未被安装程序安装。实际上你必须专门实现它的清理或卸载(例如通过RemoveFolder / RemoveFile构造),否则它将在卸载时保留在磁盘上 - 这也可能是一个问题。

避免使用Windows Installer的复杂架构来处理自定义操作总是有利的。对于您调用的各种二进制文件,有复杂模拟复杂条件复杂排序以及运行时依赖项。您使用的是DTF还是直接使用C#程序集进行呼叫?使用托管自定义操作存在一些问题(加载了错误的CLR版本,根本没有安装.NET(已锁定?),GAC中的文件依赖性等等...我没有完整的概述 - 出于这些原因,我远离所有用于MSI部署的托管代码。)

将模板设置文件复制到安装程序无法触及的新文件时,您无需处理MSI的奇想和怪癖 - 或任何托管自定义操作及其运行时要求。

更新:我删除了之前添加的传递方法,经过进一步测试后发现它只适用于某些情况。我将使用次要升级而不是主要升级再次检查它。然后,您可以使用次要升级修补程序迁移所有旧版本以将设置文件设置为永久性,以便永远不会再次卸载,然后您将应用主要升级。这应该可以包装在 Burn bootstrapper 中。

更新:假定(并验证)次要升级可以将任何组件切换为永久性,并且不需要对组件使用任何传递设置(我没有检查是否有小更新可以如果组件在之前设置为永久性,则将组件切换为非永久性组件。事实上,如果在安装期间附加到组件的任何条件评估为false,则启用传递实际上可以卸载组件 - 我没有验证这一点,但从逻辑上讲它是可能的。首先想到的是这是否可以将组件集卸载为永久组件。它不应该,但我在MSI之前看到过这样的怪异。我可以想象一下,对于一个永久部署到System32的组件集来说这是必要的。总之:如果您只需要保留设置文件,只需使用次要升级将其设置为永久性,然后您可以再次使用主要升级。不要将组件设置为可传递的。

提一下:顺便提一下,您的设置文件实际上并没有被您当前的升级方案覆盖。它在主要升级期间被卸载并重新安装,因为其组件最初未设置为Permanent = "yes"NeverOverwrite="yes"。这似乎已将其恢复为默认值,但它从未被覆盖。而是卸载并重新安装,消除了更改。 MSI不会覆盖已更改的非版本化文件,但除非标记为永久文件,否则它将很乐意卸载并重新安装。在我看来,这是一种技术反模式 - 很多团队一直都在面对这个问题。因此,我建议审查一些数据文件部署选项,如下所述:Create folder and file on Current user profile, from Admin Profile(与上面相同的链接)。

我希望其中一些有用,请告诉我们您在测试过程中发现的内容。

OLD ANSWER

Brian提到了真正的建议,但也许有些问题需要澄清。一旦得到答案,我会将其演变为尝试的答案。

  • 这些自定义操作如何运行?它们是EXE命令还是运行启动器EXE然后调用它们?如果您使用这样的启动器EXE,它是原生(C ++)还是.NET? (C#/ VB.NET)。如果它是.NET通常是坏消息。
  • 我们可以问这些复制命令你在做什么吗?这可以在应用程序本身更可靠地完成吗?这可能是我们给予人们最常见的建议,如果遵循这些建议实际上可以大大简化部署并使其更可靠。您可以更好地控制应用程序中发生的事情,在可预测的安全上下文中运行,并且没有任何条件或顺序可以处理。最后:您可以重新启动应用程序并再次执行,设置是&#34;一次拍摄&#34;。
  • 我现在就把它留在那里......

答案 1 :(得分:0)

你应该更明确地说明你的意思&#34;更新&#34;因为它可能是补丁,次要升级,重大升级。如果它是一次重大升级,您应该说出它的排序位置。但是,可能会运行先前版本的自定义操作有两个一般原因:

  1. Brian的评论/回答 - 他们在原始安装中被错误地调整,当更新通过旧安装中的序列时,它发现条件评估为true。如果您愿意,则不需要安装自定义操作或卸载自定义操作:只有具有条件的自定义操作。在作为更新发布的WiX源中,使用UPGRADINGPRODUCTCODE不正确。在主要升级期间卸载时,此属性在旧产品中设置,因此旧安装中的任何条件都表示&#34;或UPGRADINGPRODUCTCODE&#34;将是真的。如果您想要在升级旧产品时在升级安装中设置的条件,请使用MainUpgrade元素使用的WIX_UPGRADE_DETECTED。

  2. 执行更新的行为导致旧产品的修复,因此它已运行自定义操作,甚至可能具有正确的条件。例如,如果二进制文件已被替换并且在更新期间是替换的候选者,则Windows Installer将修复并恢复不匹配的二进制文件,以便它可以决定是否安装更新中的二进制文件。这将重新安装包含该二进制文件的功能。因此可以运行以功能或组件安装为条件的自定义操作。

  3. 此外,为了扩展Stein的答案,Windows Installer和WiX有一个举动(参见CopyFile元素)。为什么要将文件安装到一个位置并立即将其移动到另一个位置?我认为没有简单地安装它和没有移动的最终位置的原因是什么?