-
Notifications
You must be signed in to change notification settings - Fork 3
PsfLauncher
The PsfLauncher is an executable that is provided in the PSF to act as a wrapper for any containerized application entry-point that needs the PSF. The most common use of PsfLauncher is to act at the target of Start Menu items. The PsfLauncher uses configuration from the config.json file to know what to do, which will include what target application to actually launch inside the container.
PsfLauncher is more than just for those typical start menu entry-points. It is used for:
- Start Menu entry-points to exes in the package.
- Start Menu entry-points to exes not in the package but must run in the container for configuration and/or plug-ins.
- Start Menu entry-points to non exe targets, like scripts and documents and Web URLs.
- File Type Association entry-points.
- Protocol Handler entry-points.
PsfLauncher is available in both 32-bit and 64-bit varieties. The bitness of the application (Microsoft uses the overloaded term 'Architecture' for this) must match the bitness of the PsfLauncher used. This bitness rule also applies to all of the dlls (both PsfRuntime dll and Fixup dlls).
One of the limitations of the MSIX AppXManifest file is that you must have an independent Application element in the manifest for each entry-point, and no two Application elements can have the same exe. To make this work, we often make multiple copies of PsfLauncher in the package and give them different names. We recommend starting that name with the 'PsfLauncher' string to make debugging easier. Some tools just call them PsfLauncher1.exe, PsfLauncher2.exe, and so on.
The following drawing walks through the typical way that a traditional application is started from a Start Menu shortcut, and how it works with Psflauncher:
In the traditional application, the installer creates a shortcut (lnk file) and deposits into one of the start menu folders. In windows 10, this is detected and an entry in the Windows 10 Start Menu is added (along with other lnk files and entries from UAP/MSIX packages). This entry points to the target application and it is normally run outside of the container and/or PSF.
The bottom part of the image shows what happens when the app is containerized with the PSF.
The MSIX package will have an applicaiton entry-point that is added to the start menu. This will now point to a copy of the PsfLaunncher application. Then:
- PsfLauncher automatically loads in PsfRuntime dll, and this dll finds and reads the Application section of the config.json file to find the matching entry for the name of our PsfLauncher file.
- That configuration will cause the runtime to start the idenfied target application and
- inject another copy of PsfRuntime into that new process.
- The copy of PsfRuntime in the new process will also locate and read the config.json file, but in this case looking for a matching entry from the Process section of that file, and
- The PsfRutime in that process will inject and configure any additional Fixup dlls defined in that Process configuration.
The Applications section of the json identifies applications by matching to the Application Id field of an application in the AppXManifest file and not necessarily the actual name of the exe process. While other third party tooling may use different naming schemes for the creation of the Id field in the AppXManifest file, the Microsoft MSIX Packaging Tool uses a munging of the process name that you can see in this partial AppXManifest file:
<Package ...>
...
<Applications>
<Application Id="PSFLAUNCHEROne" Executable="PsfLauncher1.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements BackgroundColor="transparent" DisplayName="7-Zip File Manager" Square150x150Logo="Assets\SevenZFM-Square150x150Logo.png" Square44x44Logo="Assets\SevenZFM-Square44x44Logo.png" Description="7-Zip File Manager">
<uap:DefaultTile Wide310x150Logo="Assets\SevenZFM-Wide310x150Logo.png" Square310x310Logo="Assets\SevenZFM-Square310x310Logo.png" Square71x71Logo="Assets\SevenZFM-Square71x71Logo.png" />
</uap:VisualElements>
...
</Application>
<Application Id="PSFLAUNCHERTwo" Executable="PsfLauncher2.exe" EntryPoint="Windows.FullTrustApplication">
...
</Application
</Applications>
</Package>
The config.json file for this package might have an applications section such as this:
"applications": [
{
"id": "PSFLAUNCHEROne",
"executable": "VFS\\ProgramFilesX64\\7-Zip\\7zFM.exe",
"arguments": "",
"workingDirectory": "VFS\\ProgramFilesX64\\7-Zip"
},
{
"id": "PSFLAUNCHERTwo",
"executable": "VFS\\ProgramFilesX64\\7-Zip\\7-zip.chm",
"arguments": "",
"workingDirectory": ""
}
],
Although Start Menu items in Windows 10 do not currently support arguments, Microsoft is considering adding them. Until then, the launcher is the only way to specify command line arguments to the target application, and this is done in the arguments field of the json configuration of our launcher.
Similarly, the Start Menu items in Windows 10 do not support specification of a working directory of the target application and will always start the app with the System32 folder as the working directory. This may be overridden in the workingDirectory field of the json configuration for our launcher. To make this work like the native lnk files, if the workingDirectory item of the json configuration is left blank, the folder that contains the ultimate target file will be used.
Although Windows 10 Start Menu items may not be files, by using PsfLauncher we can use the shell launch method to get an appropriate client side application to open the file. This is shown in the previous json for PSFLAUNCHERTWO. When the launcher sees that the executable file is not an exe file, it will look up the default program for that file type on the end-user system. It will then use a technique to perform a shell launch and force the resulting program to run inside this container, if possible. Some of the shell launch apps might be AppX based, so starting those inside this container won't be possible for those and the app will be externally started for the file instead. This might not always work, but it is the best we can do.
When the target application contains an internal or external manifest file requesting elevation (such as RequireAdministrator or HighestAvailable), the PSFLauncher must be elevated first. The PsfLauncher does not include an internal manifest, but you may add an external manifest file in the package to request that elevation. See the "About PsfLauncher and Processes needing elevation" section of PsfLauncher Developer Documentation for more information.
A 'monitor' is a program to be started by the launcher before the target program is started. The most common use of this launcher feature is to start PsfMonitor because the target process will be using PsfTraceFixup. But this monitor program may be any secondary program that you need to start. The launcher starts this program and waits a few seconds for it to initialize before starting the target app.
Here is an example of the PsfLauncher configuration for that use:
"applications": [
{
"id": "PSFLAUNCHERSixFour",
"executable": "PrimaryApp.exe",
"arguments": "/AddedArg"
"workingDirectory": "",
"monitor": {
"executable": "PsfMonitor.exe",
"arguments": "",
"asadmin": true,
}
}
],
The PsfLauncher also supports the configuration of scripts that may be run in conjunction of the target application. There are two triggers that are available to run a script, and up to one script may be run at each trigger. These events are:
- StartScript - runs prior to starting the target application.
- EndScript - runs after the target application exits.
The script to be run must be a PowerShell PS1 file, and it will be run by a PSF provided wrapper PowerShell script so that the requested PS1 script will be run inside the container.
If a start script is requested, it will begin before the target application. The script configuration may request that the application start immediately ( "wait"=false ) or it can wait for the script to complete ( "wait"=true ). If a wait is requested, a maximum wait time field, in milliseconds may be given. Note that setting the wait with a timeout of 0 means to wait for 0 milliseconds, not wait forever. If a wait is requested, there is an additional rollback field set to true means that the target application will not be started unless the script returns with a exit code of 0. There is no list for alternative exit codes.
If an end script it requested, it will begin after the target application exits. No wait is possible on this script and an error code for rollback is not supported.
Both scripts may also have arguments, and an option to show or hide the script window is also provided. While the json syntax also supports a field to specify if the script should run inside or outside the container, this field is currently ignored, and all scripts will run inside the container.
Here is an example of an application configuration that uses scripts.
"applications": [
{
"id": "Sample",
"executable": "Sample.exe",
"workingDirectory": "",
"stopOnScriptError": false,
"scriptExecutionMode": "-ExecutionPolicy Bypass",
"startScript":
{
"waitForScriptToFinish": true,
"timeout": 30000,
"runOnce": true,
"showWindow": false,
"scriptPath": "PackageStartScript.ps1",
"waitForScriptToFinish": true
"scriptArguments": "%MsixWritablePackageRoot%\\VFS\LocalAppData\\Vendor",
},
"endScript":
{
"scriptPath": "\\server\scriptshare\\RunMeAfter.ps1",
"scriptArguments": "ThisIsMe.txt"
}
}
],
It is sometimes necessary to specify file paths in the various fields of the application record that configures PsfLauncher. This can include the arguments field for the target application, argument field for the monitor, or argument field of scripts.
The two special variables are:
- %MsixPackageRoot% - which resolves to the location of the package root (typically "C:\Program Files\WindowsApps\PackageFamilyName").
- %MsixWritablePackageRoot% - which resolves to the location that the FileRedirectionFramework will redirect for copy-on-access and copy-on-write (typically "%LocalAppData%\packages\PackageFamilyName\LocalCache\Microsoft\WritablePackageRoot").