I'm getting the list of installed Microsoft Store apps with this command:
Get-AppxPackage -AllUsers
And then I try to open an app:
powershell -Command "Start-Process 'C:\Program Files\WindowsApps\Microsoft.Windows.Photos_2021.21070.22007.0_x64__8wekyb3d8bbwe\Microsoft.Photos.exe' -Verb runAs"
I get an access error:
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()
Note: That Start-Process
-Wait
(and -PassThru
) cannot be used with at least some Microsoft Store applications is unfortunate; the problem has been reported in GitHub issue #10996.
Using a URI protocol scheme such as ms-photos:
is the simplest approach, although discovering a given Microsoft Store's application's protocol(s) is non-trivial - see this answer, which provides a helper function, Get-AppXUriProtocol
, which builds on the standard
Get-AppXPackage
cmdlet; e.g.:
# 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...}
As you can see, the Microsoft Photos application has several protocol schemes associated with it, but the obvious candidate for simply launching the application is ms-photos:
, which indeed works.
Launching Microsoft Store applications that do not have a URI protocol scheme defined:
If a given application doesn't define a URI protocol scheme, you must - somewhat obscurely - launch it via its AppId (application ID), and the general shell:
URI protocol scheme and the virtual AppsFolder
shell folder; e.g., to launch Calculator:
Start-Process shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
Finding an application's AppID:
In Windows 10 and above, you can now use the Get-StartApps
cmdlet to list all installed AppX applications or search by (part of) their display name, which reports their AppIDs. Thus, if you know an application's full display name, e.g., Photos
, you can launch it as follows:
Start-Process "shell:AppsFolder\$((Get-StartApps Photos | Select-Object -First 1).AppId)"
Note: The reason for Select-Object -First 1
is that even specifying the exact display name can result in multiple results, such as for Microsoft Edge
.
If you're unsure of the full display name, you can use a substring to find matching applications; e.g.. Get-StartApps edge
In older versions, you must determine the AppID manually, which is quite cumbersome, unfortunately: read on.
The AppID is composed of the family package name (e.g. Microsoft.MicrosoftEdge_8wekyb3d8bbwe
) followed by !
and a package-internal identifier, which is typically - but not always !App
; two notable exceptions:
Spotify requires !Spotify
(as you've discovered yourself).
Microsoft Edge uses !MicrosoftEdge
(note, however, that Edge does have a URI protocol for lauching, microsoft-edge:
and that there's also a simpler AppID, MSEdge
, though it doesn't support passing arguments (see below)).
As you have discovered yourself, the suffix is the package-internal application ID, which is defined in an application's manifest file, appxmanifest.xml
, located in the app-specific subfolder underneath $env:Programfiles\WindowsApps
; note that a manifest can contain multiple application IDs, as is indeed the case for Microsoft Photos:
# 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
It's fair to assume for launching the application interactively that the first entry must be used, though I'm not clear on whether there are official rules.
To demonstrate the technique using Microsoft Photos:
# 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"
Note that since the executable is then launched indirectly, the actual target process (Microsoft.Photos
in this case) isn't guaranteed to exist yet when Start-Process
returns, so more work is needed to first wait for it to come into existence, and then wait for it to exit.
In the simplest - but not fully robust - case, insert a Start-Sleep
command, to sleep as long as you would expect creation of the target process to take at most (the actual timing varies with system load):
Start-Process "shell:AppsFolder\$packageFamilyName!App"
Start-Sleep -Seconds 5 # Wait for the Microsoft.Photos process to be created.
(Get-Process Microsoft.Photos).WaitForExit()
A fully robust approach would require more work.
Passing arguments to Microsoft Store applications:
With the general "shell:AppsFolder\$appId"
approach, you can seemingly pass argument as usual, via Start-Process
' -ArgumentList
(-Args
) parameter; e.g., with Microsoft Edge (run from Windows PowerShell - if you have an older Edge version, replace !App
with `!MicrosoftEdge:
# Starts Microsoft Edge and opens the specified URLs.
# Note: Curiously, this does NOT work with the simpler "MSEdge" AppID.
Start-Process `
shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge `
-Args 'http://example.org https://wikipedia.org'
With the app-specific URI-scheme approach, argument(s) must be passed as part of the URI (-ArgumentList
is ignored):
Caveat: It is unclear to me how you can pass multiple arguments and, generally, whether there is a standardized method across applications to embed arguments in the URI.
For instance, Microsoft Edge seems to accept only one argument: the URL of a site to open. Anything after that one URL is seemingly interpreted as a part of that one URL:
# Starts Microsoft Edge an opens the specified URL.
Start-Process 'microsoft-edge:https://en.wikipedia.org?search=wikipedia'