Custom Actions in MSIX vs. MSI vs. App-V Scripting - A quick comparison
Scripts have been traditionally used by ISVs to add Custom Actions to their applications and make changes to the environment. They have been present in MSI and App-V packaging formats for ages, while for MSIX, they were introduced and supported about a year after Microsoft announced the MSIX release.
From the MSI perspective, it is common to have at least one CustomAction script added to your package.
Over the years, I have come across some application installers that required a lot of reverse engineer work. Through my experience, I've encountered situations when I've had to add a dozen of CustomAction Scripts to my packages in order to get them to install and uninstall smoothly - and to be able to customize them to meet organization requirements. Fortunately, this changed a lot when App-V came into play.
How? Let’s go into a short overview of Application Packaging scripting and a comparison of how it has changed between MSIX, MSI and App-V.
How Scripting Worked with MSI and App-V
The oldest and probably the most used packaging format – MSI Windows Installer – comes with extensive flexibility in terms of the execution sequence for the CustomAction that contains the script. With just a few limitations (mainly depending on the CustomAction type), you can place your script pretty much anywhere in the sequence.
When App-V 4.6 came in, the whole concept around scripting changed - and then it changed again with App-V 5. As virtualization technologies, they both offer the capability of running your script inside or outside the App-V container. You can call your script based on a handful of your package's specific lifecycle events - illustrated in the figure below:
|App-V Package Event||Can run within App-V container ?||System User Context||Description|
|App-V 4||App-V 5|
|OSD||Deployment Config.||User Config.|
|AddPackage||N/A||System||N/A||After the App-V package is added|
|PublishPackage||N/A||System||User||After the App-V package is published (globally or not)|
|PRE STREAM||User||N/A||N/A||Before the App-V package is streamed|
|POST STREAM||User||N/A||N/A||After the App-V package is streamed|
|StartVirtualEnvironment||N/A||User||User||After the virtual environment is started|
|StartProcess||N/A||User||User||After the virtual application is launched and the corresponding process is started|
|PRE LAUNCH||User||N/A||N/A||Before the virtual application is launched|
|POST LAUNCH||User||N/A||N/A||After the virtual application is launched|
|ExitProcess||N/A||User||User||After the virtual application is shuted down and the corresponding process terminated|
|POST SHUTDOWN||User||N/A||N/A||After the virtual application is shuted down and the corresponding process terminated|
|TerminateVirtualEnvironment||N/A||User||User||When the virtual environment is terminated|
|UnpublishPackage||N/A||System||User||Before the App-V package is unpublished (globally or not)|
|RemovePackage||N/A||System||N/A||Before the App-V package is removeed|
How Scripting Works In MSIX
In contrast with MSI and App-V, MSIX packages do not natively support scripting, but you can use the Package Support Framework to run PowerShell scripts. MSIX scripts can only be triggered by 2 specific events: startScript and endScript.
“scriptPath” is the only configuration item that is mandatory and must contain the path to the script – including the name and the extension. All the others are optional.
There was a time when you were able to specify whether a script would run inside or outside an MSIX container by setting “runInVirtualEnvironemnt”.
However, that option was decommissioned when Microsoft introduced the so-called PSF Launcher Pseudo-Variables (%MsixPackageRoot% and %MsixWritablePackageRoot%) which can be used to force the script to run inside the container. Setting “RunOnce'' to “true” allows your script to run only once per user, per version, and it will prevent it from running for any subsequent starting/ending of the application.
You can specify whether the application waits for the script to complete before starting by setting “waitForScriptToFinish”. When this is set to “true”, you can also define how long the application must wait for the script to complete. When the time elapses, the script is terminated and will return an error; if you set “stopOnScriptError” to “true”, this will prevent your application from starting.
The “waitForScriptToFinish” and “stopOnScriptError” configuration items are applicable only for “Process Start” scripts and they are completely ignored for “Process End” scripts.
Take into consideration that setting “stopOnScriptError” to “true” and “waitForScriptToFinish” to "false" for the same application is not supported.
As for any standard PowerShell script call, you can specify any script arguments parsed to the PowerShell script if needed. Also, you can state where the PowerShell window is suppressed by setting “showWindow”.
All the above-mentioned configuration items are optional. As mentioned before, the only configuration item that is mandatory and must contain the path to the script – including the name and the extension - is “scriptPath”.
You can easily set all the configuration items that I've mentioned directly from the Advanced Installer GUI. Below, you can find an example of a PowerShell script added into an MSIX package for the purpose of editing a file located within MSIX Package Root.
And the corresponding section within the config.json file
If you are new to Package Support Framework, you may want to have a look at our Introduction to Package Support Framework article.
If we compare the 3 packaging formats -- MSI, App-V, and MSIX -- strictly from the scripting perspective, it is clear that MSI offers the most flexibility by far. But, some installers were created using MSI just as a wrapper for extra space left and flexibility, and sometimes even not considering best practices.
In my opinion, this is not the best course of action, and we can see a good example of that with the Google Chrome Enterprise installer. If you look in the Files or Shortcuts table, you will see that they have no entries. Instead, there are some files added to the Binary table which are then executed via Custom Actions.
On the other side, some of you may think that having only two events that can trigger the script within your MSIX package limits IT Pros when it comes to customizing their packages.
That’s true, it may not be enough. But at the same time, it serves as a limiting factor for vendors, requiring them to adhere to industry best practices. In the end, it is a positive restriction that leads to less reverse engineering work for IT Pros. And to top it off, it helps to have a more standardized MSIX packaging format.
I hope you found this quick overview comparing scripting in MSIX vs MSI and App-V handy.
We're curious, which scripting process do you prefer?