使用PowerShell启动Metro风格应用程序

9

我正在尝试编写一个适用于Windows 10的PowerShell脚本,可以自动启动Metro风格应用程序。

Start-Process命令似乎可以起到作用,但是如果我不提供.exe的路径,它就无法启动任何东西。

例如,以下输入有效:

    Start-Process 'C:\Program Files\Internet Explorer\iexplore.exe'

很遗憾,Metro风格的应用程序没有可执行文件。我需要使用哪个文件来启动它们? 例如,如果我想启动Windows Store,我该怎么做?
谢谢
9个回答

13

存储应用只能由 shell 启动。请尝试以下操作:

explorer.exe shell:AppsFolder\Microsoft.WindowsAlarms_8wekyb3d8bbwe!App

此外,您可以使用以下方法启动自己的UWP应用程序:explorer.exe shell:AppsFolder\18b72f48-axxx-xxxx-xxxx-903bd872921a_h65w5j3hw1x76!App - Yasser Asmi
不错,尽管这可能会让你更灵活地直接传递“shell:”URI到“Start-Process”中:Start-Process shell:AppsFolder\Microsoft.WindowsAlarms_8wekyb3d8bbwe!App。鉴于需要知道包系列名称,其中包括抽象发布者ID(8wekyb3d8bbwe)- GetAppXPackage可以帮助发现。然而,如果可能的话,通过它们特定的URI协议方案启动UWP应用程序通常更容易;在这种情况下:Start-Process ms-clock: - mklement0

4

现有回答中有一些有用的信息,但让我试着将这些信息整合在一起,同时提供自动化的步骤。
本回答假设存在特定于应用程序的URI协议。 如果对于给定的应用程序不存在此类协议,请使用接受的答案中显示的shell: URI方案来调用它(直接将此类URI传递给Start-Process即可;例如:
Start-Process shell:AppsFolder\Microsoft.WindowsAlarms_8wekyb3d8bbwe!App)。请注意,您需要知道应用程序系列名称,其中包括抽象出版商ID(8wekyb3d8bbwe);
Get-AppXPackage可以帮助您进行发现 - 请参见下面的内容。

Windows 8+Metro风格的应用程序(过时的术语)也称为UWP应用程序 / AppX软件包 / Microsoft Store应用程序,最好使用应用程序特定的协议方案的URL进行启动:

例如,Windows 10的计算器应用程序定义了两个URL协议名,calculatorms-calculator,这两者都可以在使用带有:Start-Process时使用:

# Note the trailing ":"
Start-Process calculator: # Or: Start-Process ms-calculator:

Microsoft Edge支持多种协议,其中包括microsoft-edge,因此您可以按照以下方式在Edge中打开给定的URL(例如http://example.org):

Start-Process microsoft-edge:http://example.org

请注意,在此示例中,协议名称后的:后跟一个要传递给目标应用程序的参数警告:截至PowerShell(Core)7.2版本,许多AppX应用程序无法使用-Wait-PassThru参数启动,请参见GitHub问题#10996挑战在于如何通过应用程序名称(包名称)发现给定应用程序的协议名称。 以下部分讨论了可以在注册表中找到此信息的位置,并定义了辅助函数GetAppXUriProtocol,该函数自动完成此发现,允许您针对应用程序使用通配符表达式,如果不知道确切的包名称(这是典型的情况)。
例如,您可以按如下方式找到计算器应用程序的协议名称:
# Find the protocol names supported by the Calculator application,
# by wildcard expression rather than full package name.
PS> Get-AppXUriProtocol *calculator*

PackageFullName                                            Protocols
---------------                                            ---------
Microsoft.WindowsCalculator_10.1908.0.0_x64__8wekyb3d8bbwe {calculator, ms-calculator}

那就是说,你可以使用Start-Process calculator:或者Start-Process ms-calculator:来启动计算器应用程序。

如果您只想获取有关AppX包的信息 - 不包括协议名称 - 请使用标准的Get-AppXPackage cmdlet,例如:

PS> Get-AppXPackage *calculator*
Name              : Microsoft.WindowsCalculator
Publisher         : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
...

发现AppX应用程序的URL协议名称:

注册表位置HKEY_CLASSES_ROOT\Extensions\ContractId\Windows.Protocol\PackageId有以已安装的AppX包命名的子键,它们在ActivatableClassId\*\CustomProperties子键的Name值中指定它们支持的URL协议名称。

以下函数Get-AppXUriProtocol通过Get-AppXPackage cmdlet和注册表查找检索与给定AppX应用程序相关联的协议名称。

该函数支持通配符表达式,因此您可以按照包名称(例如应用程序的常见名称)的一部分进行搜索;例如:
Get-AppXUriProtocol *calc*

Get-AppXUriProtocol源代码:

function Get-AppXUriProtocol {
<#
.SYNOPSIS
Gets the URI protocol names assocated with AppX packages on Windows 8 and above.

.DESCRIPTION
Given AppX package names or wildcard expressions, retrieves all associated
URI protocol names that can be used to launch these applications.

AppX is the package format for UWP applications typically distributed via
the Microsoft Store.

For instance, the protocol names associated with the Windows 10 Calculator
application are 'calculator' and 'ms-calculator', so you can use
Start-Process calculator: (note the appended ":") to launch it.

.PARAMETER PackageName
One or more package family names, full package names, or wildcard expresssions
matching either. 

.EXAMPLE
Get-AppXUriProtocol *calculator*

Outputs a [pscustomobject] instance such as the following:

PackageFullName                                            Protocols
---------------                                            ---------
Microsoft.WindowsCalculator_10.1908.0.0_x64__8wekyb3d8bbwe {calculator, ms-calculator}

#>
  [CmdletBinding(PositionalBinding = $false)]
  [OutputType([pscustomobject])]
  param (
    [Parameter(Mandatory, Position = 0)]
    [SupportsWildcards()]
    [string[]] $PackageName
  )
    
  begin {
    if ($env:OS -ne 'Windows_NT') { Throw "This command is supported on Windows only." }
  }

  process {
    # !! Even though Get-AppXPackage allegedly accepts -Name values from the pipeline
    # !! that doesn't work in practice.
    $packages = foreach ($name in $PackageName) { Get-AppXPackage -Name $name }
    foreach ($package in $packages) {
      $protocolSchemes = (Get-ChildItem registry::HKEY_CLASSES_ROOT\Extensions\ContractId\Windows.Protocol\PackageId\$($package.PackageFullName)\ActivatableClassId\*\CustomProperties).ForEach('GetValue', 'Name')
      [pscustomobject] @{ 
        PackageFullName = $package.PackageFullName
        Protocols       = $protocolSchemes
      }
    }
  }

}

4
您可以通过在注册表中导航到此处找到要使用的命令:Computer\HKEY_CLASSES_ROOT\Extensions\ContractId\Windows.Protocol\PackageId。
然后展开ActivatableClassId,然后展开应用程序,在CustomProperties文件夹中查看Name的值。
必须使用PowerShell运行Start-Process,因为CMD无法识别它。
我使用这个命令启动Windows Mail应用程序。

4

如果 appx 注册了 URI 协议方案,您可以使用它来启动它。例如,在 Win8/Win10 中启动 Windows Store,使用以下代码:

    Start-Process ms-windows-store:

我很惊讶发现关于启动Metro风格应用的文档很少。

This command cannot be run due to the error: The system cannot find the file specified. - Sam I am says Reinstate Monica
1
根据 Get-AppxPackage,Windows Store 的名称是 "Microsoft.WindowsStore",你从哪里找到了 "ms-windows-store" 作为名称? - Luke
5
这不是一个名称,而是已注册的协议。(例如在http中)只有一些Appx可以用这种方式打开。 - papo
1
@Luke:诸如ms-windows-store之类的协议名称在注册表中定义为HKEY_CLASSES_ROOT\Extensions\ContractId\Windows.Protocol\PackageId的子键中 - 有关详细信息,请参见我的答案 - mklement0

2

如果你是因为WindowsTerminal而来到这里的,我为我的个人资料编写了此功能,以便我可以在不移动手指的情况下提升权限:

Original Answer翻译成"最初的回答"

function term {
    $pkgName = (Get-AppxPackage -Name Microsoft.WindowsTerminal).PackageFamilyName
    $Proc = @{
        FilePath = 'explorer.exe'
        ArgumentList = "shell:AppsFolder\$pkgName!App"
        Verb = 'RunAs'
    }
    Start-Process @proc
}

不错,但是你不需要使用 -FilePath explorer.exe;相反,直接使用 -FilePath "shell:AppsFolder\$pkgName!App" - mklement0

1
如果您下载了Windows SDK,那里面有一个可执行文件叫做:microsoft.windows.softwarelogo.appxlauncher.exe,可以用来启动UWP应用程序。
格式为:microsoft.windows.softwarelogo.appxlauncher.exe <packageFamilyName>!App 您可以通过查看kayleeFrye_OnDeck的答案来获取您的应用程序的packageFamilyName。

0

我不知道有什么真正通用的方法,但你可以通过一些中间检查来解决。

注意:我讨厌使用 PowerShell,所以请原谅从 CMD 中调用 PS 东西的怪异行为。

步骤1:找出你拥有哪些应用程序。

powershell Get-AppXPackage 将生成所有应用程序的列表。假设你特别想启动桌面应用程序转换器,这样你就可以在利用自动化进行一些 Centennial 补丁处理时处理它们。所以我将针对 AppX 列表查询一些可能匹配的内容,并使用 findstr 进行过滤。

步骤2:确定你是否已经拥有你想要的应用程序

powershell Get-AppXPackage | findstr /i Desktop

虽然这给了我很多结果,但我可以清楚地看到返回的一组匹配项:

Name              : Microsoft.DesktopAppConverter
PackageFullName   : Microsoft.DesktopAppConverter_2.1.1.0_x64__8wekyb3d8bbwe
InstallLocation   : C:\Program Files\WindowsApps\Microsoft.DesktopAppConverter_2.1.1.0_x64__8wekyb3d8bbwe
PackageFamilyName : Microsoft.DesktopAppConverter_8wekyb3d8bbwe

如果我没有得到任何像这样的返回,自然的下一步就是去找到该死的东西:) 所以对于下一步,这可能会变得棘手,你的效果可能会有所不同:

第三步:找到应用程序存在的位置,您可以实际调用它: 为什么要这样做?因为如果我尝试从AppXPackage查询返回的路径运行它,我会得到“拒绝访问”。

where DesktopAppConverter

C:\Users\user name\AppData\Local\Microsoft\WindowsApps\DesktopAppConverter.exe 

然后您应该能够获取该结果路径并从那里运行它。


2
不错,但是 Get-AppXPackage 直接支持通配符表达式作为包名,所以你可以使用 Get-AppXPackage *Desktop*。查找文件路径实际上并不那么有用,因为你无法通过这种方式启动 AppX 应用程序 - 而应该使用 URL 方案。 - mklement0
谢谢你提醒我关于 Get-AppXPackage :) 我认为这个答案已经过时了。被接受的答案似乎表明,知道路径曾经是在命令行启动它们的唯一方法。我IRC记得 URL 方案只有在开发者通过手动包含支持它而不是自动支持它时才起作用,但最近几年可能已经改变了。我确实记得我们需要在清单文件中设置所需的 URL 方案名称,而不是它可以自动开箱即用。 - kayleeFrye_onDeck
1
谢谢 - 没有考虑到 URI 协议名称可能不是强制性的 / 支持开箱即用。 接受的答案实际上并没有使用路径,而是使用 shell: 协议方案(尽管您不一定需要文件资源管理器,直接将这样的 URI 传递给 Start-Process 就可以了;例如,Start-Process shell:AppsFolder\Microsoft.WindowsAlarms_8wekyb3d8bbwe!App)。 对于没有自己的 URL 协议的应用程序,这种晦涩的方式真的是唯一调用它们的方法吗?请注意,您需要知道应用程序系列名称,其中包括抽象发布者 ID (8wekyb3d8bbwe)。 - mklement0
1
我不确定这是现在唯一的方法,但它似乎仍然有效。例如,我可以通过直接调用该目录中的可执行文件("C:\Users\user name\AppData\Local\Microsoft\WindowsApps\AppleInc.iTunes_nzyj5cx40ttqa\iTunes.exe")来启动iTunes商店应用程序,但这带有一个关于默认权限的巨大警告; 如果我没记错的话,即使是管理员也需要手动修改权限才能访问WindowsApps目录。我不记得需要更改权限才能使用此问题的已接受答案来适用于应用程序。 - kayleeFrye_onDeck

0

据称Metro风格的“应用商店”应用程序没有传统的可执行文件,所以我开始深入挖掘,结果发现它们确实有。从一个老派的管理员cmd.exe尝试:

 dir "%ProgramW6432%\WindowsApps"
 dir "%ProgramW6432%\WindowsApps\Microsoft.WindowsCalculator_10.1903.21.0_x64__8wekyb3d8bbwe"      Directory of C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1903.21.0_x64__8wekyb3d8bbwe

 04/30/2019  05:58 PM    <DIR>          .
 04/30/2019  05:58 PM    <DIR>          ..
 04/30/2019  05:58 PM            35,314 AppxBlockMap.xml
 04/30/2019  05:58 PM             3,860 AppxManifest.xml
 04/30/2019  05:58 PM    <DIR>          AppxMetadata
 04/30/2019  05:58 PM            11,296 AppxSignature.p7x
 04/30/2019  05:58 PM    <DIR>          Assets
 04/30/2019  05:58 PM         4,188,672 Calculator.exe
 04/30/2019  05:58 PM            95,744 CalculatorApp.winmd
 04/30/2019  05:58 PM           286,920 resources.pri
 04/30/2019  05:58 PM    <DIR>          WinMetadata

帮助我找到了Ubuntu的exe文件,"%ProgramW6432%\WindowsApps\CanonicalGroupLimited.Ubuntu18.04onWindows_1804.2019.522.0_x64__79rhkp1fndgsc\ubuntu1804.exe"


1
是的,有可执行文件,但您不能总是直接调用它们;例如尝试从cmd.exe运行 "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1908.0.0_x64__8wekyb3d8bbwe\Calculator.exe",会提示 拒绝访问。但更重要的是,即使这样可以工作,显然这是一种非常繁琐的方法;如果应用程序定义了URL协议,则可以简单地执行类似于 Start-Process calculator: 的操作。 - mklement0

0
我遇到了类似的问题,并编写了以下代码。请注意,以下代码还提供了所需的完整行,因为并非所有的UWP程序都使用“!App”后缀。有些是自定义的。此脚本会返回完整的包名和类型。在我的用例中,我在最后一列生成批处理脚本的代码,但这个输出可以很容易地更新以满足您的要求。
# Function to get the app ID for a given package name
function Get-AppId {
    param (
        [string]$PackageName
    )

    # Get the app package for the given package name
    $appPackage = Get-AppxPackage | Where-Object { $_.Name -eq $PackageName }

    if ($appPackage) {
        return $appPackage.PackageFamilyName
    } else {
        return $null
    }
}

# Get all installed UWP programs
$installedPackages = Get-AppxPackage | Where-Object { $_.IsFramework -eq $false }

if ($installedPackages.Count -gt 0) {
    Write-Host "List of UWP programs with package name, app ID, and batch command:`n"

    # Generate a custom table with formatted columns
    $table = @()
    foreach ($app in $installedPackages) {
        $appName = $app.Name
        $appId = Get-AppId -PackageName $appName

        if ($appId) {
            $packageNameWithAppId = "$appName.$appId"

            # Get the app IDs from the app's manifest
            try {
                $ids = (Get-AppxPackageManifest $app -ErrorAction Stop).Package.Applications.Application.Id
            } catch {
                Write-Output "No IDs found for $($app.Name)" 
            }

            # Construct batch file command for each app ID
            foreach ($id in $ids) {
                $line = [PSCustomObject]@{
                    Name = $appName
                    "Package Name" = $packageNameWithAppId
                    "App ID" = $id
                    "BatchFileCommand" = "start explorer.exe `shell:AppsFolder\$($appId)!$($id)"
                }
                $table += $line
            }
        }
    }

    # Output the formatted table
    $table | Format-Table -AutoSize 

} else {
    Write-Host "No installed UWP programs found."
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接