Back Story
Several months ago, I ran across some Reddit posts where other sysadmins were talking about wrapping up their HUGE Autodesk app installs into .zip, .7z, or .wim files. Also, the MSEndpointMgr guys currently do a similar thing with their Driver Automation Tool for large driver packages.
I’ve kept this in the back of my mind for a while now until I needed to take advantage of this method. Now I’ve finally found a scenario that can benefit from this process!
The past couple days I’ve been trying to create an application deployment for a software called InEight Estimate. The package is fairly large (not Autodesk large) at 1.5 GB, but it has thousands of small files included in the installation directories.
The Problem?
No matter how quick your network connection is, ConfigMgr will iterate through and download these thousands of files separately. In our case, it took 10-15 minutes just to download this piece of software.
The solution is to compress the entire installation package into a .wim file because that’ll allow ConfigMgr to only hash and download one large file, dramatically speeding up this process.
We’re talking going from 10–15 minutes to a less than 2-minute download!
![stop, time, waste](https://endpointmanagertips.com/wp-content/uploads/2021/05/stop-time-waste-3089945-1024x678.jpg)
Creating the .WIM File
Creating the .wim file couldn’t be easier when using PowerShell. Use the following code to create the compressed .wim:
Using the New-WindowsImage cmdlet (run elevated), just specify the following:
- ImagePath = Location where you want the .wim to end up
- CapturePath = Location of the directory where the install files currently live
- Name = Whatever name you’d like to give the image
New-WindowsImage -ImagePath C:\Temp\[NAMEOFAPP].wim -CapturePath c:\Temp\InstallFiles -Name [Name of App]
In my example, I have the installer files in the C:\Temp directory, but you can adjust the command to point to any location you would like.
![](https://endpointmanagertips.com/wp-content/uploads/2021/05/051821_1921_DeployingLa1.png)
Setting up the App Deployment
The next step is to create the Application in ConfigMgr (or Intune) using the newly created .wim file. Do not include the “InstallFiles” directory from the previous step in the deployment package. That will defeat the purpose of this whole process and double up the size of your deployment.
Below is what the example deployment package looks like after it’s all setup. I’m simply including the .wim file and two scripts to install and uninstall.
![](https://endpointmanagertips.com/wp-content/uploads/2021/05/051821_1921_DeployingLa2.png)
How to Install the App Using a PowerShell Script
The first step is to mount the .wim file. I’m my case, I’m mounting the .wim contents to a temp folder that I create inside the app folder that’s used in ccmcache. Don’t worry, mounting the .wim only takes a couple of seconds.
Next you can install your application as normal using the $Mount directory that we used before to access your installation files. See script provided below for more details.
After installation is completed (hopefully successfully), we will then dismount the image before your script exits. We do this by using a try-catch-finally block.
The script (and this entire post) was heavily inspired by Justin Holloman and @_aarony blog post. Aaron’s code at the end is particularly clever because if the image fails to dismount for some reason, it’ll create a scheduled task as SYSTEM to run an additional dismount command after the next reboot.
Now go off and start deploying gigantic apps a little bit easier!
#Start Logging
Start-Transcript "$($env:ProgramData)\ExampleApp\ExampleInstall.log"
#Create a mount directory and attempt to mount the .wim file
#Mount and Dismount code inspired by https://adminsccm.com/2020/07/20/use-a-wim-to-deploy-large-apps-via-configmgr-app-model/
try {
$Mount = "$PSScriptRoot\Temp"
[void](New-Item -Path $Mount -ItemType Directory -ErrorAction SilentlyContinue)
Write-Host "Mounting the .wim to Temp directory"
Mount-WindowsImage -ImagePath .\Estimate.wim -Index 1 -Path $Mount
}
catch {
Write-Host "ERROR: Encountered an issue mounting the .wim. Exiting Script now."
Write-Host "Error Message: $_"
Exit 1
}
try {
#Installing Application
Write-Host "Installing Example App"
Start-Process -FilePath "$Mount\ExampleInstall.exe" -Wait
}
catch {
Write-Host "ERROR: Error installing application. Exiting Now"
Write-Host "Error Message: $_"
#Set Return Code 1 = Error
$returnCode = 1
}
finally {
try {
Write-Host "Attempting to Dismount the image"
Dismount-WindowsImage -Path $Mount -Discard
}
catch {
#Failed to Dismount normally. Setting up a scheduled task to unmount after next reboot (exit code 3010)
Write-Host "ERROR: Attempting to create scheduled task CleanupWIM to dismount image at next startup"
Write-Host "Error Message: $_"
#Set Return Code = 3010 to trigger a soft reboot
$returnCode = 3010
$STAction = New-ScheduledTaskAction `
-Execute 'Powershell.exe' `
-Argument '-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -command "& {Get-WindowsImage -Mounted | Where-Object {$_.MountStatus -eq ''Invalid''} | ForEach-Object {$_ | Dismount-WindowsImage -Discard -ErrorVariable wimerr; if ([bool]$wimerr) {$errflag = $true}}; If (-not $errflag) {Clear-WindowsCorruptMountPoint; Unregister-ScheduledTask -TaskName ''CleanupWIM'' -Confirm:$false}}"'
$STTrigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask `
-Action $STAction `
-Trigger $STTrigger `
-TaskName "CleanupWIM" `
-Description "Clean up WIM Mount points that failed to dismount" `
-User "NT AUTHORITY\SYSTEM" `
-RunLevel Highest `
-Force
}
#Stop Logging and Return Exit Code
Stop-Transcript
exit $returnCode
}
I’ve used similar techniques for years but use ZIP files rather than WIM files.
That’s my question, what’s the benefit of using the .wim approach against a simple compressed file (compressed files won’t have unmount issues fir example).
I liked the post, but cannot see the benefit.
The main point is to compress into one file to speed up downloads, so yeah a .wim, .zip, .7z would all be perfectly acceptable.
I’m using .wims specifically because of the ability to mount/dismount. Say you’re deploying a 20gb Revit installation…you’re not going to want to extract that .zip after already downloading the .zip. You’re doubling up the space required.
Fair enough, I did not think about that point.
Thank you!
I would also note that its usually not the size of the download that is the speed/time issue, its the fact that MECM hashes every file and then checks it to verify it was delivered properly. 10,000 files = 10,000 hash checks. 1 Wim/Zip = 1 hash check. So, large file size deployments with few files might not get much benefit from this deployment method than one with many files.
Thanks,
Ryan