相关文章推荐

Stack Exchange Network

Stack Exchange network consists of 183 Q&A communities including Stack Overflow , the largest, most trusted online community for developers to learn, share their knowledge, and build their careers. Visit Stack Exchange

Server Fault is a question and answer site for system and network administrators. It only takes a minute to sign up.

Sign up to join this community

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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?

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:

  • First I made a search with winget search Netflix --source=msstore, I see that the app id is 9WZDNCRFJ3TJ.
  • I install app with winget install -e -i --id=9WZDNCRFJ3TJ --source=msstore.
  • I upgrade app with winget upgrade -e -i --id=9WZDNCRFJ3TJ.
  • 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

    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. – David Wilson May 23, 2020 at 15:20

    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.

    hey @DeerSpotter what package did you try to download? my example still runs on my system – Yorai Levi 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é 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 Jul 13, 2021 at 18:01 $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'} – user15261314 Jul 21, 2022 at 14:28 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!

    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
    
     
    推荐文章