Edit

Share via


Package Support Framework - Working Directory fixup

Investigation

Windows apps will redirect specific directories that are related to the application to the C:\Program Files\WindowsApps folder. If an application creates a subfolder (C:\Program Files\Vendor\subfolder) as part of the installation, and later calls this subfolder, it will fail to find the directory as it does not exist.

Using the Package Support Framework (PSF), enhancements can be made to the Windows app package to resolve this issue. First, we must identify the failure, and directory paths that are being requested by the app.

Capture the Windows app failure

Filtering the results is an optional step, that will make viewing application related failures easier. To do this, we will create two filter rules. The first an include filter for the application process name, and the second is an inclusion of any results that are not successful.

  1. Download and extract the SysInternals Process Monitor to the C:\PSF\ProcessMonitor directory.
  2. Open Windows Explorer and navigate to the extracted SysInternals Process Monitor Folder
  3. Double-click the SysInternals Process Monitor (procmon.exe) file, launching the app.
  4. If prompted by UAC, select the Yes button.
  5. In the Process Monitor Filter Window, select the first drop-down menu labeled with Architecture.
  6. Select Process Name from the drop-down menu.
  7. In the next drop-down menu, verify that it is set with the value of is.
  8. In the text field type the process name of your App (Example: PSFSample.exe). Example of the Process Monitor Filter Windows with App Name
  9. Select the Add button.
  10. In the Process Monitor Filter Window, select the first drop-down menu labeled Process Name.
  11. Select Result from the drop-down menu.
  12. In the next drop-down menu, select it, and select is not from the drop-down menu.
  13. In the text field type: SUCCESS. Example of the Process Monitor Filter Windows with Result
  14. Select the Add button.
  15. Select the Ok button.
  16. launch the Windows app, trigger the error, and close the Windows app.

Review the Windows app failure logs

After capturing the Windows app processes, the results will need to be investigated to identify if the failure is related to the working directory.

  1. Review the SysInternals Process Monitor results, searching for failures outlined in the above table.
  2. If the results show an "Name Not Found" result, with the details "Desired Access: ..." for your specific app targeting a directory outside of the "C:\Program Files\WindowsApps\...\" (as seen in the below image), then you have successfully identified a failure related with the working directory, use the PSF Support - Filesystem Access article for guidance on how to apply the PSF correction to your app. Displays the error message witnessed in the SysInternals Process Monitor for failure to write to directory.

Resolution

Windows apps will redirect specific directories that are related to the application to the C:\Program Files\WindowsApps folder. If an application creates a subfolder (C:\Program Files\Vendor\subfolder) as part of the installation, and later calls this subfolder, it will fail to find the directory as it does not exist.

To resolve the issue related to the Windows app referencing an incorrect Working Directory, we must follow the following four steps:

  1. Stage the Windows app to a local directory
  2. Create the Config.json and inject required PSF Files
  3. Update the Windows app AppxManifest file
  4. Repackage and sign the Windows app

The above steps provide guidance through extracting the content of the Windows app to a local staged directory, injecting the PSF fixup files into the staged Windows app directory, configuring the Application Launcher to point to the PSF launcher, then configuring the PSF config.json file to redirect the PSF launcher to the app specifying the working directory.

Download and Install Required Tools

This process will guide you through the retrieval of, and usage of the following tools:

  • NuGet Client Tool
  • Package Support Framework
  • Windows 10 SDK (latest version)
  • SysInternals Process Monitor

The following will provide step-by-step guidance on downloading and installing the required tools.

  1. Download the latest (non-preview) version of the NuGet client tool, and save the nuget.exe in the C:\PSF\nuget folder.

  2. Download the Package Support Framework using Nuget by running the following from an Administrative PowerShell window:

    Set-Location "C:\PSF"
    .\nuget\nuget.exe install Microsoft.PackageSupportFramework
    
  3. Download and install the Windows 10 Software Development Toolkit (Win 10 SDK).

    1. Download the Win 10 SDK.
    2. Run the winsdksetup.exe that was downloaded in the previous step.
    3. Select the Next button.
    4. Select only the following three features for install:
      • Windows SDK Signing Tools for Desktop Apps
      • Windows SDK for UWP C++ Apps
      • Windwos SDK for UWP Apps Localization
    5. Select the Install button.
    6. Select the Ok button.

Stage the Windows app

By staging the Windows app, we will be extracting/unpackaging the contents of the Windows app to a local directory. Once the Windows app has been unpacked to the staging location, PSF fixup files can be injected correcting any unwanted experiences.

  1. Open an Administrative PowerShell window.

  2. Set the following variables targeting your specific app file, and Windows 10 SDK version:

    $AppPath          = "C:\PSF\SourceApp\PSFSampleApp.msix"         ## Path to the MSIX App Installer
    $StagingFolder    = "C:\PSF\Staging\PSFSampleApp"                ## Path to where the MSIX App will be staged
    $OSArchitecture   = "x$((gwmi Win32_Processor).AddressWidth)"    ## Operating System Architecture
    $Win10SDKVersion  = "10.0.19041.0"                               ## Latest version of the Win10 SDK
    
  3. Unpack the Windows app to the staging folder by running the following PowerShell cmdlet:

    ## Sets the directory to the Windows 10 SDK
    Set-Location "${env:ProgramFiles(x86)}\Windows Kits\10\Bin\$Win10SDKVersion\$OSArchitecture"
    
    ## Unpackages the Windows app to the staging folder
    .\makeappx.exe unpack /p "$AppPath" /d "$StagingFolder"
    

Create and inject required PSF Files

To apply corrective actions to the Windows app, you must create a config.json file, and supply it with information about the Windows app launcher that's failing. If there are multiple Windows app launchers that are experiencing issues, then the config.json file can be updated with multiple entries.

After updating the config.json file, the config.json file and supporting PSF fixup files must then be moved into the root of the Windows app package.

  1. Open Visual Studio Code (VS Code), or any other text editor.

  2. Create a new file, by selecting the File menu at the top of the VS Code, selecting New File from the drop-down menu.

  3. Save the file as config.json, by select the File menu at the top of the VS Code window, selecting Save from the drop-down menu. In the Save As window, navigate to the Windows app staging directory (C:\PSF\Staging\PSFSampleApp) and set the File Name as config.json. Select the Save button.

  4. Copy the following code to the newly created config.json file.

    {
        "applications": [
            {
                "id": "",
                "executable": "",
                "workingDirectory": ""
            }
        ],
        "processes": [
            {
                "executable": ""
            }
        ]
    }
    
  5. Open the staged Windows app AppxManifest file located in the Windows app staging folder (C:\PSF\Staging\PSFSampleApp\AppxManifest.xml) using VS Code, or another text editor.

    <Applications>
        <Application Id="PSFSAMPLE" Executable="VFS\ProgramFilesX64\PS Sample App\PSFSample.exe" EntryPoint="Windows.FullTrustApplication">
        <uap:VisualElements BackgroundColor="transparent" DisplayName="PSFSample" Square150x150Logo="Assets\StoreLogo.png" Square44x44Logo="Assets\StoreLogo.png" Description="PSFSample">
            <uap:DefaultTile Wide310x150Logo="Assets\StoreLogo.png" Square310x310Logo="Assets\StoreLogo.png" Square71x71Logo="Assets\StoreLogo.png" />
        </uap:VisualElements>
        </Application>
    </Applications>
    
  6. Copy the value in the ID field located in the AppxManifest.xml file located in Package.Applications.Application to the Applications ID field in the config.json file. Image circling the location of the ID within the AppxManifest file.

  7. Copy the package-relative path from the Executable field located in the AppxManifest.xml file located in Package.Applications.Application to the Applications Executable field in the config.json file. Image circling the location of the executable within the AppxManifest file.

  8. Copy the package-relative parent path from the Executable field located in the AppxManifest.xml file located in Package.Applications.Application to the Applications WorkingDirectory field in the config.json file. Image circling the location of the working directory within the AppxManifest file.

  9. Copy the executable name from the Executable field located in the AppxManifest.xml file located in Package.Applications.Application to the Processes Executable field in the config.json file. Image circling the location of the process executable within the AppxManifest file.

  10. Save the updated config.json file.

    {
        "applications": [
            {
            "id": "PSFSample",
            "executable": "VFS/ProgramFilesX64/PS Sample App/PSFSample.exe",
            "workingDirectory": "VFS/ProgramFilesX64/PS Sample App/"
            }
        ],
        "processes": [
            {
            "executable": "PSFSample"
            }
        ]
    }
    
  11. Copy the following three files from the Package Support Framework based on the application executable architecture to the root of the staged Windows app. The following files are located within the .\Microsoft.PackageSupportFramework.<Version>\bin.

    Application (x64) Application (x86)
    PSFLauncher64.exe PSFLauncher32.exe
    PSFRuntime64.dll PSFRuntime32.dll
    PSFRunDll64.exe PSFRunDll32.exe

Update AppxManifest

After creating and updating the config.json file, the Windows app's AppxManifest.xml must be updated for each Windows app launcher that was included in the config.json. The AppxManifest's Applications must now target the PSFLauncher.exe associated with the applications architecture.

  1. Open File Explorer, and navigate to the Staged MSIX App folder (C:\PSF\Staging\PSFSampleApp).

  2. Right-click on AppxManifest.xml, and select Open with Code from the drop-down menu (Optionally, you can open with another text editor).

  3. Update the AppxManifest.xml file with the following information:

    <Package ...>
    ...
    <Applications>
        <Application Id="PSFSample"
                    Executable="PSFLauncher32.exe"
                    EntryPoint="Windows.FullTrustApplication">
        ...
        </Application>
    </Applications>
    </Package>
    

Re-package the application

All of the corrections have been applied, now the Windows app can be re-packaged into an MSIX, and signed using a code signing certificate.

  1. Open an Administrative PowerShell Window.

  2. Set the following variables:

    $AppPath          = "C:\PSF\SourceApp\PSFSampleApp_Updated.msix" ## Path to the MSIX App Installer
    $CodeSigningCert  = "C:\PSF\Cert\CodeSigningCertificate.pfx"     ## Path to your code signing certificate
    $CodeSigningPass  = "<Password>"                                 ## Password used by the code signing certificate
    $StagingFolder    = "C:\PSF\Staging\PSFSampleApp"                ## Path to where the MSIX App will be staged
    $OSArchitecture   = "x$((gwmi Win32_Processor).AddressWidth)"    ## Operating System Architecture
    $Win10SDKVersion  = "10.0.19041.0"                               ## Latest version of the Win10 SDK
    
  3. Repack the Windows app from the staging folder by running the following PowerShell cmdlet:

    Set-Location "${env:ProgramFiles(x86)}\Windows Kits\10\Bin\$Win10SDKVersion\$OSArchitecture"
    .\makeappx.exe pack /p "$AppPath" /d "$StagingFolder"
    
  4. Sign the Windows app by running the following PowerShell cmdlet:

    Set-Location "${env:ProgramFiles(x86)}\Windows Kits\10\Bin\$Win10SDKVersion\$OSArchitecture"
    .\signtool.exe sign /v /fd sha256 /f $CodeSigningCert /p $CodeSigningPass $AppPath