我正在使用以下命令获取已安装Microsoft应用商店应用程序的列表:
Get-AppxPackage -AllUsers
然后我尝试打开一个应用程序:
powershell -Command "Start-Process 'C:Program FilesWindowsAppsMicrosoft.Windows.Photos_2021.21070.22007.0_x64__8wekyb3d8bbweMicrosoft.Photos.exe' -Verb runAs"
我收到访问错误:
This command cannot be run due to the error: Access is denied.
# Use the URI scheme of the Microsoft.Photos application.
# Note: Unfortunately, -Wait does *not* work in this case.
Start-Process ms-photos:
# Wait for the process to exit (from what I can tell there's only ever 1
# Microsoft.Photos process).
# The relevant process name was obtained with: Get-Process *Photos*
(Get-Process Microsoft.Photos).WaitForExit()
注意:不幸的是,Start-Process
-Wait
(和-PassThru
)不能与至少某些Microsoft应用商店应用程序一起使用;GitHub 问题 #10996 中报告了此问题。
使用URI 协议方案(如ms-photos:
)是最简单的方法,尽管发现给定的 Microsoft Store 应用程序的协议并非易事 - 请参阅此答案,它提供了一个帮助程序函数Get-AppXUriProtocol
,它基于标准Get-AppXPackage
cmdlet 构建;例如:
# Note:
# * Requires custom function Get-AppXUriProtocol from the linked answer.
# * Must be run in *Windows PowerShell*, because the AppX module
# isn't supported in PowerShell (Core), as of v7.1.
PS> Get-AppXUriProtocol *Photos* | Format-List
PackageFullName : Microsoft.Windows.Photos_2021.21070.22007.0_x64__8wekyb3d8bbwe
Protocols : {ms-wcrv, ms-wpdrmv, ms-photos, microsoft.windows.photos.crop...}
如您所见,Microsoft Photos应用程序具有多个与之关联的协议方案,但是简单地启动该应用程序的明显候选者是ms-photos:
,这确实有效。
启动未定义 URI 协议方案的Microsoft存储应用程序:
如果给定的应用程序没有定义 URI 协议方案,则必须 - 有点模糊地 - 通过其AppId(应用程序 ID)以及通用shell:
URI 协议方案和虚拟AppsFolder
shell 文件夹启动它;例如,要启动计算器:
Start-Process shell:AppsFolderMicrosoft.WindowsCalculator_8wekyb3d8bbwe!App
查找应用程序的 AppID:
在Windows 10 及更高版本中,你现在可以使用
Get-StartApps
cmdlet 列出所有已安装的 AppX 应用程序,或按其显示名称(部分)进行搜索,该名称报告其 AppID。因此,如果您知道应用程序的完整显示名称,例如Photos
,您可以按如下方式启动它:Start-Process "shell:AppsFolder$((Get-StartApps Photos | Select-Object -First 1).AppId)"
注意:
Select-Object -First 1
的原因是,即使指定确切的显示名称也可能导致多个结果,例如Microsoft Edge
。如果您不确定完整的显示名称,则可以使用子字符串来查找匹配的应用程序;例如
Get-StartApps edge
在旧版本中,您必须手动确定AppID,不幸的是,这非常麻烦:请继续阅读。
AppID 由系列包名称组成(例如Microsoft.MicrosoftEdge_8wekyb3d8bbwe
) 后跟!
和包内部标识符,通常 - 但并不总是!App
;两个值得注意的例外:
Spotify需要
!Spotify
(正如你自己发现的那样)。MicrosoftEdge 使用
!MicrosoftEdge
(但请注意,Edge 确实有一个用于 URI 协议,用于 lauching、microsoft-edge:
,还有一个更简单的 AppID,MSEdge
,尽管它不支持传递参数(见下文))。正如您自己所发现的,后缀是包内部应用程序 ID,它在应用程序的清单文件中定义,
appxmanifest.xml
,位于$env:ProgramfilesWindowsApps
下特定于应用程序的子文件夹中;请注意,清单可以包含多个应用程序 ID,就像 Microsoft 照片一样:# Run in *Windows PowerShell*. # For Microsoft Photos, the following application IDs are reported: # 'App', 'SecondaryEntry' $appManifestPath = (Get-AppxPackage *Photos*)[-1].InstallLocation + 'appxmanifest.xml' ( Select-Xml '//ns:Application' $appManifestPath ` -Namespace @{ ns='http://schemas.microsoft.com/appx/manifest/foundation/windows10' } ).Node.Id
假设以交互方式启动应用程序必须使用第一个条目是公平的,尽管我不清楚是否有官方规则。
要使用"Microsoft照片"演示该技术,请执行以下操作:
# Get the package family name (the assumption here is that only *1* package matches).
# Note: While you must run the Get-AppXPackage from *Windows PowerShell*
# you can use the resulting package name to launch the application
# from PowerShell (Core) too.
$packageFamilyName = (Get-AppXPackage *Photos*).PackageFamilyName
Start-Process "shell:AppsFolder$packageFamilyName!App"
请注意,由于可执行文件随后是间接启动的,因此实际的目标进程(在本例中为Microsoft.Photos
)在Start-Process
返回时还不能保证存在,因此需要做更多的工作来首先等待它的存在,然后等待它退出。
在最简单但不是完全健壮的情况下,插入一个Start-Sleep
命令,只要您期望创建目标进程最多需要多长时间(实际时间因系统负载而异):
Start-Process "shell:AppsFolder$packageFamilyName!App"
Start-Sleep -Seconds 5 # Wait for the Microsoft.Photos process to be created.
(Get-Process Microsoft.Photos).WaitForExit()
一个完全健全的方法需要更多的工作。
将参数传递给Microsoft应用商店应用程序:
使用一般的
"shell:AppsFolder$appId"
方法,您似乎可以像往常一样通过Start-Process
'-ArgumentList
(-Args
) 参数传递参数;例如,使用 Microsoft Edge(从Windows PowerShell运行 - 如果您有较旧的 Edge 版本,请将!App
替换为 '!微软边缘:# Starts Microsoft Edge and opens the specified URLs. # Note: Curiously, this does NOT work with the simpler "MSEdge" AppID. Start-Process ` shell:AppsFolderMicrosoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge ` -Args 'http://example.org https://wikipedia.org'
使用特定于应用的 URI 方案方法,参数必须作为 URI 的一部分传递(
-ArgumentList
将被忽略):警告:我不清楚如何传递多个参数,以及通常,是否有跨应用程序的标准化方法在 URI 中嵌入参数。
例如,Microsoft Edge 似乎只接受一个参数:要打开的网站的 URL。该 URL 之后的任何内容似乎都被解释为该 URL 的一部分:
# Starts Microsoft Edge an opens the specified URL. Start-Process 'microsoft-edge:https://en.wikipedia.org?search=wikipedia'