4

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.
mklement0
  • 382,024
  • 64
  • 607
  • 775
AlekseyHoffman
  • 2,438
  • 1
  • 8
  • 31

1 Answers1

6
# 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'
      
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Ah, I see. It seems that Photos app just doesn't accept image paths as arguments. it just opens the main page. But how does File Explorer is able to open images via context menu then. Perhaps it expects something like -Path C:\image.png. Task manager doesn't show any arguments on the Photos.exe process either. – AlekseyHoffman Aug 24 '21 at 15:01
  • 1
    I'm making an open-source modern [file manager app](https://github.com/aleksey-hoffman/sigma-file-manager). With your help I will now be able to add a way to open files in specific UWP store apps, thank you for your contribution – AlekseyHoffman Aug 24 '21 at 15:02
  • Ok, well, I have almost experience with COM objects. unfortunately, so I have no idea how to use it in a command – AlekseyHoffman Aug 24 '21 at 15:21
  • 1
    Ah yeah, I remember you Michael. So you've come to my rescue yet again, huh. Cheers, bought you another coffee, enjoy mate – AlekseyHoffman Aug 24 '21 at 15:25
  • By the way I figured you can find the app ID (the `!App` bit on the end) in the AppxManifest.xml located in the app's folder. – AlekseyHoffman Aug 24 '21 at 15:32
  • 1
    Yep, it seems that the ID is located in ` – AlekseyHoffman Aug 24 '21 at 15:48
  • @AlekseyHoffman: As for the COM issue: I suggest asking a _new_ question focused on that: Given a shell-extension CLSID, how do you find the implementing COM executable or DLL, and how do you inspect its interfaces and members? I' been able to track down the implementing DLL as `%SystemRoot%\system32\PhotoMetadataHandler.dll`, but I don't know how to reflect on it (yet). – mklement0 Aug 24 '21 at 15:48
  • 1
    Thanks for the info. You've helped enough already. I will create another question with that exact title – AlekseyHoffman Aug 24 '21 at 16:10
  • @AlekseyHoffman. Sounds great; re finding the app ID(s) of an application (there can be multiple): I've added a command to the answer that extracts them programmatically. – mklement0 Aug 24 '21 at 16:14
  • 1
    Oh that's great, thanks. I just tested it with a few apps, it seems to be working as expected – AlekseyHoffman Aug 24 '21 at 16:17