如何在 Windows Server 2019 上使用执行别名?

问题描述

我将 Win32 控制台应用程序打包到 MSIX 包中。在 Win 10 上一切正常。我也可以在 Windows Server 2019 上安装它,但无法通过调用别名或任何其他方式从控制台在那里运行它。

  1. 应用安装在C:\Program Files\WindowsApps\stackmuncher_1.1.1.0_x64__eqf80b1s88fx6
  2. C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps 中有一个它的别名作为零长度文件
  3. 如果我将可执行文件C:\Program Files\WindowsApps\stackmuncher_1.1.1.0_x64__eqf80b1s88fx6 复制到任何其他文件夹,我就可以运行该应用程序
  4. 别名显示设置 > 应用执行别名

如果我尝试通过 PS 或 CMD 终端的别名 stackmuncher.exe 运行应用程序,我会收到“未找到”消息。

我将 %userprofile%\AppData\Local\Microsoft\WindowsApps 添加到系统 Path 变量并得到不同的错误

程序“stackmuncher.exe”无法运行:指定的可执行文件不是适用于此操作系统平台的有效应用程序

该应用似乎已安装,并且它正常运行所需的所有文件都在那里。

如何使用别名或其他方式运行它?


包裹信息

PS C:\rust\stm> get-appxpackage |  Where-Object { $_.Name -like "*stackmuncher*" }

Name              : stackmuncher
Publisher         : CN=stackmuncher,C=NZ
Architecture      : X64
ResourceId        :
Version           : 1.1.1.0
PackageFullName   : stackmuncher_1.1.1.0_x64__eqf80b1s88fx6
InstallLocation   : C:\Program Files\WindowsApps\stackmuncher_1.1.1.0_x64__eqf80b1s88fx6
IsFramework       : False
PackageFamilyName : stackmuncher_eqf80b1s88fx6
PublisherId       : eqf80b1s88fx6
IsResourcePackage : False
IsBundle          : False
IsDevelopmentMode : False
NonRemovable      : False
IsPartiallyStaged : False
SignatureKind     : Developer
Status            : Ok

AppManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<Package
    xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" 
  >
  <Identity Name="stackmuncher" Version="1.1.1.0" Publisher="CN=stackmuncher,C=NZ" ProcessorArchitecture="x64" />
    <Properties>
       <displayName>stackmuncher</displayName>
       <PublisherdisplayName>stackmuncher</PublisherdisplayName>
             <Description>stackmuncher app</Description>
      <logo>150.png</logo>
    </Properties>
    <Resources>
      <Resource Language="en-us" />
    </Resources>
      <Dependencies>
        <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.15063.0" />
      </Dependencies>
      <Capabilities>
        <rescap:Capability Name="runFullTrust"/>
      </Capabilities>
    <Applications>
      <Application Id="stackmuncher" Executable="stackmuncher.exe" EntryPoint="Windows.PartialTrustApplication">
        <uap:VisualElements displayName="stackmuncher" Description="stackmuncher app"   Square150x150logo="150.png" Square44x44logo="44.png"    BackgroundColor="#999999" />
        <Extensions>
          <uap3:Extension Category="windows.appExecutionAlias" EntryPoint="Windows.FullTrustApplication" Executable="stackmuncher.exe">
            <uap3:AppExecutionAlias>
              <desktop:ExecutionAlias Alias="stackmuncher.exe"/>
            </uap3:AppExecutionAlias>
          </uap3:Extension>
        </Extensions>
      </Application>
    </Applications>
  </Package>

完整的错误信息

PS C:\> stackmuncher.exe
Program 'stackmuncher.exe' Failed to run: The specified executable is not a valid application for this OS platform.At
line:1 char:1
+ stackmuncher.exe
+ ~~~~~~~~~~~~~~~~.
At line:1 char:1
+ stackmuncher.exe
+ ~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (:) [],ApplicationFailedException
    + FullyQualifiedErrorId : NativeCommandFailed

解决方法

正如您在评论中提到的,Win Server 2019 不支持执行别名(遗憾的是)。我刚刚在尝试在使用 Windows Server 2019 的 GitHub Actions 上测试我的 MSIX 包时遇到了同样的问题。

我找到了几种运行安装包的方法。

  1. 使用 PowerShell command Invoke-CommandInDesktopPackage。您也可以调用主可执行文件。我测试了这种方法,它有效(虽然在我的机器上),但很难从代码中做到这一点,然后将其附加到目标应用程序进程。

  2. 另一种方法是使用类似的命令运行应用程序 explorer.exe shell:appsFolder\<ApplicationID>!<AppID>。这种方法描述了here with handy scripts。我还没有找到添加命令行参数的方法,所以对我来说不太好。

  3. 使用协议。它需要对应用程序进行额外的更改,但对我来说,这是最简单、最可靠的方法。因此,我按照 in this article 所述为我的应用添加了协议支持。在我的代码中,我只是添加了几行来支持这种类型的参数:

     public AppConfigBuilder AppendCommandLineArgs(string[] args)
     {
         const string protocol = "myproto:?";
    
         bool isProtocolUsage = args.Any() && args[0].StartsWith(protocol);
    
         string[] keyValueArgs = isProtocolUsage
             ? args[0][(args[0].IndexOf("?",StringComparison.Ordinal) + 1)..].Split('&')
             : args;
    
         var configuration = new ConfigurationBuilder()
             .AddCommandLine(keyValueArgs)
             .Build();
    
             ...
     }
    

基本上,我将其转换为常规参数并将其传递给 ConfigurationBuilder,后者处理得很好。