This post provides a free MSIX Packaging tool for the Package Support Framework (PSF), and is hosted in the PowerShell Gallery.
Most of us already know that native MSIX has its limitations (at time of writing) in terms of compatibility with some applications. For example, once we package an application into MSIX format we may find that it has issues finding DLLs, or generates Access Denied warnings amongst other annoying things.
So the folks over at Microsoft created the Package Support Framework (PSF), which was later forked by the great Tim Mangan to include additional functionality. The PSF essentially comprises of an executable which acts as the “PSF launcher”, a bunch of associated DLLs that provide “fix-ups”, and a config.json file which tells the launcher what to fix!
How Does The Package Support Framework Work?
In simple terms, we redirect any problematic shortcuts to the PSF launcher instead of the original executable. The PSF launcher then reads the associated config.json file which tells it what to do in terms of which executable to launch (the original executable) and which fix-ups to apply at runtime.
Why AlkanePSF?
When I originally wrote this (over a year ago), injecting the PSF into an MSIX package manually was a bit laborious and fiddly to say the least. The official MSIX packaging tool GUI didn’t support PSF configurations at the time (if I recall), and amending JSON files is prone to human error. So I created this PowerShell module called AlkanePSF that makes life easy (or easier).
The advantages of this scripted approach are that:
- It doesn’t require the MSIX packager. You can extract, inject fix-ups, recompile and sign on-the-fly.
- It could be used as part of an automation pipeline to inject fixes into a bunch of packages on a file share, or perhaps at the end of an automated conversion batch.
- It supports Tim Mangan’s PSF (which includes fix-ups like the MFR fix-up), which the official MSIX packaging tool doesn’t natively support.
- It’s fast when making fix-up modifications and re-retesting packages.
Caveats
- Whilst it does support every fix-up type, it doesn’t support every single fix-up configuration.
Assumptions
- You’ve already packaged your MSIX, launched it and it doesn’t work.
- You might have run some process monitoring, and have an understanding of which fixups you might need to apply. Maybe read the Package Support Framework Overview first.
- You have a code signing certificate and a password.
- You have a basic understanding of fix-ups. If not, use the links below to understand the different types.
Available Cmdlets
***NOTE – for example cmdlet parameters, please see code sample below***
Set-AlkanePSFConfiguration – Configure AlkanePSF for input and output.
Install-AlkanePSFPrerequisite – Installs Windows SDK/Microsoft PSF/Tim Mangan PSF.
New-AlkanePSFStagedPackage – Extracts/stages MSIX.
Get-AlkanePSFApplications – Returns a list of applications from the AppxManifest.xml
Get-AlkanePSFFiles – Returns a list of applications from the AppxBlockMap.xml
Add-AlkanePSFApplication – Adds an application from the AppxManifest.xml to “fix”. This must be called for any application that requires fixing.
Add-AlkanePSFFileRedirectionFixup – Adds a FileRedirectionFixup to the application.
Add-AlkanePSFRegLegacyFixup – Adds a RegLegacyFixup to the application.
Add-AlkanePSFEnvVarFixup – Adds a EnvVarFixup to the application.
Add-AlkanePSFDynamicLibraryFixup – Adds a DynamicLibraryFixup to the application.
Add-AlkanePSFMFRFixup – Adds a MFRFixup to the application (Tim Mangan only).
Add-AlkanePSFTraceFixup – Adds support for the trace module.
Add-AlkanePSFStartScript – Adds a StartScript.
Add-AlkanePSFEndScript – Adds an EndScript.
Add-AlkanePSFCapability – Adds capabilities (Such as elevation)
Add-AlkanePSFDependency – Adds dependencies (Such as Visual C++)
Remove-AlkanePSFApplication – Removes applications from AppxManifest.xml
Remove-AlkanePSFShortcut – Removes shortcuts from AppxManifest.xml
Add-AlkanePSFStringReplace – replaces strings (using a regular expression) in the AppxManifest.xml
Add-AlkanePSFProtocol – Adds a protocol for a given application ID
Set-AlkanePSF – Updates AppxManifest.xml, generates config.json.
New-AlkanePSFResourcesPRI – Recompiles resources if we need to add new assets.
New-AlkanePSFMSIX – Compiles and signs new MSIX.
Usage of Free MSIX Packaging Tool for the Package Support Framework
One day I’ll get around to documenting it properly. But until that day:
Install and import the module:
Install-Module AlkanePSF -Force
Import-Module AlkanePSF -Force
And use it like so (I’ve provided some example cmdlets and their arguments)
cls
#********************************************
#configure AlkanePSF
#********************************************
Set-AlkanePSFConfiguration -MSIXInputFilePath "C:\Alkane-SampleApp-1.0.0\Alkane-SampleApp-1.0.0.msix" `
-MSIXOutputFilePath "C:\Alkane-SampleApp-1.0.0\Fixed\Alkane-SampleApp-1.0.0.msix" `
-MSIXStagingFolderPath "C:\Alkane-SampleApp-1.0.0\Staging\" `
-MSIXCertificateFilePath "C:\Alkane.pfx" `
-MSIXCertificatePassword (ConvertTo-SecureString "certpass" -AsPlainText -Force) `
-MSIXArchitecture "64" `
-PSFType "TM" `
-TimManganZipUrl "https://github.com/TimMangan/MSIX-PackageSupportFramework/blob/develop/ZipRelease.zip-v2024-10-26.zip?raw=true"
#********************************************
#install prereqs (SDK, Tim Mangan's PSF etc)
#********************************************
Install-AlkanePSFPrerequisite -ForceReinstall
#********************************************
#Extract (stage) the MSIX package
#********************************************
New-AlkanePSFStagedPackage -ForceOverwrite
#********************************************
#Iterate through all files in block map. Useful for providing fixes to specific file extensions etc
#********************************************
#$allFiles = Get-AlkanePSFFiles -Filter "*.exe"
#foreach($file in $allFiles) {
# write-host $file
#}
#********************************************
#Iterate through each application in our MSIX (iterating optional)
#********************************************
$appIds = Get-AlkanePSFApplications
foreach($app in $appIds) {
$appId = $app.id
$appExe = $app.executable
$appWorkingdir = Split-Path -Path $appExe
#********************************************
#Add an app for PsfLauncher to invoke
#********************************************
Add-AlkanePSFApplication -ApplicationId "SAMPLEAPP" -WorkingDirectory "$appWorkingdir" -Arguments @("arg1","arg2") -InPackageContext -ScriptExecutionMode "-ExecutionPolicy Bypass"
#********************************************
#Define fixups we want to apply
#********************************************
Add-AlkanePSFTraceFixup -FixupExePattern ".*" -FixupTraceMethod "outputDebugString" -FixupWaitForDebugger -FixupTraceFunctionEntry -FixupTraceCallingModule -FixupIgnoreDllLoad -FixupTraceLevelProperty "default" -FixupTraceLevelValue "allFailures" -FixupBreakOnProperty "default" -FixupBreakOnValue "allFailures"
#Add env var fixups
Add-AlkanePSFEnvVarFixup -FixupExePattern ".*" -FixupVarName "alkaneenv1" -FixupVarValue "alkanevalue1" -FixupVarUseRegistry
Add-AlkanePSFEnvVarFixup -FixupExePattern ".*" -FixupVarName "alkaneenv2" -FixupVarValue "alkanevalue2" -FixupVarUseRegistry
#Add DLL fixups
Add-AlkanePSFDynamicLibraryFixup -FixupExePattern ".*" -FixupDllName "alkane1.dll" -FixupDllFilepath "VFS\Alkane\alkane1.dll"
Add-AlkanePSFDynamicLibraryFixup -FixupExePattern ".*" -FixupDllName "alkane2.dll" -FixupDllFilepath "VFS\Alkane\alkane2.dll" -FixupForcePackageDllUse
#Add reg legacy fixups
Add-AlkanePSFRegLegacyFixup -FixupExePattern ".*" -FixupType "FakeDelete" -FixupHive "HKCU" -FixupAccess "FULL2RW" -FixupPatterns@(".+\.exe",".+\.dll")
Add-AlkanePSFRegLegacyFixup -FixupExePattern ".*" -FixupType "ModifyKeyAccess" -FixupHive "HKLM" -FixupAccess "Full2MaxAllowed" -FixupPatterns@(".+\.exe",".+\.dll")
#Add MFR fixups (only applies to Tim Mangan PSF)
Add-AlkanePSFMFRFixup -FixupExePattern ".*" -FixupType "overrideLocalRedirections" -FixupName "ThisPCDesktopFolder" -FixupMode "Disabled"
Add-AlkanePSFMFRFixup -FixupExePattern ".*" -FixupType "overrideLocalRedirections" -FixupName "Personal" -FixupMode "traditional" -FixupIlvAware
#Add file redirection fixups
Add-AlkanePSFFileRedirectionFixup -FixupExePattern ".*" -FixupType "packageDriveRelative" -FixupBase "example3" -FixupPatterns @(".+\.log") -FixupExclude
Add-AlkanePSFFileRedirectionFixup -FixupExePattern ".*" -FixupType "knownFolders" -FixupId "ProgramFilesX64" -FixupBase "example1" -FixupPatterns @(".+\.log") -FixupReadOnly
Add-AlkanePSFFileRedirectionFixup -FixupExePattern ".*" -FixupType "packageRelative" -FixupBase "example2" -FixupPatterns @(".+\.log") -FixupExclude
Add-AlkanePSFFileRedirectionFixup -FixupExePattern ".*" -FixupType "knownFolders" -FixupId "ProgramFilesX64" -FixupBase "example4" -FixupPatterns @(".+\.log")
Add-AlkanePSFFileRedirectionFixup -FixupExePattern ".*" -FixupType "packageDriveRelative" -FixupBase "example3" -FixupPatterns @(".+\.log")
#********************************************
#Add file redirection for all log files in VFS
#********************************************
##$vfsFolder = "C:\Alkane-SampleApp-1.0.0\Staging\VFS"
##Get-ChildItem -Path $vfsFolder -Recurse -Include *.log | Select -ExpandProperty DirectoryName -Unique | foreach {
##$fullPath = $_.Replace($vfsFolder,"VFS")
##Add-AlkanePSFFileRedirectionFixup -FixupExePattern ".*" -FixupType "packageDriveRelative" -FixupBase $fullPath -FixupPatterns @(".+\.log")
##}
#********************************************
#Add scripts we want to run for the relevant application(s)
#********************************************
Add-AlkanePSFStartScript -ApplicationId "SAMPLEAPP" -ScriptSourcePath "C:\Alkane\Scripts\ExampleScript.ps1" -ScriptArguments @() -RunInVirtualEnvironment -StopOnScriptError -WaitForScriptToFinish -Timeout 30 -RunOnce
Add-AlkanePSFEndScript -ApplicationId "SAMPLEAPP" -ScriptSourcePath "C:\Alkane\Scripts\ExampleScript.ps1" -ScriptArguments @("-install") -RunInVirtualEnvironment -ShowWindow -WaitForScriptToFinish -Timeout 30 -RunOnce
#********************************************
#Add capabilities to AppxManifest.xml
#********************************************
Add-AlkanePSFCapability -Capability "allowElevation"
#********************************************
#Add dependencies to AppxManifest.xml
#********************************************
Add-AlkanePSFDependency -DependencyName "Microsoft.VCLibs.110.00.UWPDesktop" -DependencyMinVersion "11.0.61135.0" -DependencyPublisher "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
#********************************************
#Remove applications from AppxManifest.xml
#********************************************
#Remove-AlkanePSFApplication -ApplicationId SAMPLEAPP
#********************************************
#Remove shortcuts from manifest (-ShortcutName is "like" comparison, hence this example will remove all desktop shortcuts)
#********************************************
Remove-AlkanePSFShortcut -ShortcutName "[{Desktop}]"
#********************************************
#Generate new config.json
#********************************************
Set-AlkanePSF -OverwriteConfigJson -OpenConfigJson
#********************************************
#Compile new MSIX
#********************************************
New-AlkanePSFMSIX
}
You can quickly tweak and regenerate your MSIX file to test modifications in a matter of seconds – just re-run the script!
Hint: If you want to view the config.json at the end of each compilation, specify -OpenConfigJson
when calling Set-AlkanePSF
.
This is work in progress, so your feedback in the comments below is always welcome!