Unlike MSI, MSIX does not offer a solution when it comes to custom actions. You don’t even have sequences where you can place the custom actions in an MSIX.
However, to help IT Pros, Microsoft does offer a way to trigger a PowerShell script during the launch or closure of the application with PSF (Package Support Framework). Keep in mind that these scripts CANNOT be placed to run during installation/uninstallation. All the alterations you with to perform with these scripts can only be done upon launching/closing an application after installation.
I already covered some of the basics of PSF in a previous article. In this article, we are going to add a script to copy the application data (appdata) from the VFS to the %localappdata%\packages\PublisherName.AppName_hash during the first launch. This way, the settings which are captured inside the %appdata% folder can be accessed by the application.
1. Download PSF Binaries
The simplest way (from my point of view) to get the PSF is to go through Nuget.
Navigate to this link and select “Direct Download”. Once Downloaded, extract the .nupkg with 7Zip or other archive tool.
That’s it, all the required files can be found in the bin folder.
2. Add PSF Binaries in the MSIX
With all the PSF files downloaded, open up the package with MSIX Packaging tool.
The following files must be added in the ROOT of the package:
The StartingScriptWrapper.ps1 is very important, because PSF used this PowerShell script to start your desired PowerShell script. I know it sounds weird, but this is how it’s designed to work.
At the end, your package should look something like this:
3. Edit the manifest file
In the MSIX Packaging Tool from Microsoft, in the Package Information Tab (on the left) scroll down until you see “Manifest File” and click “Open File”.
This will open up the MSIX manifest file with Notepad.
In here, navigate to your “Applications” element and look for your “Application”. In this example, we have:
<Application Id=”SAMPLEAPPLICATION” Executable=”VFS/ProgramFilesX86/SampleApplication.exe” EntryPoint=”Windows.FullTrustApplication”>
This must be changed to open the PSFLauncher32.exe. We are using the 32 bit version of PSF Launcher because our application is 32 bit. In case you don’t know the application architecture, use the 32bit one and see if it works. If not, change it to the 64 bit.
In the end, it should look something like this:
<Application Id=”SAMPLEAPPLICATION” Executable=”PsfLauncher64.exe” EntryPoint=”Windows.FullTrustApplication”>
4. Create and add the config.json in the MSIX
We added the PSF binaries, we modified our application (shortcut) to start the PSF Launcher, now all we have to do is to create a config.json file which tells the PSF Launcher what to actually do.
A sample config.json file can be found on this Microsoft post that explains how scripts can be added.
In this example, the config json file looks like this:
- stopOnScriptError: If the PowerShell script fails, the launch of the application is stopped. In our case we left it as false
- scriptExecutionMode: Determine what execution mode is used when running the PowerShell script. We set it to run as Unrestricted, but you can leave it as RemoteSigned
- scriptPath: The location of the script. Because the script is at the base of the package (not in subfolders) we left only CopyFiles.ps1. If the script was in subfolders, the full path must be provided (e.g: VFS\Script\CopyFiles.ps1)
- showWindow: Determines of the PowerShell window is shown. In our case we left it as false
- waitForScriptToFinish: Determines if the launch of the application waits for the script to finish. This should always be left as true
- runOnce: If you want to execute the script at each launch, this should be set to false. Because we are only copying the %appdata% folder at first launch, we are going to leave it as false
5. Create and add the PowerShell script in the MSIX
The last step to do is to create the PowerShell script that is going to be executed during the launch of the application. Notice how in the previous step, we called the script CopyFiles.ps1.
The script which copies the %appdata% to the %localappdata%\packages\PublisherName.AppName_hash is actually simple, and it looks something like this: