Don't Do It: Use Immediate CustomAction For Changing The System State
Let's put it bluntly, you should never set a CustomAction to “Immediate” when you intend to change the system state.
Why - you ask?
When you plan to change the system state, you should always use a Deferred CustomAction because only with it, you can have a corresponding rollback custom action to undo the system state change on an installation rollback -- in case of a failure.
The Immediate Custom Actions are suitable for situations when you need to set properties, feature or component states, or schedule system operations by using rows in sequence tables.
To give it more context, first we'll address what is a CustomAction, the phases of a successful installation and the differences between "Immediate" and "Deferred" CustomActions.
What is a Custom Action?
A package in MSI format uses the Windows Installer service provided by Microsoft to install and configure an application (a widely-known fact within professionals in the industry). As stated in the Windows Documentation, "the Windows Installer database consists of many interrelated tables that together comprise a relational database of the information necessary to install a group of applications".
By default, Windows Installer provides several dozen built-in actions to deal with the installation of an application. However, there might be cases where you need to write a custom action to add a specific customization to your application. For these cases, the CustomAction table provides you with the means of integrating the custom code into the Windows Installer package.
The source of the custom code can be one of the following:
- a stream
- a file within the package
- a file outside the package
To make more sense of the process and the reasons behind why you should avoid using the "Immediate" CustomAction when making a change in the system state, let's go through the two phases of a successful installation:
1. The acquisition phase – which is intended to gather information for the installation, such as:
- Query target system – LaunchCondition action is the process of evaluating each conditional statement recorded in the LaunchCondition table. If any of these conditional statements fail, then an error message is displayed and the installation is terminated.
- Check available hard disk space – File Costing is the process of evaluating the disk space requirements needed by the installer.
- Collect installation information that is displayed to the user through the installation wizard.
2. The execution phase – which is intended to install the application and make changes to the system.
If the installation is unsuccessful, then a rollback phase may occur.
Now that we've discussed the phases of a successful installation, we can move to see the difference between an "Immediate" and a "Deferred" CustomAction -- which is where we'll be able to see why we shouldn't use "Immediate" CustomActions to make changes to the system state.
Immediate vs Deferred CustomActions: The Differences
In the acquisition phase, you can use "Immediate" CustomActions, which run in the context of the user performing the installation -- and must not change the system.
Windows Installer uses “sequences” to specify the order in which the actions are performed (either standard actions or custom actions).
As its name implies, “Immediate” CustomActions are executed straight away in the order in which they appear in the sequence. Because this type of CustomActions run before any change is made to the target system, they cannot refer or rely on any file that is being installed by the MSI package.
On the other hand, if a CustomAction has a “Deferred” attribute set to it, Windows Installer only evaluates the condition (during the acquisition phase). If the condition is true, then it follows the sequence and builds the script that will be executed (during the execution phase).
Only Deferred CustomActions can run with elevated permissions using the system context.
Deferred CustomActions can be used in conjunction with:
The Reasons Why You Shouldn't Use Immediate Custom Actions When Changing The System State
There are two main reasons why you should avoid scheduling Immediate CustomActions and stick to Deferred CustomActions when wanting to change the system state:
- First reason is that Deferred CustomActions allow you to perform a rollback;
- The second reason is that only Deferred CustomActions can run in the system context.
You need to schedule a Deferred CustomAction in the Execute Sequence table within the section that performs the script generation – this happens after InstallInitialize and before InstallFinalize.
Deferred CustomActions don't provide access to the original session handle and property data set during the installation sequence as Immediate CustomActions do.
According to Windows Documentation's best practices, "you should not attempt to use an Immediate custom action to change the system state, because every custom action that changes the state needs to have a corresponding rollback custom action to undo the system state change on an installation rollback."
For more details on how to obtain context information for a Deferred CustomAction, you can check the Microsoft Docs.
How does this look in practice? The MSI Log File
To offer you a practical example, I chose a very simple script that replaces a string within a text file installed by our package -- and I will show you how I set up the corresponding CustomAction within the package.
From what we've learnt before, this CustomAction will change the system and therefore must be set as “Deferred” rather than “Immediate”.
There are multiple types of CustomActions you can choose from depending on your requirements. For this specific scenario, I opted for “Custom Action Type 34 EXE file having a path referencing a directory” which is calling wscript.exe from System32 folder with my VB Script as an argument.
Advanced Installed comes with a built-in list of predefined CustomActions that you can use to simplify your customizations.
For more info about Custom Action Types, you can have a look here.
Keep in mind that on Windows Vista or above versions, the custom actions that affect the system or require Administrator privileges should typically run without impersonation. To meet this requirement, I simply checked the “Run under the LocalSystem account with full privileges (no impersonation)” box under “Execution Options”.
Like any other “Deferred” CustomAction, it must be scheduled to be executed between InstallInitialize and InstallFinalize. In this example, I have chosen to schedule it straight after InstallFiles for the simple reason that the text file that gets updated by the CustomAction must be installed on the system when the CustomAction is getting executed.
Now, let’s have a peek within the log file created for an MSI installation.
You can get more insights on how to create a log file for your MSI package here.
If you search for the name of your CustomAction, lines similar to the one below should appear in your MSI log file:
This is the acquisition phase where, as stated previously, Windows Installer only evaluates the condition and if true, then it builds the script to be executed during the execution phase.
CustomActions have been and will always be used by enterprises in order to customize their applications before rolling them out to production.
I hope that in this article, I succeeded at shedding some light on when and why you should use either an Immediate or Deferred CustomAction. And most importantly, to share the main reason why you shouldn't use the "Immediate" CustomAction -- when it can cause changes to the system state.
Popular custom actions such as Terminate Process, Get Free Disk Space, Add Network Location, Install/Uninstall Certificates, and many more are available out of the box with Advanced Installer, minimizing time and work efforts for the end-user. If you have any suggestions for CustomActions that you commonly use and are not there in our predefined list already, please let us know.
If you have any further inquiries , please do not hesitate to let us know by commenting below.