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

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

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

调查

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

捕获 Windows 应用错误

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

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

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

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

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

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

  6. 验证 is 是否出现在下一个字段中。

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

    应用名称为“进程监视器筛选器”窗口的示例。

  8. 选择 “添加”。

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

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

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

    “进程监视器筛选器”窗口的示例,其中包含结果。

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

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

查看 Windows 应用失败日志

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

查看 SysInternals 进程监视器的故障结果。 如果结果包括 访问被拒绝,且 具有‘预期访问:通用写入’详细信息,对于面向 C:\Program Files\WindowsApps\...\ 的应用程序,您已发现与工作目录相关的写入权限失败问题。

显示在 SysInternals 进程监视器中看到的无法写入目录的错误消息。

如果确定此错误,请对应用应用以下 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.ID 文件中字段中的值相同。

      一幅图像,显示 AppxManifest 文件中 ID 的位置。

    • applications.executable 值设置为指向位于 Applications.Application.Executable 文件的 字段中应用程序的相对路径。

      显示可执行文件在 *AppxManifest.xml* 文件中的位置的图像。

    • 设置applications.workingdirectory值以定位Applications.Application.Executable文件中字段的相对文件夹路径。

      显示 AppxManifest 文件中工作目录的位置的图像。

    • process.executable 文件的 Applications.Application.Executable 字段中,将 值设置为仅目标文件名,不包括路径和扩展名。

      图像显示了 AppxManifest 文件中可执行的过程的位置。

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

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

      显示 AppxManifest 文件中工作目录的位置的图像。

    • 设置值 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 应用启动器的 AppxManifest.xml 文件。 AppxManifest.xmlApplications 现在必须面向与应用程序体系结构关联的 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