ConfigMgr: WIM Your Applications Like a Boss
12-12-2020 2:25 PM
Disclaimer: All information and content in this blog posts is provided without any warranty whatsoever. The entire risk of using this information or executing the provided content remains with you. Under no circumstances should Dell, Microsoft, its author, or anyone else involved in the creation of these blog posts be held liable for any damage or data loss.
Knowledge: I assume that people who read this blog post has an general understanding of application creation in Microsoft Endpoint Configuration Manager, so I won't be deep-diving into details about that in this post.
For several years I've built huge applications of 10-20 GB in size (Hashtag Autodesk) with a long deployment time to follow for the end user. For all those years I been wanting to come up with a solution to reduce the size of the applications and deployment time.

Let´s WIM Your Applications Like a Boss!
Then earlier this year I was inspired by Martin Bengtsson and his blog post about capturing drivers into a WIM format and *BINGO* then came the idea to build a PowerShell script to handle WIM applications in our Microsoft Endpoint Configuration Manager environment with logic and log function.
After it has gone into production, I can now share it with you guys
🤓
Windows Imaging (WIM) format is a file-based disk image format. It was developed by Microsoft to help deploy Windows Vista and subsequent versions of the Windows operating systems.
With the Deployment Image Servicing and Management (DISM) tool, it is possible to create a data image for applications, files, and other resources.
Okay, let's get started! As mentioned above, you need the Deployment Image Servicing and Management (DISM) tool in order to capture an application as WIM format and you must use this tool from either CMD or PowerShell.
Note: There is currently an ongoing discussion for and against using MAX compression when using deduplication in your environment. I've tested both FAST and MAX compression and I have not experienced any problems in our environment and we are using deduplication along with BranchCache.
But I tend to listen to clever people, so my recommendation at this point is to use "/Compress:fast" if you are using deduplication, just to be safe
🤓
7-ZIP: Wait a second, why WIM and not 7-Zip you might ask? Well, with WIM you only need to mount and unmount the image, which leaves a much smaller footprint than 7-Zip because you don't have to extract the content and use extra storage space!
Hashing: Microsoft Endpoint Configuration Manager uses a hashing function to determine if the files are different. Every file are given a hash value, which means that there may be hundreds of files per application to hash check during distributing and downloading content.
By using WIM captured applications, only two files need to be hash checked.
Now, let´s try and WIM the latest Java 8 Update 271 application.
Step 1. Create a temp folder containing your source application e.g. C:\Temp\Java
Step 2. From an elevated CMD or PowerShell prompt, run the below DISM command.
# DISM command for capturing a data image
Dism.exe /Capture-Image /ImageFile:C:\Temp\Application.wim /CaptureDir:"C:\Temp\Java" /Name:"Oracle" /Description:"Java 8 Update 271" /Compress:fast
Creating WIM with the Deployment Image Servicing and Management (DISM) Tool
This will create an application.wim file and if we compare the source folder to the application.wim, we can see that it didn't reduce the size due to the already small size of the Java application.
Comparison of the Source Folder and WIM Application
But what happens if we make the same comparison with an Autodesk application?
Creating WIM with the Deployment Image Servicing and Management (DISM) Tool
Comparison of the Source Folder and WIM Application
Let´s compare the Autodesk Revit 2021 source folder with the WIM file. Whoa..! We went from 12.039 files and 1610 folders to 1 single WIM file and reduced the size by 2,5 GB! Damn! That's awesome
😎
This was the easy part! We can now focus on my PowerShell script, which will be used to deploy the application as WIM format.
The script supports the following deployment modes (Install, Uninstall, Repair) and you only need to change a few lines for each of these deployment modes to fit your needs - See more in the script details.
Installing Java 8 Update 271
Uninstalling Java 8 Update 271
Repairing Java 8 Update 271
The script does also support Get-Help and Verbose.
Get-Help -Examples
Get-Help -Detailed
-Verbose
Script (Invoke-AppDeploy.ps1)
<#
.SYNOPSIS
Mount WIM, Install, Uninstall or Repair Application and Unmount WIM.
.DESCRIPTION
The purpose of this script is to mount a WIM containing an application that will
be installed, uninstalled or repaired and then unmount the WIM again.
So before using this script, you must capture the application into a WIM file and
this can be done with the DISM example further down in this description.
Capturing applications as WIM and the use of this script reduces our application
deployment time through Configuration Manager by 30-60% depending on the hardware
configuration and the application size.
We are old school and we use CMD scripts for application deployment in our environment.
But it's pretty easy to modify the deployment mode variables found in the "Begin" script
block to support other formats like .msi, .exe or .ps1 file.
DISM Example.
Dism.exe /Capture-Image /ImageFile:C:\Temp\Application.wim /CaptureDir:"C:\Temp\Java" /Name:"Oracle" /Description:"Java" /Compress:fast
NOTE. I'll recommend using "/Compress:fast" if you are using deduplication. Some wise people state that
"/Compress:max" is no good if you are using deduplication. And I tend to listen to wise people ;)
CMD Example (Default).
$FilePath = Join-Path -Path "$MountDir" -ChildPath "Install.cmd"
$Process = "cmd.exe"
$Arguments = @(
"/c",
"""$FilePath""",
"> nul",
"&& exit"
)
MSI Example.
Change this -> $FilePath = Join-Path -Path "$MountDir" -ChildPath "Setup.msi"
Change this -> $Process = "msiexec.exe"
Change this -> $Arguments = @(
"/I",
"""$FilePath""",
"/qn",
"REBOOT=ReallySuppress"
)