For the past decade or so, MDT Lite Touch have had a little know feature called Exits (or UpdateExit), which is called every time you do a full update of the deployment share. The feature was added back in MDT 2010, and was originally documented by Michael Niehaus (@mniehaus) here: MDT 2010 New Feature #17: Customizable boot image process.
Note: This not the same as UserExits that you define in Bootstrap.ini and/or CustomSettings.ini.
Background
The Exits feature was initially intended to do automation around WDS, like automatically replace the boot image in WDS every time you updated the deployment share. But it has also been useful when patching boot images back in the old days when WinPE 1709 had a rather ugly driver bug, or to dynamically update the bootstrap.ini file, or to disable SMB1 to secure WinPE before SMB1 was disabled by default. Lately I've been using it to add BITS and BranchCache to the boot image.
How it works
When you update a deployment share, the update process looks for an Exits section in two XML files in your deployment share templates folder. The two files are the LiteTouchPE.xml file, which is called for the boot image you define in the mandatory Lite Touch Boot Image Settings section, and the Generic.xml file which is called for the optional boot image that you can define in the Generic Boot Image Settings section (not so commonly used).

Both XML templates have Exits section like this, which by default runs the UpdateExit.vbs script from the MDT installation directory:
<Exits>
<Exit>cscript.exe "%INSTALLDIR%\Samples\UpdateExit.vbs"</Exit>
</Exits>
If you rather want to run a PowerShell Script for your MDT Lite Touch boot image, you simply copy the LiteTouchPE.xml to the templates folder in your deployment share, and change it to run PowerShell . In the below example I'm calling a PowerShell script named UpdateExit.ps1 which is stored in the scripts folder of my deployment share.
<Exits>
<Exit>powershell.exe -File "%DEPLOYROOT%\Scripts\UpdateExit.ps1"</Exit>
</Exits>
Four Stages
During the deployment share update process, the script configured in LiteTouchPE.xml is run four times, one for each stage (phase), in the deployment update process. By referencing one more stages in the script, you can decide exactly when to run your custom code. The four stages are:
- WIM. This stage happens right before the WIM changes are committed.
- POSTWIM. This stage happens right after the WIM changes are committed.
- ISO. This stage happens right before a new ISO is created (as long as your deployment share is setup to create one)
- POSTISO. This stage happens after the ISO has been created.
To keep track of the four stages, the MDT deployment share update process updates two environment variables. One is the STAGE variable, and one is the CONTENT variable. The STAGE variables simply tells you what stage the deployment share update process is currently in, and then CONTENT variable tells you where to find the content the update process is working on at the moment.
For example, if you want to do something in the WIM stage, you can just add the below code to your UpdateExit script, and it will run that code when the deployment share is updated. In this example I'm actually calling a second script in the WIM phase. I found it easier to have separate scripts for the various actions I want to do, rather then clutter the UpdateExit script itself with a bunch of different code snippets or functions.
In the PowerShell Deployment extension to MDT we use this feature to add BITS, and BranchCache support to MDT boot images, but I have simplified the script in this post a bit to make it easier. Below is a sample UpdateExit.ps1 script that in turns calls the main modification script, named Set-BootImage.ps1. Again this script is run every time you do a full update of the deployment share.
If ($Env:STAGE -eq "WIM") {
$Argument = "$Env:DEPLOYROOT\Scripts\Set-BootImage.ps1"
$Process = Start-Process PowerShell -ArgumentList $Argument -NoNewWindow -PassThru -Wait
}
The Set-BootImage.ps1 script
In this particular example I wanted my Set-BootImage.ps1 script, called by UpdatedExit.ps1 script, to download the latest version of Process Monitor, and add it to the boot image. I also added in some very basic logging to track the progress. Again, check out the PowerShell Deployment extension to MDT for examples with more advanced logging and error handling.
#Requires -RunAsAdministrator
$Logfile = "$Env:DEPLOYROOT\Set-BootImage.log"
Function Write-Log{
param (
[Parameter(Mandatory = $true)]
[string]$Message
)
$TimeGenerated = $(Get-Date -UFormat "%D %T")
$Line = "$TimeGenerated : $Message"
Add-Content -Value $Line -Path $LogFile -Encoding Ascii
}
# Added for downloading and adding Process Monitor
Write-Log -Message "Set-BootImage.ps1 script started"
Write-Log -Message "Current DEPLOYROOT value is $Env:DEPLOYROOT"
# Download Process Monitor to C:\Windows\Temp
$URL = "https://live.sysinternals.com/Procmon64.exe"
Write-Log -Message "Downloading Process Monitor from $URL"
Start-BitsTransfer -Source $URL -Destination "C:\Windows\Temp"
# Get the downloaded version
$ProductVersion = (Get-item -Path "C:\Windows\Temp\Procmon64.exe").VersionInfo.ProductVersion
# Copy Process Monitor to the mounted boot image
$DestinationPath = "$Env:CONTENT\Windows\System32"
Write-Log -Message "About to copy Procmon64.exe to $DestinationPath"
Copy-Item -Path "C:\Windows\Temp\Procmon64.exe" -Destination $DestinationPath
Write-Log "All done, Process Monitor version: $ProductVersion has been added to the boot image"
Deployment Share Update Process – Behind the scenes
When updating the deployment share, there are quite many steps happening in the process. Here follows a detailed list for what happens when the deployment share only has support for x64 configured, only have the Lite Touch Boot Image Settings section configured, but the generation of an ISO is selected within that section.
- MDT copies required WinPE boot image files to the boot folder in the deployment share. These are files like boot loaders, boot managers, and fonts etc.
- MDT copies the winpe.wim from the ADK installation directory to a temporary location in under %temp%, for example MDTUpdate.2256, and renames it to LiteTouchPE_x64.wim.
- MDT runs dism from the ADK install directory to mount the copied wim file to a temporary folder, for example MDTUpdate.2256\Mount.
- MDT runs dism several times to add all optional components to the mounted WinPE image folder. This can be components you selected in the deployment share properties, as well as hardcoded components listed in the LiteTouchPE.xml file.
- MDT creates the boot image ISO file from the content in MDTUpdate.2256\ISO
Happy Deployment, Johan
Hello Johan, please can you share how to ensable BITS and BranchCache one Winpe ?
And for what use is it useful then ?
Hi, you need to use the free OSD Toolkit from 2Pint Software to enable BITS and BranchCache to WinPE. It can then be used to peer-to-peer content when imaging via ConfigMgr or the PSD PowerShell extension for MDT Lite Touch. You can download the toolkit from this link: https://2pintsoftware.com/products/osd-toolkit/
Johan, thanks very much for this.
Is there any specific way to run a full update on media in MDT 8456? I've searched high and low and can't find anything on this.
Hi Richard,
I'm sorry for the super-late reply, I totally missed this comment. Is this for boot media or standalone media?
No problem at all – I really appreciate your response. This is for standalone media. When I run the Update-MDTMedia cmdlet with 8456, the script defined in the Exit node only seems to run on the first attempt. Subsequent attempts where the boot WIM is already present and needs no updates do not run the exit script – at least in my setup. What I ended up doing is adding a step in my media update script to delete various files/folders in the media output path: Applications, Operating Systems, and Scripts, along with the boot media WIM file itself. I… Read more »
Hi Richard,
Yes, a full regenerate of the deployment share is usually needed, unless the boot folder is empty, which forces a full generation anyway.
While the Update-MDTMedia does not have it, the Update-MDTDeploymentShare cmdlet does support the -Force option which is the same as selecting the regenerate option.
/ Johan