Executing custom commands in MSIX context

Sometimes, for troubleshooting it may be necessary to invoke commands in the context of MSIX, so that all virtualized file and registry resources are available. There are three main use cases for it:

  1. Testing out whether the files and registry entries are visible inside the virtual package in the correct place as defined in the AppxManifest.xml.
  2. Testing out whether Modification Package correctly merges its VFS and virtual registry with the base package.
  3. Executing your app from the MSIX package with custom executables and/or parameters which are not necessarily exposed as entry points.

There exists a really useful PowerShell cmdlet which does the heavy lifting, the only thing the user has to do is to supply the right parameters. Its signature (from MSDN):

      [-PackageFamilyName] <String>
      [-AppId] <String>
      [-Command] <String>
      [[-Args] <String>]

Both PackageFamilyName and AppId are required, as well as the command to be executed. You can get the two values from another cmdlet Get-AppxPackage.

The command that is started in the “bubble” can be pretty much anything (it is validated before running), but some typical examples are:

  • cmd.exe
  • powershell.exe
  • regedit.exe
  • Executables being part of the package (indirectly)

For example, let’s execute a PowerShell session in MSIX container to verify the virtualized file structure.

First, get the package you need, for example:

$msix = Get-AppxPackage | ? { $_.Name -match "RayEval" } | Select -First 1

This outputs the following:

PS C:\Users\m.otorowski> $msix
Name              : RayEval
Publisher         : CN=RaynetGmbH
Architecture      : Neutral
ResourceId        :
Version           : 4.0.736.52
PackageFullName   : RayEval_4.0.736.52_neutral__7k4crt5chdnyp
InstallLocation   : C:\Program Files\WindowsApps\RayEval_4.0.736.52_neutral__7k4crt5chdnyp
IsFramework       : False
PackageFamilyName : RayEval_7k4crt5chdnyp
PublisherId       : 7k4crt5chdnyp
IsResourcePackage : False
IsBundle          : False
IsDevelopmentMode : False
NonRemovable      : False
Dependencies      : {RayEvalModificationPackage_1.0.0.0_neutral__7k4crt5chdnyp}
IsPartiallyStaged : False
SignatureKind     : Developer
Status            : Ok

The value of property Name is the actual AppId, PackageFamilyName is self-explaining. Once you take these two values, executing a PowerShell.exe inside the container is trivial:

Invoke-CommandInDesktopPackage "powershell.exe" -PackageFamilyName $msix.PackageFamilyName -AppId $msix.Name -PreventBreakaway

Inside the newly spawned window, you can navigate to Program Files or any other virtualized folder and verify, that the files from the MSIX package are visible from there:

Top window showing the results of DIR command inside a usual PowerShell session. The bottom window is the result of invoking a command inside the MSIX package context – the content of VFS is now visible!

You can also confirm that both PowerShell and RayEval are grouped together in the Task Manager window:

Grouped processes in Task Manager.

The switch –PreventBreakAway makes the entire process tree stay in the package context.

The same works for modification packages, with only difference that you always target the family name and the application ID from the base package.

In case you ask yourself – there is a good reason I used PowerShell to list the directory content, and not explorer.exe. It seems that explorer window kind of breaks away from the bubble and is currently unable to work properly.

Further points

The command parameter does not support commands/files not available on the system (for example being part of the package). If we try to execute a file which exists only in an MSIX package like C:\Program Files (x86)\RayEval\RayEval.exe we will get an exception. In order to workaround this, instead of using a direct command, start the process via proxy, for example by invoking cmd.exe with parameters /c <command_to_execute>. Essentially, we dispatch looking up for a file to a later point of time where we should already be in the right context. Sample call:

Invoke-CommandInDesktopPackage "cmd" -Args "/c "c:\program files (x86)\rayeval\rayeval.exe" -PackageFamilyName $msix.PackageFamilyName -AppId $msix.Name -PreventBreakaway

This also shows how to use an optional parameters -Args to pass a custom command line to the executable being started. As a side effect, a console window will be shown in the background, but it doesn’t make any difference for troubleshooting needs.

Links and resources

Leave a Reply