wixwindows-installerinstallationinstallshieldadvanced-installer

How do I avoid common design flaws in my WiX / MSI deployment solution?


How do I avoid common design flaws in my WiX / MSI deployment solution?


Deployment is a crucial part of most development - failed deployment means your end user will never get to evaluate your product. This could easily be the most expensive error to make in software development. Please give this content a chance. It is my firm belief that software quality can be dramatically improved by small changes in application design to make deployment more logical and more reliable - that is what this "answer" is all about - software development.


This is a Q/A-style question with an answer that just list a few things not to do in your MSI file to avoid the most common design flaws.


Solution

  • WiX / MSI Deployment Anti-Patterns

    There are several deployment anti-patterns often seen in WiX / MSI files. Below is a rough-draft of some of the most common ones.

    Before going into the problems, on the other hand here is a quick reminder of the things that have made MSI an overall success! (despite its problems).

    This answer is a work in progress

    What do you know I hit the max size for the answer. I guess that's a hint it's enough already :-). Some sections need clarification and improvement though.

    If you recognize some of these problems, you might want to read on - these are all well known developer hates and annoyances with Windows Installer / MSI:

    The sections below are in no particular order at all - as of now.

    The sections are continually sought to be improved. Please add comments on what isn't clear or helpful.

    Pending addition:

    • Difficult multi-instance installations
      • Relatively common requirement, especially for service installations
    • Uninstall is not working for MSI application - Error 1722
      • Service control: Failing to stop services before uninstalling
      • Uninstall CAs: Trying to run batch files / scripts that are no longer on disk during uninstall
      • Custom Actions: Erroneous conditioning so custom action runs unexpectedly. Often on uninstall or during major upgrades.

    1. Self-repair problems

    A particularly annoying problem is related to constructs that frequently trigger unwanted self-repair for your installed application.

    2. Incorrect installation of shared, vendor or Microsoft runtime files

    Although this is extensively explained in the link above (self-repair issues), it should be noted here as well that one of the most common errors in any setup is the inclusion of "local copies" of shared runtime files - sometimes also globally registered on the system if they are COM files. The installers for old VB6 applications sometimes did this for common controls they required, breaking the system for other applications.

    3. Incorrect handling of (your own) shared files and data

    If you create a suite of MSI files to deploy different products, they might share certain files between them. If you target the same file location (absolute path) from several MSI files - each using a different component GUID, then each setup will treat the file as if it "owns it" - happily uninstalling it on uninstall, or putting it in place again via self-repair.

    4. Component creation errors - not following best practice

    Not following best practice for component creation. MSI components are the basic installation units for files and registry settings.

    5. Upgrade problems relating to user data being overwritten or reset

    This is no less than extremely common. I have answered several stackoverflow questions on this topic, and it keeps coming up.

    6. Erroneous or unnecessary use of custom actions

    The (over)-use of custom actions for MSI files is a huge topic and this section got too large and was split into a separate answer: Why is it a good idea to limit the use of custom actions in my WiX / MSI setups?.

    Essentially custom actions are often unnecessary due to built-in support in MSI to achieve the same effect, or the availability of ready-made solutions in free frameworks such as WiX or commercial tools such as Advanced Installer or Installshield.

    And custom actions are by their very nature error prone and the leading cause of deployment failures and errors. Please read the above link for details. Thousands of people, tens of thousands of people, even millions of people have tested these built-in constructs. Why on earth do you do it on your own?

    Some "besserwissing" (advice that I should follow myself): Focus on what sets your product apart - what is new about it, and eliminate all other sources of errors. Good deployment won't make your product, but bad deployment can break it.

    7. Failure to properly merge INI files

    It is possible to install an INI file via the File table - as you would any other file. This allows no merging if there is an existing INI file at the target location.

    8. Erroneously using self-registration for COM files

    Or install their registration via the Registry table. Use the appropriate COM advertisement tables. There are many reasons, as explained here: Self-registration considered harmful.

    9. Overuse of per-user file and registry deployment

    UPGRADE: new answer relating to this topic: Create folder and file on Current user profile, from Admin Profile.

    This section got too large and was split into a separate answer: Why is it a good idea to limit deployment of files to the user-profile or HKCU when using MSI?

    Essentially user-profile deployment of files or settings in HKCU are tolerable, but it might not be the best design, and it can be cumbersome to ensure that all settings and files make it into every user-profile and user registry on the box. The deployment problems that result and some proposed solutions are discussed in the linked answer above.

    Essentially user deployment can be supported using MSI self-repair, Microsoft Active Setup, or by logical design changes to the application or solution in question (the preferred option - see linked answer for details). In general deployment should not interfere with user data and settings since it is really user data and should not be deployed but generated at runtime by the application.

    10. Silent installation fails to complete or is incomplete

    A built-in feature of Windows Installer is that any MSI file can be installed in silent mode. This is a core feature of the technology intended to help corporate deployment - which is generally always run in silent mode. Making sure your MSI is capable of completing and successfully working after a silent install, is no less than exceptionally important. In my experience custom actions can often cause problems for silent install.

    11. You try to "force overwrite" files with your MSI installer

    MSI features some pretty complex "file versioning rules" designed to minimize the impact of "DLL Hell". They typically cause files to not be overwritten as intended - a classic MSI issue. As a result, people feel they can't find a reliable way to always force overwrite files on disk during installation.

    12. You install services that run with user credentials

    In my opinion this just isn't good practice, and typically people wipe out the credentials during major upgrade scenarios as well - and in some cases also settings files that the service uses.

    13. Your application requires extensive, custom NT privileges

    NT privileges are different from discretionary access control (the access control of file system and registry objects) and include things such as SeServiceLogonRight "logon as a service" (which must be set for any user account trying to run a service - a very common setup issue for setups trying to run services with user credentials).

    In some cases a plethora of such privileges are required to run an application or more likely a service. A very strong "deployment smell" or actually a "solution smell" - an anti-pattern if ever there was one.

    Just about all these privileges are dangerous to squander around.

    14. You apply a lot of custom disk and registry permissioning

    This is a definite "deployment smell" or deployment "anti-pattern". In almost all cases this can be avoided by redesigning the application in question.

    15. Your license key in the registry is reset on upgrade

    A very common design is to write a license key to the registry using an MSI component. This can be either HKCU or more often HKLM - in order to make it a shared license for all users on the same machine.

    If you use an MSI public property to set this license key, you should read this value back on a fresh install to ensure that you don't overwrite existing data there with an empty string. MSI public properties are (amazingly) not persisted and automatically read back by your upgrade setup in major upgrade scenarios. Forgetting to do this is a very common cause of people seeing their license key wiped out during major upgrade.

    I rarely, if ever, recommend read/write custom actions. They are error prone and can be complex to get right - and most people never implement proper rollback (if the setup crashes and needs to roll back). However, you also have more power to check the system's "current state" with a custom action, and you can condition your custom action so it always runs, even during the patching sequence, and you can have it do different things during different sequences if you need to. Most of the time it can actually be problem that custom actions run when not intended - for example during a patch installation. Few people remember to condition their custom action with NOT PATCH (to prevent running during patching).

    Despite all this I just might use a custom action to write a license key to HKLM during installation if I am instructed to write the license during the setup. However, and this is important, I would much rather remove the whole licensing issue from the setup altogether, for a lot of reasons described here: Installer with Online Registration for Windows Application (recommended read - there are a lot of reasons to keep licensing out of your setup).

    16. Undesirable Hard Coded GUIDs

    Some GUIDs can be hard coded in your WiX source file (or other MSI creation tool). For example component GUIDs - they should remain stable for each component, unless you change the installation location. The rationale for this is attempted explained here: Change my component GUID in wix?

    However, don't hard code the Package Code. An MSI's Package Code should always be auto-generated for every build. It is simply supposed to be unique. In more detail; the idea of a package GUID is that it should be unique for each compiled MSI file. It is simply there to uniquely identify a file. Two different MSI files with the same package GUID will be treated by Windows Installer as the same file by definition. All kinds of X-files problems result. Accordingly a package GUID should always be auto-generated since it is simply supposed to be unique.

    Many also auto-generate the Product Code - because they only use major upgrades to upgrade their applications. For this use-case auto-generated Product Codes work just fine. However, if you need to support Windows Installer minor upgrades as well, you should hard code your Product Code and update it when appropriate. The Upgrade Code should generally be hard-coded and manually managed. See this answer.

    17. Erronous Inclusion of Sensitive Data

    There is now a separate Q/A on the topic of preventing sensitive data from ending up in your final installer: How do I avoid distributing sensitive information in my MSI by accident?

    Essentially the advice is to give your files a once-over for hard coded dev-box sins. How to check? I don't get fancy about it, open the MSI with Orca - and just skim through the tables. Most vulnerable tables are probably: Registry, Property, IniFile, maybe Directory, and if you use the MSI GUI: all tables relating to GUI. Any scripts (CustomAction table or Binary table - the latter requiring you to stream out any scripts - or check them in their source locations).


    Links: