Packaging and repackaging 201
Published: 23 March 2015 - Last update: 12 Dec 2015 (c) Nicolai Kjaer / Spinner Software B.V.
This document is meant for advanced tips and tricks for application scripting/packaging.
This is an example section.
Tips are shown in these sections.
1. Property repair
By default, property values that were changed via commandline are not remembered during a repair. This section explains how to fix it.
The basic idea is this: To remember the value of a property during installation, you must save it to somewhere (e.g. the registry) during installation and have Windows Installer look it up before repairing. Windows Installer uses the AppSearch table in combination with a locator table in order to find the value the property must be set to before repair.
To remember a property via the registry:
Windows Installer will now set the value of MYPROPERTY to the value stored in the registry before actually repairing.
Use CompLocator for component keypaths, IniLocator for ini entries, and DrLocator for folders.
2. Non-advertised shortcuts
Older shortcuts usually points straight to an executable. This prevents the auto-repair functionality (self-heal) of Windows Installer, and should be fixed.
To fix this, we must find the target component and feature, and make sure it only contains the executable file, and that the component KeyPath points to it. Once this is done, you can change the shortcut to point to the target feature and component - and Windows Installer will repair if the executable is not found.
3. Installing features by commandline
You can use ADDLOCAL to specify which features to install via the commandline. This can be useful for some deployments where a large number of plugins are present, and you use the basic vendor installation with a different commandline depending on the target.
ADDLOCAL=feature1,feature2,etc.Keep in mind that you may need to specify subfeatures, depending on their state / attributes. Always try and keep the vendor documentation handy if they support deployments like this.
Only use ADDLOCAL on commandline, never in a transform ! When Windows Installer removes a product, REMOVE will be "ALL" and ADDLOCAL should be empty. Otherwise those features specified in ADDLOCAL will never be removed.
4. Removing empty directories
It happens regularly that a vendor msi creates a folder (perhaps via the CreateFolder table), but never removes it. To fix this, we can add entries to the RemoveFile table to remove the folder if it was empty after the component was removed.
Note that this will not work for removing files/folders from the users profile in normal cases of deployments (e.g. SCCM), as the user used to install or remove application is a system account and not the actual user.
5. Custom Actions
I wrote an example for VbScript some 10 years ago - see Custom Actions.
You can disable a custom action in the InstallExecuteSequence by putting the condition to 0 (false). This can be needed in order to fix certain installations, or to maintain guidelines. For example, Adobe sets the ARPREADME property to the locally installed readme file with a custom action during the installation ; if your guidelines specify that this entry should be left blank, you can disable that custom action.
5.1 Deferred vs immediate
During an installation or removal, Windows Installer essentially executes 2 phases:
Custom Actions that are marked as Immediate, are executed in phase 1. Custom Actions that are marked as Deferred, are executed in phase 2. Custom Actions marked as Deferred System Context, are executed within a limited part of phase 2, in a system context (not user).
This is also why there is such a strict limit to what you can do with values (properties etc) in phase 2. Everything was already resolved in the previous phase.
The way to pass data to a deferred custom action is to create a property with the exact same name as the custom action. The data in the property can then be referenced in the script using MsiGetProperty("CustomActionData").
6. User Interfaces
There are two parts to what the user sees during the installation:
The Dialog table contains the definition of the various windows (also called Dialogs or Forms) that the user sees during the installation. It has entries to define width, height, title etc. You can consider this the canvas on which Controls are painted, as defined in the Controls table. What happens during the user interaction with the window is defined in the related ControlEvents and ControlCondition tables.
You would normally use an editor to change the layout and content of the window, instead of changing entries in these tables directly.
The tables are handy though - if you are not sure in which property a value is stored, you can check to see what happens when you would enter it during an installation with a user interface. Find the dialog that matches the window, then find the control where you enter the value. The Property field controls the value for the control. It could also have a control event set to [PROPERTY], with the argument being the new value.
This is somewhat identical to the InstallExecuteSequence, except it controls the user interface, and therefore mostly just spawns Dialogs.
You will sometimes see smaller vendors using a lot of custom actions in the InstallUISequence, mostly in order to provide feedback to the user (such as popup message boxes). Keep in mind that this will not happen during a deployment, as there will be either none, or a very limited user interface (e.g. progress bar only). Any UI Custom Actions that installs or configures items should be matched during an unattended installation.
7. Prerequisites and Merge Modules
You will often see an application either downloading or installing a prerequisite such as Microsoft Visual C++. You can handle this in many ways:
1. Deploy the prerequisite to all machines. Some prerequsites are required by so many different software packages that it will make sense to do so ; a good example is Visual C++ and the .NET frameworks.
2. Include the prerequisite as a separate installer, to be run before the installation itself. For example, you can specify this in SCCM.
3. Include the prerequisite as a Merge Module in your package. This is mostly useful for old requirements that only include one or two DLLs, such as Visual C.
When using Microsoft deployments (e.g. Office 365), it will download any missing components. Always check the installation log file for download tasks. You can also disable the network temporarily in order to ensure the installation fails instead of downloading any missing prerequisites.
8. Analysing Logfiles
To generate a logfile, add this to your normal msiexec commandline
Since the exitcode from MsiExec is the main error code, it's nice to have it shown directly when running installation test scripts. You can do so by adding
@ECHO Result: %ERRORLEVEL%straight after the MsiExec line in your script.
Example install.cmd test script with log and result:
@ECHO OFF MsiExec /I My.msi /L*v %temp%\My.log /Qn ECHO Result: %ERRORLEVEL% PAUSE
A lot of the errors you will see along the way are standard, and you'll learn to fix them without looking up the actual error in the logfile. Some standard errors and their typical unofficial meaning:
1602 You cancelled the installation before it was finished. 1603 Generic fatal error, usually in a custom action script. 1605 You cannot remove something you haven't installed. 1618 Another installation is in progress. 1619 You used a wrong path\filename (not found). 1620 That's not an msi file. 1622 Logging path is invalid. 1624 Transform path is incorrect. 3010 (warning) Reboot is required to complete the installation. If this should not be needed, change the REBOOT property to ReallySuppress.
After the installation or removal fails, open %TEMP%\My.log in Notepad. The logfile can generally be viewed as 3 sections:
Start/buildup Execution until Failure Rollback and exitYou need to find the Error: sentence that describes what went wrong, at the end of the execution phase. There will probbaly be a lot of FileCopy and RegAddValue etc until something goes wrong, and then it notes the error and starts the rollback (resulting in RemoveFile, RegRemoveValue, etc).
At the end of the log it will also state the resulting exitcode, which you can also search for (e.g. if the exitcode was 1710, search for 1710 and you should find the Error: 1710 after a few hits). Once you find the precise failure, you should have 1-2 lines of code documenting exactly what went wrong. Fix it and retest.
If you try and install Java 8 as a non-admin, the installation fails.
For further reading, please check MSDN, Msi.chm, or your tool documentation.
I hope you enjoyed this guide !
(c) 2015 Nicolai Kjaer, Spinner Software B.V.