Ste*_*mul
8
简短的"Folksy"版本:
总体而言:现代设置应该"声明",而不是编码."想想SQL查询,而不是脚本".应用经过良好测试的逻辑,您只需调用它来完成工作.稍后会详细介绍.
- 如果可以,请避免自定义操作.
- 他们会拧你的头(并为你的少女形象谋杀)!
- 说真的:它们是部署失败的头号原因.
- 它们具有" 吸气复杂性 ",在您将设置部署一段时间之后,事情经常会意外地突破并且没有任何警告,并且它"在野外".
- 部署是一个过程 - 您将不得不为每个新版本处理" 过去的罪行 ".在部署完成后清理事务可能会成为一场真正的噩梦.每次迭代都会添加新的潜在错误源(我修复失败的修复程序,失败等等).
- 运行时要求对托管代码和脚本的自定义操作都非常容易出错(尤其是在我看来,.NET).设置 - 如果有的话 - 应该具有" 最小依赖性 " - 因为它用于完全安装依赖项,并且应该在" 任何语言 "的" 任何状态 "中的" 任何机器 " 上运行.
- 除了使用内置的MSI构造或WiX自定义功能外,通常可以通过对应用程序设计进行微小更改来避免自定义操作,从而不再需要复杂的自定义操作(下面的示例).
- 花时间从WiX,Installshield,Advanced Installer(和其他供应商工具)查找和查看内置的MSI功能和扩展.
- 这些扩展由最好的部署专家提供,并且在大多数情况下已经被数千人测试(在内置MSI功能的情况下数百万和数十亿).
- 你怎么能想到这与你自己的专有代码相匹配?如果现有的解决方案足够好 - 通常是这样 - 那么你自己的代码完全增加了风险,无论如何都没有.现成的解决方案甚至支持回滚 - 这是一个众所周知的被忽视和难以实现的功能 - 实际上是设计所需要的.
- 换句话说:当您使用现有的解决方案时,您不仅要借用实现,还要借用QA,UAT以及使用它们时扩展的测试.这可以节省数周的工作量并大大有助于部署稳定性.
- 所需要的只是花一些时间搜索和阅读已有的内容,而不是使用自己的代码来启动内容.哎呀,即使你自己的经理也可以参与搜索...在一个梦想的世界里.
- 设置通常不应该编码,应该声明!(想想SQL).这就是Windows Installer的全部内容:您声明要安装的内容,顺序由安装程序引擎本身负责.好处结果 - 做得好.
- 这是真的.如果你敢,请继续阅读!这里是龙在严重咆哮中.至关重要的是:处理设置开发以及在企业环境中大规模部署此类设置的实际经验.常见问题变得更加清晰 - 它们更容易识别.而且你可能会因为你真正需要回答的问题而被烧毁 - 你觉得你无法预见到(做公司包装和重新包装你会看到单个包装有多少可能是错的 - 它可能需要数天才能打败它们有时变成形状).
- 请记住,这并不意味着它听起来很糟糕:部署通常是一种低地位的技术努力,但是高调的失败.错误真的显示出来.有人会回答它,支持会真的感受到它.
- 在开发期间进行调试很困难,但是对于部署,有时几乎不可能,因为您通常无法访问问题系统,并且每个问题系统将处于完全不同的状态.
- 老实说:未能将软件正确部署到最终用户可能接近成为软件开发中最昂贵的错误 - 没有人能够看到您的解决方案的伟大之处 - 它会影响销售,支持,营销和进一步的解决方案开发.
- 部署不当肯定会导致产品下沉.不幸的是,良好的部署还不足以保存产品.
充实的Ranting版本:-)
如上所述,本节与现有答案分开,范围更广:如何避免WiX/MSI部署解决方案中的常见设计缺陷?(旨在帮助开发人员做出更好的部署决策的答案).
6. 错误或不必要地使用自定义操作.
使用自定义操作可能会导致大量的部署问题 - 其中大多数都非常严重.如果您的设置无法完成或崩溃,那么错误的自定义操作是错误的是公平的赌注.
因此,显而易见的解决方案是尽可能限制您对自定义操作的使用.自定义操作(通常)是" 黑盒子 "(隐藏代码),而大多数MSI具有很多透明度.可以轻松查看MSI格式(COM结构存储文件),MSI文件所做的一切基本上都可以从其MSI数据库文件中推断出来 - 除了编译的自定义操作(脚本自定义操作仍然是白盒子 - 你可以看看发生了什么,除非他们被混淆了).
在这个恶意软件时代,这些黑匣子自定义行为 - 以较高的权利运行 - 可能会以多种方式不受欢迎.它们不仅仅是稳定性和可靠性问题,而是一个全面的安全问题.
6.1过度使用自定义操作
- 请原谅下面列出的"琐事".其中很多可能是平庸的,但也许可以使用列出的参数为自己制定一个案例,以避免自定义操作并开发更好的解决方案 - 通常涉及更智能的应用程序启动顺序和应用程序自我配置.相信我们,应用程序编码将比处理Windows的安装程序的复杂调节,排序和模拟自定义操作更有趣.
- 以下内容已经更新了很多次,这里和那里的部分有点不按顺序或重复.将在时间允许的情况下进行清理.
- 开发人员擅长编码 - 所以应有的尊重 - 你倾向于过度使用自定义操作来做更好的事情,使用内置的MSI功能或现成的MSI扩展解决方案,例如WiX中提供的高级内容,例如XML文件更新,IIS,COM +,防火墙规则,驱动程序安装,磁盘和注册表项的自定义权限,修改NT权限等...此类支持也可以在Installshield和Advanced Installer等商业工具中找到.
- 作为应用程序启动序列的一部分,还可以在自定义操作中执行大量操作.主要示例是初始化用户数据并将设置文件复制到每个用户配置文件.此处有一个小问题摘要:在管理员配置文件中创建当前用户配置文件中的文件夹和文件.
- 显而易见,但通常使用自定义操作是出于对现成解决方案已经"开箱即用"的无知的使用.这种情况一直发生在我们所有人身上,不是吗?总有一些更聪明的方法来做可以为你带来许多悲伤的事情?总的来说 - 尽管有时你会开辟新天地.不要在你的设置中取得新的突破 - 除非你绝对必须!将其保存为您的应用程序.
- 我想强调的是,这些内置的Windows Installer解决方案以及WiX和商业工具的扩展都是由最好的部署专家编写的.此外,甚至更重要的是,它们已被数千,数百万人使用和测试 - 甚至数十亿人用于内置MSI功能.你真的认为你可以做得更好吗?故事的道德:选择你的战斗并使用你的优秀编码技巧来解决新问题,让部署尽可能愚蠢.使用已经有效的东西,不要重新发明轮子.部署中有太多未知数,太多无法控制的变量 - 您正处理" 任何状态 "中的" 任何机器 "任何语言 ".如果您想要示例 - 请参阅此处的部署复杂性部分 - 在页面下方 - 只是您的目标系统在您的程序包命中时状态可能不同的所有方式的简短转储.每个变量都是新的熊自定义代码的陷阱 - 从操作系统版本到应用程序空间到恶意软件情况.列表不断进行.结论在链接内容中读取:" 部署是一个简单的概念,具有复杂的变量混合,可以导致最多神秘的错误 - 包括开发人员最喜欢的:间歇性错误.众所周知,这些错误的严重性不容小觑,因为它们通常无法正常调试."
- 必须在您的设置中完成某些高级操作 - 因为它们需要提升权限,并且您的应用程序不应在运行时请求此操作.这就是设置,高级,高架系统配置 - 所以要考虑到这种复杂性,但要使用现成的解决方案!不要滚动自己的脚本和解决方案,使用内置的,经过良好测试的东西.你的脚本会在韩国正常运行吗?您的自定义操作是否会被您从未有时间测试脚本的主要反恶意软件解决方案阻止?您是否有时间编写自己的检查,以确定计算机上是否安装了某个先决条件运行时 - 它适用于所有语言环境和所有操作系统版本?这里的漏洞潜力是惊人的 - 而且有时不可能正确测试.你有阿拉伯语,中文,韩语或日语的试验机吗?也许你这样做.但是你有一个终端服务器可以测试吗?韩国终端服务器怎么样?您是否使用MSI广告测试了您的设置?要使高级系统管理功能正常工作,您必须尽可能使设置变得愚蠢和标准.花几天时间寻找现成的解决方案然后你自己写任何东西我会说.请记住,使用现成的解决方案,您不仅可以借用他们的代码,而且至关重要的是他们的创建者的QA,测试和UAT - 您几乎不可能希望重复这些.
- Real-world testing is the only yardstick that matters - there is no substitute. Don't take on this world of pain! A slight change in Windows deployed via a Windows Update and your custom action breaks in any number of ways. Choose a better battle to make use of your skills. If you fight the design, then Windows installer fights back.
- And there is a lot going on with deployment that makes it complex - and not dumb like we want it (just copy some darn files), your fight is to make it as simple as possible, but no simpler. Here is a list of deployment tasks showing why it is hard to get your package "dumb enough": What is the benefit and real purpose of program installation? Use only ready-made constructs whenever you can - it is the first easy win. All you need to do is to read and search a little.
Finally I will add that all custom actions are supposed to support rollback to put the system back to the original state if the install fails. In the real-world this is almost never done in an ad-hoc custom action (in my experience). Believe me it is complicated to deal with - I fear the word "rollback" as a Siberian husky fears the word "bath" after I implemented MSI rollback in C++. Not the most fun I ever had, but it eventually worked properly. If you want your setup to be without too many dependencies, C++ is the way to go, and as we all know it is not trivial to deal with. The ready-made solutions support rollback out of the box - it is an easy-win for only a bit of reading and searching to enable them. Complexity yes, but you are on more solid ground. And crucially: once an obscure error happens on a Japanese machine we can work for a community fix, or a third party vendor needs to sort it.
After all those "general observations", on a purely technical level, custom actions in Windows Installer are very complex with regards to implementation, scheduling, conditioning and rollback, and should hence be used when absolutely necessary (often for early-adopter stuff). A further complexity is runtime requirements - for example dependencies on specific versions of the .NET runtime, or PowerShell, or Installscript runtimes (scripting language of Installshield - it had a runtime dependency, but this is largely solved now, it used to be a problem).
- Errors from missing runtime requirements can be a enormous hairball to deal with - for zero gain. For this reason I only use minimal dependency C++ dll's or Installscript when making custom actions. It happens that I use VBScript or JavaScript for read-only custom actions in the user interface sequence. These just retrieve data, and make no system changes. These are the only types of custom actions that are not that error prone. They should however be set to run without checking exit codes (to prevent them from triggering rollback or abort in a setup that is being run - often in major upgrade mode).
- Also: Windows Installer hosts its own scripting runtime engine, so you know your active scripts (VBScript, Javascript, etc...) can run unless your target system is actually broken (there is no missing runtime on a normal system). This is in contrast to managed code custom actions - it is entirely possible for target systems to have no .NET runtime at this point (Jan 2018). Now this will change in the future, as .NET becomes a really built-in and required feature in Windows (or some minimal version of it hosted by Windows Installer itself). There are still problems with managed custom action code failing for strange reasons - such as the wrong .NET version being used to run it, or the wrong version of the CLR being loaded and being used, etc... I have limited experience here, but the problems are serious in my opinion. Eventually, though, we will all write managed code custom actions I think. I would still use C++ for worldwide distribution scenarios though.
- Powershell scripts are particularly hairy for custom actions as they apparently run out of process and can't access the MSI's session object (source: MSI expert Chris Painter). Powershell also requires the .NET framework to be installed. I would never use Powershell script for custom actions - not even for internal, corporate deployment. Your call. Just as a "sample", here is an expert in the field stating his opinion (aging blog item, but still relevant if you ask me): Don’t use managed code to write your custom actions!
- I tried to write a summary of pros and cons of different custom action types. Frankly I am not too happy with it, but here it is: Windows Installer fails on Win 10 but not Win 7 using WIX. What I am not happy with? The recommendation of JavaScript for one thing - I have used it seldomly, and although it is a better language than VBScript - particularly for error handling - I have had lots of problems using Javascript with MSI. It may be a case of the problem existing between the keyboard and the chair :-), but I think there are some real gotchas with JavaScript as well. Try to avoid complex use of scripts. For simple things like retrieving properties they seem to work OK for me. However, the experts in the field are merciless on script custom actions: Don’t use vbscript/jscript to write your custom actions! (Aaron Stebner), VBScript (and Jscript) MSI CustomActions suck (Rob Mensching - WiX benevolency).
- Let me also add that custom action complexity is "silly, conspiratory complexity" not fun-to-deal-with stuff. It bites you. Gotchas. You will discover all the mistakes you have made in due course - as you move along (and then you have some explaining to do) - they will often not be immediately obvious (problems suddenly arise when upgrading, patching, uninstalling, your custom action runs erroneously during repair because it is not conditioned properly and wipes out certain registry settings, silent install doesn't work properly - it leaves the install incomplete because the custom action only exists in the user interface sequence, there are runtime errors on Windows XP that you never tested your custom action code with, there are broken things on target systems that you didn't shield yourself from, someone calls you and tells you your package doesn't work with active directory, your package can't be advertised, it fails on all Korean and Japanese systems, self-repair triggers runtime warnings and access denied for normal users, etc...). You will have no time to fix this properly once it hits you, and you will likely have to proceed with sub-standard solutions to get yourself ahead over the next hurdle. And no, I didn't experience all of this myself. In fact I discovered most of these problems when fixing up third party vendor MSI files for corporate deployment. You really discover a lot of potential error sources when you see, compare, review and adapt hundreds of packages to a corporate standard for large scale deployment. In all honesty there are serious shortcomings and errors in all but the simplest of packages. And obviously you get to see what you did wrongly when you made such vendor setups a few years earlier. And guess what tops the list? Overuse of custom actions when built-in constructs were available.
- And to add to it all, the inherent complexity of deployment with its requirement to work on any machine, anywhere in any state, there is the issue of MSI technology borderline anti-patterns. Parts of the MSI technology that are causing repeated deployment problems because they are poorly understood, and sometimes fragile in real-world use. There is a brief summary of this in this answer (towards the bottom): How to make better use of MSI files (along with a list of the very important corporate benefits of MSI - and a random dump of common technical problems seen in real-world packages). Particularly the latter link has struck me as less than ideal after I wrote it. Take it for what it is: messy, real-world advice without much else going for it. It identifies too many problems without showing much in the line of fixes in places.
A substantial proportion of a software's support calls tend to come from problems seen during the deployment process. As the story goes: "...failing to properly install your great software may be close to being the most expensive error to make in software development. You can never hope to sell a software that was never possible to test" (from one of the linked answers above). A bad custom action is very often behind such problems.
The most common unnecessary custom action uses we see are in my opinion:
You install Windows Services via custom actions. This is much better done in the MSI itself using built-in constructs.
You install .NET assemblies to the GAC via a custom action. This is fully supported by Windows Installer itself without a line of (risky) code.
You run custom .NET assembly installer classes. These are to be used for development and testing only. They should never be run as part of deployment. Rather your MSI should use built-in constructs to deploy and register your assembly.
You run prerequisite setups and runtime installers via a custom action in your own MSI. This should be done entirely differently. What you need is a bootstrapper that can launch your setup and its prerequisites in a sequence. Commercial deployment tools such as Advanced Installer and Installshield have features for this, but free frameworks such as WiX has support via its Burn feature, and there are also free GUI applications such as DOTNetInstaller (untested by me) with these kind of features.
Please take my word for it in this particular case: running embedded setups via a custom action will fail eventually - usually rather immediately. MSI is too complicated in its scheduling, impersonation, transaction, rollback and overall runtime architecture to make this possible. Only one MSI transaction can run at a time by design, and this makes things very complicated. It used to be you could run embedded MSI files as a concept in MSI, but this was deprecated - it didn't work properly. You must run each setup in sequence. The correct sequence. There are bootstrappers/chainers available that will allow you to define such an installation sequence. Here is an answer which describes some of them (don't let the question title throw you off - it is about bootstrappers/chainers and other deployment considerations): Wix - How to run/install application without UI.
6.2 Custom Action Alternatives
The ready-made solutions found in WiX and other tools such as Installshield and Advanced Installer, are tried and tested, and crucially also implement proper rollback support - a feature almost always missing from custom action implementations - even in otherwise good vendor MSI setups. Rollback is a very important MSI feature. You cannot compete with the quality delivered from a large user community with active use and testing in all kinds of environments. Make use of these features.
Apart from using built-in MSI constructs or WiX custom features, custom actions can often be avoided by minor changes to the application design so that complex custom actions are no longer needed. I see licensing as an example of how deployment can be simplified to improve reliability.