27

I know if I have .appx package file, I can install it via powershell with the Add-AppxPackage cmdlet. However, I simply want to download & install Microsoft Store packages by name.

I don't want to have to go to the Microsoft Store page, start fiddler, start the download, capture the .appx file URL and then manually download it so that I can use Add-AppxPackage. (See how Windows OS Hub did that here)

That could be fun - but it will be flaky. I need a robust scriptable method for managing Windows Store apps.

(There are a few software packages that are only accessible via Microsoft Store. Everything else I can get via Chocolatey or direct msi download.)

One example that I can't yet script is installation of the HEIF Image Extensions (needed to view the image format from iPhones: *.HEIC format.

Once I install this from the Windows Store, it shows up with Get-AppxPackage

PS C:\Tools> Get-AppxPackage | Where-Object {$_.Name -eq "Microsoft.HEVCVideoExtension" }


Name              : Microsoft.HEVCVideoExtension
Publisher         : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture      : X64
ResourceId        :
Version           : 1.0.31053.0
PackageFullName   : Microsoft.HEVCVideoExtension_1.0.31053.0_x64__8wekyb3d8bbwe
InstallLocation   : C:\Program Files\WindowsApps\Microsoft.HEVCVideoExtension_1.0.31053.0_x64__8wekyb3d8bbwe
IsFramework       : False
PackageFamilyName : Microsoft.HEVCVideoExtension_8wekyb3d8bbwe
PublisherId       : 8wekyb3d8bbwe
IsResourcePackage : False
IsBundle          : False
IsDevelopmentMode : False
NonRemovable      : False
Dependencies      : {Microsoft.VCLibs.140.00_14.0.27810.0_x64__8wekyb3d8bbwe}
IsPartiallyStaged : False
SignatureKind     : Store
Status            : Ok

What I want is the cmdlet: Download-AppxPackage so that I can do:

Download-AppxPackage -Name "Microsoft.HEVCVideoExtension"

Does anyone know how I can do this?

3
  • 4
    Probably more suited to superuser.com
    – user574208
    Commented May 22, 2020 at 11:34
  • I submitted a feature request on their GitHub.
    – Foad
    Commented May 19, 2022 at 8:11
  • Have you tried winget? It can install soft from Microsoft Store. Commented Aug 19, 2022 at 5:52

5 Answers 5

16

You can now use winget to install msstore apps on windows 10 and 11. Use winget search <app_name> --source=msstore to make a search, and use the id of the app to install and upgrade the app. For example, to install Netflix:

  1. First I made a search with winget search Netflix --source=msstore, I see that the app id is 9WZDNCRFJ3TJ.
  2. I install app with winget install -e -i --id=9WZDNCRFJ3TJ --source=msstore.
  3. I upgrade app with winget upgrade -e -i --id=9WZDNCRFJ3TJ.
1
11

store.rg-adguard.net is a GUI for generating direct download links to store apps. Peeking at the source of that page, we can piggyback off them to download the content directly, but using PackageFamilyName, rather than Name (in your example it would be Microsoft.HEVCVideoExtension_8wekyb3d8bbwe).

function Download-AppxPackage {
[CmdletBinding()]
param (
  [string]$PackageFamilyName,
  [string]$Path
)
   
  process {
    $WebResponse = Invoke-WebRequest -Method 'POST' -Uri 'https://store.rg-adguard.net/api/GetFiles' -Body "type=PackageFamilyName&url=$($PackageFamilyName)&ring=Retail&lang=en-US" -ContentType 'application/x-www-form-urlencoded' -UseBasicParsing
    $LinksMatch = $WebResponse.Links | where {$_ -like '*_x64*.appx*'} | Select-String -Pattern '(?<=a href=").+(?=" r)'
    $DownloadLinks = @($LinksMatch.matches.Value)

    for ($i = 1; $i -le $DownloadLinks.Count; $i++) {
      Invoke-WebRequest -Uri $DownloadLinks[$i-1] -OutFile "$Path\$PackageFamilyName($i).appx"   
    }
  }
}

This is limited to the x64 version, and the path must point to a folder. It will download the package and its dependencies and save them all as PackagefamilyName(n).appx

2
  • Thanks - this is a good improvement. Not ideal as: a) I have to manualy install to find out the PackageFamilyName - and it may change. And: b) I don't know who "rg-adguard.net" are. I'll accept this as answer as probably best we can do until MS give me the cmdlet I want. They may want to divert users to the store to see ads etc. Commented May 23, 2020 at 15:20
  • as of: 06/25/2021 this is broken. Download-AppxPackage no longer works Commented Jun 25, 2021 at 14:01
6

Building further on AJ's Answer. Download any app from windows app store with powershell just supply a url from the store and a path for saving.

Usage:

Download-AppxPackage "https://www.microsoft.com/p/dynamic-theme/9nblggh1zbkw" "$ENV:USERPROFILE\Desktop"
C:\Users\user\Desktop\55888ChristopheLavalle.DynamicTheme_1.4.30233.0_neutral_~_jdggxwd41xcr0.AppxBundle
C:\Users\user\Desktop\55888ChristopheLavalle.DynamicTheme_1.4.30234.0_neutral_~_jdggxwd41xcr0.AppxBundle
C:\Users\user\Desktop\Microsoft.NET.Native.Framework.1.7_1.7.27413.0_x64__8wekyb3d8bbwe.Appx
C:\Users\user\Desktop\Microsoft.NET.Native.Runtime.1.7_1.7.27422.0_x64__8wekyb3d8bbwe.Appx
C:\Users\user\Desktop\Microsoft.Services.Store.Engagement_10.0.19011.0_x64__8wekyb3d8bbwe.Appx
C:\Users\user\Desktop\Microsoft.VCLibs.140.00_14.0.29231.0_x64__8wekyb3d8bbwe.App

Code:

function Download-AppxPackage {
[CmdletBinding()]
param (
  [string]$Uri,
  [string]$Path = "."
)
   
  process {
    $Path = (Resolve-Path $Path).Path
    #Get Urls to download
    $WebResponse = Invoke-WebRequest -UseBasicParsing -Method 'POST' -Uri 'https://store.rg-adguard.net/api/GetFiles' -Body "type=url&url=$Uri&ring=Retail" -ContentType 'application/x-www-form-urlencoded'
    $LinksMatch = $WebResponse.Links | where {$_ -like '*.appx*'} | where {$_ -like '*_neutral_*' -or $_ -like "*_"+$env:PROCESSOR_ARCHITECTURE.Replace("AMD","X").Replace("IA","X")+"_*"} | Select-String -Pattern '(?<=a href=").+(?=" r)'
    $DownloadLinks = $LinksMatch.matches.value 

    function Resolve-NameConflict{
    #Accepts Path to a FILE and changes it so there are no name conflicts
    param(
    [string]$Path
    )
        $newPath = $Path
        if(Test-Path $Path){
            $i = 0;
            $item = (Get-Item $Path)
            while(Test-Path $newPath){
                $i += 1;
                $newPath = Join-Path $item.DirectoryName ($item.BaseName+"($i)"+$item.Extension)
            }
        }
        return $newPath
    }
    #Download Urls
    foreach($url in $DownloadLinks){
        $FileRequest = Invoke-WebRequest -Uri $url -UseBasicParsing #-Method Head
        $FileName = ($FileRequest.Headers["Content-Disposition"] | Select-String -Pattern  '(?<=filename=).+').matches.value
        $FilePath = Join-Path $Path $FileName; $FilePath = Resolve-NameConflict($FilePath)
        [System.IO.File]::WriteAllBytes($FilePath, $FileRequest.content)
        echo $FilePath
    }
  }
}

This correctly downloads neutral and x64 packages but untested for arm and 32bit systems. the path must point to a folder. It will download the package and its dependencies and save them all as their original file names while avoiding name collisions like chrome.

6
  • as of: 06/25/2021 this is broken. Download-AppxPackage no longer works Commented Jun 25, 2021 at 14:01
  • hey @DeerSpotter what package did you try to download? my example still runs on my system
    – Yorai Levi
    Commented Jun 25, 2021 at 23:29
  • Thanks, it works. I didn't understand though why this fn downloads multiple versions of the same package. E.g. I tried with microsoft.com/pt-br/p/windbg/9pgjgd53tn86 and it downloaded both Microsoft.WinDbg_1.2104.13002.0_neutral__8wekyb3d8bbwe.Appx and Microsoft.WinDbg_1.2103.1004.0_neutral__8wekyb3d8bbwe.Appx
    – André
    Commented Jul 13, 2021 at 17:45
  • @André this script doesn't attempt to version check it just performs the download, you are welcome to share an adaptation that version checks~ I am sure it will be helpful for everyone
    – Yorai Levi
    Commented Jul 13, 2021 at 18:01
  • 1
    $env:PROCESSOR_ARCHITECTURE does not return the OS bitness, it returns the CPU (hardware) architecture. If you install a 32-bit OS on a 64-bit CPU, it will return AMD64. To test the OS bitness use: $CPU = if ([Environment]::Is64BitOperatingSystem) {'x64'} else {'x86'} Commented Jul 21, 2022 at 14:28
6
function Download-AppxPackage {
[CmdletBinding()]
param (
  [string]$Uri,
  [string]$Path = "."
)
   
  process {
    echo ""
    $StopWatch = [system.diagnostics.stopwatch]::startnew()
    $Path = (Resolve-Path $Path).Path
    #Get Urls to download
    Write-Host -ForegroundColor Yellow "Processing $Uri"
    $WebResponse = Invoke-WebRequest -UseBasicParsing -Method 'POST' -Uri 'https://store.rg-adguard.net/api/GetFiles' -Body "type=url&url=$Uri&ring=Retail" -ContentType 'application/x-www-form-urlencoded'
    $LinksMatch = ($WebResponse.Links | where {$_ -like '*.appx*'} | where {$_ -like '*_neutral_*' -or $_ -like "*_"+$env:PROCESSOR_ARCHITECTURE.Replace("AMD","X").Replace("IA","X")+"_*"} | Select-String -Pattern '(?<=a href=").+(?=" r)').matches.value
    $Files = ($WebResponse.Links | where {$_ -like '*.appx*'} | where {$_ -like '*_neutral_*' -or $_ -like "*_"+$env:PROCESSOR_ARCHITECTURE.Replace("AMD","X").Replace("IA","X")+"_*"} | where {$_ } | Select-String -Pattern '(?<=noreferrer">).+(?=</a>)').matches.value
    #Create array of links and filenames
    $DownloadLinks = @()
    for($i = 0;$i -lt $LinksMatch.Count; $i++){
        $Array += ,@($LinksMatch[$i],$Files[$i])
    }
    #Sort by filename descending
    $Array = $Array | sort-object @{Expression={$_[1]}; Descending=$True}
    $LastFile = "temp123"
    for($i = 0;$i -lt $LinksMatch.Count; $i++){
        $CurrentFile = $Array[$i][1]
        $CurrentUrl = $Array[$i][0]
        #Find first number index of current and last processed filename
        if ($CurrentFile -match "(?<number>\d)"){}
        $FileIndex = $CurrentFile.indexof($Matches.number)
        if ($LastFile -match "(?<number>\d)"){}
        $LastFileIndex = $LastFile.indexof($Matches.number)

        #If current filename product not equal to last filename product
        if (($CurrentFile.SubString(0,$FileIndex-1)) -ne ($LastFile.SubString(0,$LastFileIndex-1))) {
            #If file not already downloaded, add to the download queue
            if (-Not (Test-Path "$Path\$CurrentFile")) {
                "Downloading $Path\$CurrentFile"
                $FilePath = "$Path\$CurrentFile"
                $FileRequest = Invoke-WebRequest -Uri $CurrentUrl -UseBasicParsing #-Method Head
                [System.IO.File]::WriteAllBytes($FilePath, $FileRequest.content)
            }
        #Delete file outdated and already exist
        }elseif ((Test-Path "$Path\$CurrentFile")) {
            Remove-Item "$Path\$CurrentFile"
            "Removing $Path\$CurrentFile"
        }
        $LastFile = $CurrentFile
    }
    "Time to process: "+$StopWatch.ElapsedMilliseconds
  }
}


if (-Not (Test-Path "C:\Support\Store")) {
    Write-Host -ForegroundColor Green "Creating directory C:\Support\Store"
    New-Item -ItemType Directory -Force -Path "C:\Support\Store"
}

Download-AppxPackage "https://www.microsoft.com/p/snip-sketch/9mz95kl8mr0l" "C:\Support\Store"

Modified the script so that it delete old versions and only download latest.

Much thanks to Yorai Levi for the original script!

1
  • as of: 06/25/2021 this is broken. Download-AppxPackage no longer works Commented Jun 25, 2021 at 14:01
0

I've found some additional tools that I think are worth noting and hopefully may be of use to others who are using Windows Sandbox.

Although I tried to install Windows Store manually inside Windows Sandbox, that failed due to required components being missing, but this project fills in all of the gaps:

git clone https://github.com/kkkgo/LTSC-Add-MicrosoftStore

In that folder, simply run Add-Store.cmd and you will now have an operational Store App on the Start Menu in Windows Sandbox, but it is not complete as a few services have to be started also:

# 'config start=auto' is not required on Sandbox,
# but is useful for non-Sandbox environments.
SC config wuauserv start=auto
SC config bits start=auto
SC config cryptsvc start=auto
SC config trustedinstaller start=auto
SC start wuauserv
SC start bits
SC start cryptsvc
SC start trustedinstaller

Finally, make sure to log in to the Store with a Microsoft account (press the Profile at top right) after which, you should have a fully operational Windows Store app inside Windows Sandbox.

The project was built for Windows Enterprise LTSC (Long-Term Servicing Channel, designed for Windows 10 devices where the key requirement is that functionality and features don’t change over time) that, like Windows Sandbox, uses a slimmed down set of features, but this project works perfectly on Windows Sandbox. The project installs four components to achieve this:

Microsoft Store
Store Purchase App
App Installer
Xbox Identity Provider

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .