Tuesday, 21 November 2017 19:46

Install Appx Files Using PowerShell Wrapper

Written by
Rate this item
(4 votes)


These days most of my blog posts start off with a question from a customer. At least, this time around the question was relatively simple: How do you sideload a modern application into Windows 10? If you have followed Windows 10 development closely, then you have probably heard that Microsoft Deployment Toolkit has the ability to sideload apps, assuming you have the necessary source files handy. But what if you are using a third-party tool to deploy applications?

As I mentioned in my previous blog post, I am not a fan of reinventing the wheel. From Michael Niehaus' Ignite presentations and blog ramblings, I knew that MDT automatically creates the needed DISM command line to provision the app, so I opened the ZTIApplications.wsf file and started poking around. After locating the long DISM command line I quickly put together a PowerShell script that basically mimics MDT's behavior in front of my audience. No pressure, eh? Below (and on GitHub) is the end result.

How does it work:

In the simplest of terms, all you need are the source files in the right folder structure and the PowerShell wrapper I put together.

To download the necessary source files, you need to use Microsoft Store for Business (previously known as Windows Store for Business). It has been around for quite a while (two years almost to the day in fact). It's a layer that sits on top of the consumer Microsoft Store. Go to the main entry page located at businessstore.microsoft.com. You can do two things there: you can sign-in, if you have used the Store before, or start the sign-up process. Once you are logged in, browse to your inventory.

Select an application that you have acquired for offline use and download all components.

Unfortunately, there is no "Download all", so the process is a little bit messy. Basically, you need the Appx bundle, which is the main application package...

... the unencoded license XML file...

... and the required frameworks.

Once you downloaded all the pieces, you need to put them in the right folder structure, similarly to an application created in Visual Studio. For instance, with the Microsoft Wireless Display Adapter app you will end up with the following folder structure:

  • Root folder
    • Install-ProvisionedAppxPackage.ps1
      • AppxBundle
        • Microsoft.SurfaceWirelessDisplayAdapter_3.0.124.0_neutral_~_8wekyb3d8bbwe.AppxBundle
        • Microsoft.SurfaceWirelessDisplayAdapter_8wekyb3d8bbwe.xml
          • Dependencies
            • x64
              • Microsoft.NET.Native.Runtime.1.1_1.1.23406.0_x64__8wekyb3d8bbwe.Appx
              • Microsoft.VCLibs.140.00_14.0.25426.0_x64__8wekyb3d8bbwe.Appx
            • x86
              • Microsoft.NET.Native.Runtime.1.1_1.1.23406.0_x86__8wekyb3d8bbwe.Appx
              • Microsoft.VCLibs.140.00_14.0.25426.0_x86__8wekyb3d8bbwe.Appx

The wrapper will locate the Appx bundle, unencoded license file and dependencies, set the policy to enable sideloading (so strictly speaking license file should not be necessary, see the note below), build the necessary DISM command depending on the detected pieces to provision the application for you, run the DISM command and return the DISM exit code. You can run the script on a client machine either manually or by using your management tool. Ideally, the app will show up in the start menu. By default, the log file will be written to C:\temp\Log - you can adjust the path directly in the script.

So to summarize: download all the pieces, put them in the right folder structure, add the wrapper and run it. It is as simple as that.

Note: If you are not going to deploy private line-of-business apps and stick with the Microsoft Store for Business and Microsoft Store for Education applications which come with a license file, then you may want to remove the sideloading policy from the wrapper because it is not needed.

# Determine where to do the logging 
$logPath = "C:\temp\Logs"
$logFile = "$logPath\$($myInvocation.MyCommand).log"
$ScriptName = $MyInvocation.MyCommand

# Check log path
If (!(Test-Path $logPath)) {
    Write-Output "Log path not found..."
    New-Item -Path $logPath -ItemType Directory -Force

# Create Logfile
Write-Output "$ScriptName - Create Logfile" > $logFile
Function Logit($TextBlock1){
	$TimeDate = Get-Date
	$OutPut = "$ScriptName - $TextBlock1 - $TimeDate"
	Write-Output $OutPut >> $logFile

# Start main code here
. Logit "Make sure policy is set."
Set-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\Appx" -Name "AllowAllTrustedApps" -Value "1" -Force | Out-Null

. Logit "Build the base command line"
# Determine where to check
$AppxBundlePath = $PSScriptRoot + '\AppxBundle'
$AppxBundle = (Get-ChildItem -Path $AppxBundlePath) | where-object {$_.FullName -like "*.AppxBundle"}
$LicensePath = (Get-ChildItem -Path $AppxBundlePath) | where-object {$_.FullName -like "*.xml"}
$DependenciesPath = $AppxBundlePath + "\Dependencies"
$DependenciesList = (Get-ChildItem -Path $DependenciesPath -Recurse) | where-object {$_.FullName -like "*.appx"}
$Dependencies = ""

. Logit "Adding dependencies..."
ForEach ($tmp in $DependenciesList) {
    $Dependencies += " /DependencyPackagePath:" + $tmp.FullName

# Add license
If (!$LicensePath) {
    . Logit "No license file found..."
    $License = " /SkipLicense"
Else {
    . Logit "License file found..."
    $License = " /LicensePath:" + $LicensePath.FullName

# build command line
$BuildAppxCommand = "/Online /Add-ProvisionedAppxPackage /PackagePath:" + $AppxBundle.FullName + $License + " /NoRestart" + $Dependencies
# Launch Command and get return code
. Logit "Installing application $($AppxBundle.Name)"
. Logit "Command line $BuildAppxCommand"
$DISM = Execute-Command -commandTitle "Install AppxProvisionedPackage" -commandPath  DISM.exe -commandArguments $BuildAppxCommand

$ExitCode = $DISM.ExitCode
. Logit "Exit code from command $ExitCode"

Exit $ExitCode
Read 2232 times Last modified on Thursday, 21 December 2017 13:27
  1. Comments (0)

  2. Add yours
There are no comments posted here yet

Leave your comments

Posting comment as a guest.
0 Characters
Attachments (0 / 3)
Share Your Location

Recent Posts

  • Yet Another Windows 10 Optimization Script
    As a reminder, Microsoft will be ending support for Windows 7 SP1 on January 14, 2020. I've had multiple enterprise…
    Written on Monday, 25 June 2018 16:09
  • Automating Dell BIOS Configuration Using MDT
    It’s been a busy couple of weeks for me, so I’m slowly going through a backlog of things to cover.…
    Written on Thursday, 21 June 2018 08:11
  • Configuring HP BIOS Using MDT
    This is the second post in my series that explores one of the most common questions I’ve been asked from…
    Written on Tuesday, 19 June 2018 09:54
  • BIOS to UEFI - The Easy Way: MBR2GPT
    This article is the first blog post in a series I'll write over the coming days that will provide a…
    Written on Monday, 11 June 2018 17:08
  • Force LAPS Password Reset during MDT OSD
    My customers often send me exciting cases. This particular one is especially interesting because it is common in infrastructures that…
    Written on Friday, 08 June 2018 10:10
  • Localizing Inbox Apps during OSD
    As a reader of this blog, I suspect that most of you, like me, are frequenting Twitter. And I bet…
    Written on Monday, 04 June 2018 18:18