如何修复包支持框架文件系统写入权限错误

本文介绍如何使用包支持框架 (PSF) 来解决文件系统写入权限错误。

Windows 应用将特定应用程序相关目录重定向到 Windows 应用容器文件夹。 如果应用程序尝试写入 Windows 应用容器,则错误触发器,写入失败。 你可以对 Windows 应用包进行增强以解决此问题。

调查

首先,确定失败以及应用请求的目录路径。

捕获 Windows 应用失败

筛选结果是可选的,但更易于查看与应用程序相关的故障。 若要筛选结果,请创建两个筛选规则。 第一个筛选器包括应用程序进程名称,第二个筛选器包含任何未成功的结果。

  1. 下载 SysInternals 进程监视器 并将其解压缩到 C:\PSF\ProcessMonitor 目录。

  2. 打开 Windows 资源管理器并导航到提取的 SysInternals ProcessMonitor 文件夹。

  3. 选择 SysInternals 进程监视器 procmon.exe 文件以启动应用。

  4. 如果 UAC 提示,请选择“ ”。

  5. “进程监视器筛选器” 窗口中,从第一个字段的下拉菜单中选择 “进程名称 ”。

  6. 验证 是否 显示在下一个字段中。

  7. 在下一个字段中,输入应用的进程名称,例如 PSFSample.exe

    Example of the Process Monitor Filter window with app name.

  8. 选择 添加

  9. “进程监视器筛选器” 窗口中,从第一个字段的下拉菜单中选择 “结果 ”。

  10. 在下一个字段中,选择 不是 从下拉菜单中选择。

  11. 在文本字段中,输入 SUCCESS

    Example of the Process Monitor Filter window with Result.

  12. 依次选择“添加”、“确定” 。

  13. 启动 Windows 应用,触发错误,然后关闭 Windows 应用。

查看 Windows 应用故障日志

捕获 Windows 应用进程后,调查结果以确定失败是否与工作目录相关。

查看 SysInternals 进程监视器失败结果。 如果结果包括 拒绝访问,且 具有 Desired Access:Generic Write 详细信息,则针对面向 C:\Program Files\WindowsApps\...\的应用,你已识别出与工作目录相关的写入权限失败。

Displays the error message witnessed in the SysInternals Process Monitor for failure to write to directory.

如果识别此错误,请对应用应用以下 PSF 更正。

解决方法

若要解决 Windows 应用无法写入 Windows 应用容器的问题,请执行以下步骤:

  1. 将 Windows 应用的内容提取到 本地暂存目录
  2. 创建 config.json 并将 PSF 修复文件注入 到暂存的 Windows 应用目录中。
  3. 将应用程序启动器配置为指向 PSF 启动器,并将 PSF config.json 文件配置为重定向 PSF 启动器,并指定工作目录。
  4. 更新 Windows 应用 AppxManifest 文件
  5. 重新打包并对 Windows 应用进行签名

下载并安装所需的工具

此过程需要以下工具:

  • NuGet 客户端工具
  • 包支持框架 (PSF)
  • Windows 10 软件开发工具包 (Win 10 SDK) 最新版本
  • SysInternals 进程监视器

下载并安装 NuGet 和 PSF:

  1. 下载 NuGet 客户端工具的最新非预览版本,并在 C:\PSF\nuget 中保存nuget.exe

  2. 通过从管理 PowerShell 窗口运行以下命令,下载并安装 NuGet 包支持框架:

    Set-Location "C:\PSF"
    .\nuget\nuget.exe install Microsoft.PackageSupportFramework
    

下载并安装 Windows 10 SDK:

  1. 下载 Win 10 SDK
  2. 运行 winsdksetup.exe
  3. 选择“下一页”。
  4. 仅选择以下三个功能:
    • 适用于桌面应用的 Windows SDK 签名工具
    • 适用于 UWP C++ 应用的 Windows SDK
    • 适用于 UWP 应用的 Windwos SDK 本地化
  5. 选择 “安装”,然后选择“ 确定”。

暂存 Windows 应用

暂存 Windows 应用会将应用的内容解压缩并解压缩到本地目录。 将 Windows 应用解压缩到过渡位置后,可以注入 PSF 修复文件以更正任何不需要的体验。

  1. 在管理 PowerShell 窗口中,将以下变量设置为面向特定应用文件和 Windows 10 SDK 版本:

    $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
    
  2. 通过运行以下 PowerShell cmdlet 将 Windows 应用解压缩到过渡文件夹:

    ## 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"
    

创建并注入所需的 PSF 文件

若要更正 Windows 应用,请创建一个 config.json 文件,其中包含有关失败的 Windows 应用启动器的信息。 如果多个 Windows 应用启动器遇到问题,则可以使用多个条目配置 config.json 文件。

创建 config.json 文件后,将 config.json 和支持 PSF 修复文件移动到 Windows 应用包的根目录中。

  1. 打开 Visual Studio Code 或其他文本编辑器。

  2. 在 Windows 应用暂存目录 C:\PSF\Staging\PSFSampleApp 中创建名为 config.json 的新文件。

  3. 将以下代码复制到新创建的 config.json 文件。

    {
        "applications": [
            {
                "id": "",
                "executable": ""
            }
        ],
        "processes": [
            {
                "executable": "",
                "fixups": [
                {
                    "dll": "",
                    "config": {
                        "redirectedPaths": {
                            "packageRelative": [
                                {
                                    "base": "",
                                    "patterns": [
                                        ""
                                    ]
                                }
                            ]
                        }
                    }
                }
            ]
            }
        ]
    }
    
  4. 在 Windows 应用暂存文件夹中打开 AppxManifest.xml 文件。 以下示例显示了 一个AppxManifest.xml 文件:

    <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>
    
  5. config.json 文件中进行以下更改:

    • applications.id 值设置为与 Applications.Application.IDAppxManifest.xml 文件中字段中的值相同。

      Image showing the location of the ID within the AppxManifest file.

    • applications.executable 值设置为目标到位于 Applications.Application.ExecutableAppxManifest.xml 文件的字段中的应用程序的相对路径。

      Image showing the location of the executable within the *AppxManifest.xml* file.

    • 设置applications.workingdirectory该值以AppxManifest.xml文件中的相对文件夹路径Applications.Application.Executable为目标。

      Image showing the location of the working directory within the AppxManifest file.

    • AppxManifest.xml文件的字段中,将process.executable值设置为以文件名为目标(不带路径和扩展名)。Applications.Application.Executable

      Image showing the location of the process executable within the AppxManifest file.

    • processes.fixups.dll 值设置为面向特定于 FileRedirectionFixup.dll体系结构的值。 如果更正适用于 x64 体系结构,请将该值 FileRedirectionFixup64.dll设置为 。 如果体系结构为 x86 或未知,请将该值设置为 FileRedirectionFixup86.dll

    • processes.fixups.config.redirectedPaths.packageRelative.base值设置为AppxManifest.xml文件中字段的包相对文件夹路径Applications.Application.Executable

      Image showing the location of the working directory within the AppxManifest file.

    • processes.fixups.config.redirectedPaths.packageRelative.patterns设置值以匹配应用程序创建的文件类型。 如果使用 .*\\.log,PSF 会将目录和子目录中的所有日志文件写入 processes.fixups.config.redirectedPaths.packageRelative.base 重定向。

  6. 保存更新后的 config.json 文件。 以下示例显示了更新 后的 config.json 文件:

    {
        "applications": [
            {
            "id": "PSFSample",
            "executable": "VFS/ProgramFilesX64/PS Sample App/PSFSample.exe"
            }
        ],
        "processes": [
            {
                "executable": "PSFSample",
                "fixups": [
                    {
                        "dll": "FileRedirectionFixup64.dll",
                        "config": {
                            "redirectedPaths": {
                                "packageRelative": [
                                    {
                                        "base": "VFS/ProgramFilesX64/PS Sample App/",
                                        "patterns": [
                                            ".*\\.log"
                                        ]
                                    }
                                ]
                            }
                        }
                    }
                ]
            }
        ]
    }
    
  7. 将以下文件从应用程序可执行体系结构的包支持框架复制到暂存 Windows 应用的根目录。 可以在 .\Microsoft.PackageSupportFramework.\Version>\<bin 中找到文件。

    应用程序 (x64) 应用程序 (x86)
    PSFLauncher64.exe PSFLauncher32.exe
    PSFRuntime64.dll PSFRuntime32.dll
    PSFRunDll64.exe PSFRunDll32.exe
    FileRedirectionFixup64.dll FileRedirectionFixup64.dll

更新 AppxManifest

创建和更新 config.json 文件后,请更新 config.json 中包含的每个 Windows 应用启动器 Windows 应用的AppxManifest.xml文件。 现在,ApplicationsAppxManifest.xml必须面向与应用程序体系结构关联的PSFLauncher.exe

  1. 在暂存的 MSIX 应用文件夹中打开 AppxManifest.xmlC:\PSF\Staging\PSFSampleApp
  2. 使用以下代码更新 AppxManifest.xml
    <Package ...>
    ...
    <Applications>
        <Application Id="PSFSample"
                    Executable="PSFLauncher32.exe"
                    EntryPoint="Windows.FullTrustApplication">
        ...
        </Application>
    </Applications>
    </Package>
    

重新打包应用程序

应用所有更正后,将 Windows 应用重新打包到 MSIX 中,并使用代码签名证书对其进行签名。

  1. 打开管理 PowerShell 窗口。

  2. 设置以下变量:

    $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. 通过运行以下 PowerShell cmdlet 从暂存文件夹重新打包 Windows 应用:

    Set-Location "${env:ProgramFiles(x86)}\Windows Kits\10\Bin\$Win10SDKVersion\$OSArchitecture"
    .\makeappx.exe pack /p "$AppPath" /d "$StagingFolder"
    
  4. 通过运行以下 PowerShell cmdlet 对 Windows 应用进行签名:

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