Repackaging an InstallShield MSI based EXE |
Installation automation is pretty simple for non-MSI based products but becomes quite difficult if an MSI or an MSI based InstallShield EXE due to the Windows Installer restriction which only allows a single install at a time (with nested MSI installs the only exception).
One common way to handle this situation is to create your own "setup.exe" which invokes the install and uninstall of the 3rd party products followed by your own.
Note that Microsoft have admitted that their implementation was flawed and have dropped support so I recommend that you use the approach described in the "Create a MSI Transform" section instead.
MSI Customisation |
Features can be selected or deselected, files and shortcuts can be moved etc with the appropriate command line options.
Nested MSI in UI Sequence |
The example below was inserted into the "InstallExecuteSequence" as this product will always be silently installed.
In general a better approach might be to sequence the nested MSI's install into the user sequence "InstallUISequence" and add a validation to the "InstallExecuteSequence" so that if the product wasn't already install and it wasn't installed in the UI sequence then a error message is displayed.
This covers the installation by the average "Joe" (user interface) and silent install (in a way) as corporate customers can simply ensure the other required product(s) are also installed (allow a few "bounces").
isscript.msi |
This InstallShield MSI installs InstallShield custom action support. You may need to install this on a box if no other similar InstallShield developed MSI has ever been installed.
The one I had had a major bug requiring me to created a corrected version to fix the corrupt table entry for the "F1324_ISRES.dll" rowkey in the "File" table.
The MSI does not install as such so there is no need to every worry about its uninstallation. The relevant code to install this support is:
;---------------------------------------------------------------------------- ;--- Need to install INSTALLSHIELD Support ---------------------------------- ;---------------------------------------------------------------------------- #define CdFileInstallShieldMsi isscript-Fixed.msi ;;Fixed InstallShield MSI - "F1324_ISRES.dll" File entry invalid! <$Binary Table="_Storages" Key="InstallShieldMsi" "<$CdFileInstallShieldMsi>"> <$Table "CustomAction"> <$Row Action="InstallShieldInstall" *Type="CATYPE_MSI_IN_STORAGES_TABLE" Source="InstallShieldMsi" Target=^ALLUSERS=1^> ;;Installs files but no package left installed! <$/Table> <$Table "InstallExecuteSequence"> <$Row Action="InstallShieldInstall" Sequence="1461" Condition=^<$CONDITION_INSTALL_ONLY>^> <$/Table> <$TABLE "ActionText"> <$Row Action="InstallShieldInstall" Description="Installing InstallShield Support"> <$/TABLE>
The following code installs the actual vendor MSI. It has been sequenced so services or registry can be adjusted as required. The MSI requires the "data1.cab" file to be available in the "source" directory at install time. The CD had many other language based files however none of these are required for my english only based installation so I did not copy these.
#define CdFileMsi TheMsi.msi #define CdFileMsiCab Data1.cab #define NESTED_MSI_FEATURES ARPNOREMOVE=1 ARPNOMODIFY=1 ARPNOREPAIR=1 ;;If allowed fails anyway (stupid...) #( #define VENDOR_MSI_OPTIONS PROPERTY1=VALUE1 PROPERTY2=VALUE2 INSTALLDIR="[INSTALLDIR]" ;;Where do the client related files go? SERVERDIR="[SystemFolder]" ;;Where do the service related files go (must go here according to doco) #) <$Binary Table="_Storages" Key="TheMsiVendor" "<$CdFileMsi>"> <$MsiExtraFiles "<$CdFileMsiCab>"> ;;What files does the MSI need to have available? <$Table "CustomAction"> #define NESTED_MSI_IGNORE_RETURN_CODE CATYPE_MSI_IN_STORAGES_TABLE or msidbCustomActionTypeContinue <$Row Action="VendorMsiInstall" *Type="CATYPE_MSI_IN_STORAGES_TABLE" Source="TheMsiVendor" Target=^ALLUSERS=1 <$NESTED_MSI_FEATURES> <$VENDOR_MSI_OPTIONS>^> <$Row Action="VendorMsiRemove" *Type="<$NESTED_MSI_IGNORE_RETURN_CODE>" Source="TheMsiVendor" Target=^REMOVE=ALL^> <$/Table> <$Table "InstallExecuteSequence"> ;--- Install the MSI ---------------------------------------------------- <$Row Action="VendorMsiInstall" Sequence="1465" Condition=^<$CONDITION_INSTALL_ONLY>^> ;--- Only uninstall if installed (later failure will NOT rollback uninstall) --- <$Row Action="VendorMsiRemove" Sequence="1466" Condition=^<$CONDITION_UNINSTALL_ONLY>^> <$/Table> <$TABLE "ActionText"> <$Row Action="VendorMsiInstall" Description="Installing The vendor MSI"> <$Row Action="VendorMsiRemove" Description="Removing The vendor MSI"> <$/TABLE>