在使用WIX时,Windows Installer在Win 10上失败但在Win 7上不会

4

最近我被指派更新我们项目的安装程序,使其能在Windows 10上运行,但我不知道如何让它正常工作。我没有安装程序方面的经验,正在熟悉这个过程以及我们项目如何处理它。

目前,在我们的Windows 7虚拟机上运行安装程序完美无缺,但在Windows 10虚拟机上运行时,会在接近结束时失败并开始回滚。我已经让它输出了一些日志文件,正在查看其中的内容,但还是有点困惑。

我找到了这一段:

MSI (s) (B0:F4) [17:39:02:883]: Note: 1: 1708 
MSI (s) (B0:F4) [17:39:02:883]: Note: 1: 2205 2:  3: Error 
MSI (s) (B0:F4) [17:39:02:883]: Note: 1: 2228 2:  3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1708 
MSI (s) (B0:F4) [17:39:02:883]: Note: 1: 2205 2:  3: Error 
MSI (s) (B0:F4) [17:39:02:883]: Note: 1: 2228 2:  3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1709 
MSI (s) (B0:F4) [17:39:02:883]: Product: GPEP -- Installation failed.

在安装程序似乎失败时,接近最后阶段。
下一行的最后部分是这样的:
Installation success or error status: 1603.

我已经查看了错误信息,并找到了这个页面:Error 1603
我正在研究该页面上的解决方案,但所有这些都应该是正确的。我们在Win 10和Win 7虚拟机上以相同的权限和方式运行安装程序。
我怀疑这将不足以获得任何具体的响应,因此我更多地是寻求建设性的建议,如何查找和解决此问题。我有更多细节可以发布,但信息量太大,我不知道如何挑选出真正相关的内容。

2
我认为我们需要整个日志文件(详细)才能在这方面取得任何进展。也许你可以上传到某个地方?如果不行,请尝试Rob Mensching的技巧,搜索“value 3”。这应该会找到任何严重的错误。如果你发现了任何错误,请发布它们。你提供的日志中看到的错误看起来像是这个问题。只是缺少“Error”表(请参见链接答案底部)。 - Stein Åsmul
1
首先要检查的明显罪魁祸首是包中的任何自定义操作或您可能正在使用的任何高级 WiX 功能。对于这样的神秘错误,我经常使用“刷新日志”选项来确保日志文件持续写入。这可以确保崩溃的进程不会导致日志缓冲区丢失。像这样记录:msiexec.exe /I "App.msi" /L*V! "msilog.log"(感叹号是关键)。 - Stein Åsmul
嗨@SteinÅsmul,感谢您的回复。我认为我无法在不大量编辑日志文件的情况下发布完整的未编辑日志文件。但是,我能够使用那个“技巧”找到返回值3。我们在WIX文件中运行PowerShell设置脚本的某种自定义操作。当尝试运行此自定义操作/脚本时,会出现错误,它抱怨无法找到powershell的注册表键。我正在验证VM确实具有powershell(应该有,但我目前没有访问权限)。感谢您的帮助! - Caboose
1个回答

4

我将此作为答案添加 - 作为评论太长了,而且我认为这也是正确的答案。如果您阅读此答案,请还要查看我上面的评论,其中包含 Rob Mensching (WiX的创建者)提供的非常好的MSI日志文件调试提示 - 以及如何通过启用“刷新日志”来确保所有条目都进入日志文件以进行崩溃自定义操作。


答案

依赖于缺失的运行时,如Powershell,肯定会触发回滚。MSI为某些脚本自定义操作(活动脚本)提供其自己的运行时。例如VBScript和JavaScript。为了可靠的部署,建议使用的所有自定义操作都是自包含的最小依赖项C ++ dll或可执行文件(win32),或者(不太理想的)VBScript或JavaScript(甚至是Installshield如果您使用Installscript-请参阅下面的详细信息)。

我的争议性观点对于可靠性和稳健性而言,最糟糕的自定义操作是需要特定版本的.NET框架的.NET二进制文件。这也适用于PowerShell-它不仅是托管代码,还是脚本。我非常想说,这些技术不应该用于部署,但如果您需要使用PowerShell,则必须在安装程序开始时添加“验证已安装PowerShell”的自定义操作,并在没有PowerShell的情况下正常退出并显示适当的错误消息(和/或记录)。

这就是真正答案的结束 :-). 如果你正在制作通用分发包(而不仅仅是用于公司内部部署的包),以下是一些“冗长的思考”。如果我是你,即使只是内部部署,我也会阅读它,PowerShell自定义操作可能是一个重大的部署问题
托管代码和脚本都有问题。PowerShell实际上同时具备两者的功能。这里是Rob Mensching关于为什么脚本自定义操作不好的博客。基本上:脚本很脆弱,缺乏语言特性,难以调试,并且防病毒产品经常阻止它们。请阅读博客。这里是Aaron Stebner关于为什么托管代码不好的博客。基本上,当你依赖.NET框架的存在时,无法保证一个正确的运行时环境。

详细思考

我不确定Win7和Win10上安装了什么标准软件。如果您将其部署为公司的“内部软件包”,我认为只需添加可靠的检查以查找PowerShell的存在,然后在未找到PowerShell时中止并显示有意义的错误消息即可。个人观点警告但总体而言,.NET二进制文件和PowerShell脚本是可靠性最差的自定义操作。我永远不会使用它们来针对各种计算机进行设置。

如果您正在制作用于分发到任何计算机的通用MSI,我建议花时间将PowerShell脚本转换为其他形式。最好是C++ dll——我认为这是最可靠的。没有需要考虑的依赖项或层次结构。即使是InstallScript也可以接受,如果您将使用Installshield(它现在可以在没有预安装运行时的情况下运行——这显着提高了其可靠性和实用性——尽管它是一种晦涩的语言,具有相当古老的语法。公平地说,不应低估——它完成了工作,并且比C++更简单)。

JavaScriptVBScript自定义操作可以用于任何计算机的MSI,但仍不建议使用。我倾向于仅在“内部公司部署”软件包中使用它们。这些可以进行标准化,并且脚本对其他系统管理员和打包人员是透明的。他们可以查看和检查安装的一部分。这通常是可取的,也是企业部署MSI的关键利益之一,但有时您需要编译的二进制文件来隐藏实现细节(例如验证许可证密钥时)。然后无法使用任何类型的脚本-显然。通过透明并嵌入MSI中(因此始终可用完整运行源),它有助于不同的应用程序打包人员在需要时接管其他人的工作。在部署团队中,总会有人可以调试脚本-但很少有人了解正确的C ++。在内部应用程序的开发人员制作自己的MSI文件而没有太多部署知识的企业中,脚本可能会完全偏离轨道并导致非常困难的部署问题。很多时候,所需的是应用程序本身的小改变,以实现更可靠的部署。例如,应用程序应该执行自己的启动配置-不应在安装脚本中执行任何操作,但是许多开发人员都这样做。 使用脚本自定义操作是有争议的。如果你问两个开发专家,你会得到四种意见。在我看来,“白盒子”自定义操作(脚本)对于企业使用是好的,如果它们执行的是一些特定的不常见的任务,这样人们就可以看到正在发生什么。对于经常需要的东西,一个公司应该制作一个编译的C++ dll,由MSI文件中的自定义表格驱动,并具有完整的QA和回滚支持-对于所有脚本自定义操作通常都缺少的东西(实现起来并不简单)。一个“数据驱动”的(自定义表格)C++自定义操作具有最小的依赖关系,这是它最大的优势,也是透明的(将发生什么是透明的,但实际的实现是编译和隐藏的-这也可以提高安全性)。WiX工具包提供了这样一个用C++编写的带有回滚支持的自定义操作dll,它应该解决企业部署所需的大部分自定义任务。尽管如此,所有这些都远远超出了您的问题-只是一个离题的讨论:-)。
如果我猜的话,我会说Windows Installer可能会被更新以能够托管自己的Powershell运行时-但这只是猜测。我不确定技术细节-整个.NET运行时似乎都需要?如果问我,我仍然更喜欢JavaScript而不是PowerShell脚本,但我意识到您可能已经将PowerShell视为公司标准?此外,始终优先选择JavaScript而不是VB Script,因为它具有类似于异常处理的东西(VB Script完全缺少)。更新:实际测试表明,与Javascript相比,VBScript实际上更适合在MSI中使用。例如:使用Javascript访问MSI API时可能会出现模糊的问题。创建MSI时,VBScript可能比Javascript进行了更多的测试。让我们诚实地说:两种“语言”都有严重的局限性,并且都很难调试。 Rob Mensching, Chris Painter, Phil Wilson, Bob Arnson 和其他人(我不确定 Stefan Kruger 对脚本的看法,或者 Robert Dickau 的观点) - 他们可能会因此杀了我,但这里有一个 JavaScript 自定义操作的模板(未经过我的测试,但看起来还不错):如何调试实现在 Javascript 中的 MSI 自定义操作?如果我能说出来:任何东西都比 PowerShell 好 - 即使是 JavaScript。

请放心,我已经浪费了很多时间来调试极其糟糕的 VB Script 自定义操作。这可能是用于部署的最无能和被剥夺的语言。错误处理使用 On Error Resume Next?它不能更糟了。我通常仅将脚本用于只读操作和设置属性操作。

也许在不久的将来,我们会看到VB脚本被弃用,PowerShell成为可行的MSI脚本选项?在所有正在使用的操作系统都至少安装了基线版本的.NET框架之前,我不认为这是安全的 - 即使如此,我相信策略也可以锁定特定版本的.NET以防止使用。你想要一个包突然无法卸载,因为目标版本的.NET框架已经不再运行吗?修复这样的问题可能需要大量的工作 - 特别是对于拥有大量软件包(数千个包,数千台机器)的企业而言。

推荐的自定义操作实现方式

我写了一个“建议”自定义操作实现的摘要,但内容冗长且不够明确,最终删除。相反,以下是我个人偏好的自定义操作实现清单(按可靠性和稳健性递减排列):

更新 2018年5月:不再推荐使用JavaScript而非VBScript。

  1. C++ dll
  2. Installscript(仅限InstallShield)
  3. VB Script
  4. JavaScript
  5. C# DTF
  6. PowerShell

摘要:

  • 在我看来,PowerShell 绝对是最糟糕的选择。它既是托管代码(运行时不可靠),又是脚本自定义操作(调试困难)。
  • 我想像 Chris 那样写 C# / DTF 自定义操作,但我认为时机还未成熟 - 运行时环境无法保证。在现实世界中,你不会为了一个 C# dll 抛弃一个正常工作的 C++ dll。这会大大降低可靠性。
  • C++ dllInstallscript 是制作专业的、面向多样化计算机的厂商设置的唯一选择(不是标准化的托管环境 - 企业,而是全球任何地方的计算机,以及它们各种语言和不同硬件软件配置的异构状态)。
  • 相比其他自定义操作,C++ 自定义操作 dll 的设置和配置要复杂得多,因为它涉及到导出、构建设置和输出等方面,但这并不是什么神奇的不可能完成的任务。你将得到很多回报:完整的调试功能高级语言特性错误处理。而且最重要的是:最小的依赖关系(确保启用静态链接以消除所有可能的依赖项)。为了调试,你只需将 Visual Studio 调试器附加到自定义操作显示的消息框上,然后就可以逐步执行代码。这适用于用户和系统上下文的自定义操作。完全控制。这实际上使得调试 C++ 自定义操作比脚本自定义操作更容易,当然也更可靠。
  • JavaScript 我通常会避免使用。它不是一个完整的语言。但我仍认为它比托管代码更可靠 - 在运行时依赖和可靠性方面(运行时依赖问题较少)。
  • VB Script 在受控环境下的 "内部企业使用" 是可以接受的。但我永远不会在供应商设置中使用它进行普遍分发。但是,在企业网络上分发软件包时,可以使用它。既适用于开发人员打包自己的应用程序,也适用于应用程序打包人员调整第三方设置以进行企业部署。VBScript 操作的主要优点和缺点:
    • 如上所述,脚本仅在必要时使用,对于人们倾向于重复使用的所有常见脚本任务,都应该使用 win32 C++ dll 或 WiX 的自定义操作 dll。只有在必要时才使用脚本来完成工作。
    • VBScript 自定义操作与所有脚本自定义操作一样,在一般情况下都很难调试,容易受到反病毒干扰,并且缺乏实现高级编码结构所需的语言特性。你没有可用的 C++ 语言特性和灵活性(现在甚至 C++ 自定义操作也可能会被安全软件阻止 - 但这不是很常见,但随着安全性的加强,情况可能会发生变化?)
    • 脚本对每个人(无论目的还是实现)都是透明的
      我确信的一件事是,托管代码自定义操作的可用性将导致人们在设置中做太多本不应该在设置中完成的事情(丰富的 API,相对容易的编码)。这是因为编码更容易、更快速,而相关开发人员可能缺乏如何进行适当部署的理解。这不可避免地导致各种自定义操作的过度使用,并进而触发自定义操作的复杂性引发意外错误,从而造成主要的部署问题。

再次您好,感谢详细的回复。不幸的是,我只能使用PowerShell,并且通常现有的内容将保持不变。我想我已经找到了为什么会发生这种情况的原因,似乎可能是一个愚蠢的问题。我们的虚拟机显然有PS,但没有2.0版本。我们进行注册表检查并找到PS,但然后我们在SetProperty标记中有:Value =""[POWERSHELLEXE]" -Version 2.0 ...我想知道是否可以删除该版本标志,或者根据存在的哪个版本来进行条件设置? - Caboose
1
是的,我想这就是类似的问题。未来,PowerShell 可能会成为 MSI 文件更“可接受”的脚本类型,但是如果可以,请始终首选最少依赖(win32),特别是如果您要制作用于大规模分发到各种机器的软件包。这里是关于部署复杂性的简短介绍(在底部)。基本上:部署错误是累积的调试很困难目标机器处于各种不可预测的状态。您正在处理间歇性错误 - Stein Åsmul
1
我使用C#/DTF和CustomAction.config文件,可以在.NET 2.0-4.7上运行。偶尔,如果真的需要,我会使用它来托管PowerShell管道。在2017年,绝对没有ActiveScript(VB/JS)自定义操作的位置。 - Christopher Painter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接