Exploring Device Management.
05 June 2025
This post will introduce a Command-line tool that I developed to fully automate the creation of Windows installation media in form of a usb-drive. But I didnt stopped there because you could get that using the official Windows Media Creation tool from Microsoft…I wanted my tool to have even more features that simplify things even more.
So let me introduce you to mctcli
- which stands for:
M edia
C reation
T ool
C ommand
L ine
I nterface
and is a simple to use powershell script which creates Windows installation medias with even more than just Windows 11.
ARM64
or X64
versions of Windows 11This question is simple, check out my Github Repo which hosts the script files.
It is free to use and I am still working on adding other features and optimize it.
[!NOTE] Check out the Readme file in the repo as this always will hold the latest documentation on how to use the script and its parameters.
Download the mctcli.ps1 script from my Github Repo. Then start a elevated
PowerShell console and run the following command from the folder where you downloaded the script into.
This sample will pull Windows 11 with:
amd64
24H2
en-us
en-us
(this parameter is only needed if you need different regional settings that from the base language)Pro
"E:"
(this parameter defines the letter of the usb-drive where you want to apply the install media onto)Add OEM drivers
If you want to include oem drivers you need the -DriverManufacturer
and -DriverModel
parameter.
Dell
, Lenovo
and HP
are the supported manufacturers for oem drivers in this script. The Manufacturers are hard coded into the parameters so you can “tap” trough the tree supported manufacturers. For models you could use for example “Latitude 5440” or “ThinkPad X390” or “Z6 G5” to name one model per manufacturer :)
Dont forget to use the -DriverInjectionType switch with a value of DISM
or AUTOUNATTEND
to control how to inject the drivers…explained later in this post.
So a sample call of the script could look like this:
.\mctcli.ps1 -Architecture amd64 -Build 24H2 -LanguageCode "en-us" -RegionCode "en-us" -Edition Pro -UsbDriveLetter "E:" -DriverManufacturer Dell -DriverModel "Latitude 5440" -DriverInjectionType DISM -Verbose
As the script has some parameters I tought it would be nice to have them described.
So the script has a Parameter based help
section in the top, which I also have in the Readme at the repo.
I added a description for each parameter to tell you what this parameter does, what values are supported and if applicable what its default value ist:
-Architecture
The architecture of Windows to download. Valid values are amd64 or arm64.
The default is x64.
-Build
The build number of Windows to download. Valid values are "21H2", "22H2", "23H2", "24H2".
The default is the 24H2 build.
-LanguageCode
The language code of Windows to download. Valid values for example are en-us, de-de, fr-fr, es-es, it-it.
The default is en-us.
-RegionCode
The regional code of Windows to download. Valid values for example are en-us, de-de, fr-fr, es-es, it-it.
The default is en-us and will be matched to LanuageCode. if not set.
-Edition
The edition of Windows to download. Valid values are "Home", "Pro", "Pro N", "Enterprise", "Enterprise N", "Education", "Education N"
The default is Pro.
-UsbDriveLetter
The drive letter of the USB drive to create the bootable media.
For example "E:".
-DriverManufacturer
The manufacturer of the drivers to download. Valid values are "Dell", "Lenovo", "HP".
The default is not set.
-DriverModel
The model of the drivers to download. This is optional and will be used to filter the drivers from the manufacturer.
For example (Dell) "Latitude-5440" or (Lenovo) "ThinkPad X390" or (HP) "Z6 G5".
The default is not set.
.PARAMETER -DriverInjectionType
The type of driver injection to use. Valid values are "AUTOUNATTEND" or "DISM".
The default is not set.
-Verbose
Enable verbose output. I recommend using this parameter, as it exactly shows you what the script does and where it currently is.
This section will describe what the script does, how it works and why I build it like it is.
mctcli
(and some subfolders that only exists during runtime) at %LOCALAPPDATA%\temp
.XML
Manifest file, containing all the download liks for all Windows 11 versions. The script downloads this file and uses regex to search for the specific version of Windows that you requested using the parameters. Once it found the version, it will download as Edition-LanguageCode-Build-Architecture.esd
into the mctcli
folder..cab
file which you need to extract when you want to work with it.setup
, boot
and install
-wim files
wim
files from the esd:
NTFS
as the format to be able to hold larger .wim
files and driverpacks - this wouldnt be possible with FAT32
but it wasnt possible to boot from NTFS
. So i figured out that you can use two partitions with a custom bootloader. Thats why the script creates two partitions and as you will see in step 7 and loads the Rufus Bootloader onto the first partition. This then looks on the second partition which is NTFS
for the Windows Setup.setup.wim
to the root of the second usb-drive-partition
setup.wim
as it holds all the files and structure of a Windows installation media, while mounted we copy everything on the NTFS
partition and then dismount the setup.wim
.boot.wim
and install.wim
to the \sources\
folder on the usb-drive
boot.wim
and install.wim
to the \sources\
folder on the usb-drive which will be used to boot the PE and apply the install.wim
to the new C:\
drive which will hold the operating system.FAT32
partition and it then, while booting, looks to the NTFS
partition for the boot files.DriverManufacturer
and DriverModel
parameters to have a search string which the script then builds to query the oem driver manifests to get download urls, download the driverpacks, silently extract them and copy them on the usb-drive in the \drivers\
folder. In step 10 we will configure how this then will be used from the Windows setup.Issue
starting with Windows 11 24H2 I´ve implemented a switch to control how you inject drivers. If Microsoft fixes this with the next version of Windows I am happy to use it from the autounattend.xml
and drivers
-folder again - but until then we have to use DISM…which you can control using a switch parameter in my script or by using the dism-driver-injection branchGet-AutopilotDiagnosticsCommunity.ps1
, Get-WindowsAutopilotInfoCommunity.ps1
and Get-IntuneManagementExtensionDiagnostics.ps1
scripts from @Andrew Taylor and @Petri Paavola so I asked them to use their scripts in my tool and they agreed. Check those tools out they are really usefull for Intune Admins. Maybe I will add more scripts in the future…autounattend.xml
years ago, I always created on for Windows Installation media. So of course we needed that here. What it (simply said) does is to automate the Windows setup. You can pre-configure disk-layout, language and so on and also it supports further automations like to define a folder on the Installation media which holds driverpacks which will be installed from the Windows setup..esd
file. I keep the esd file if we want to create another boot stick. Im thinking about adding a parameter (switch) to configure to keep or delete it if you want to control that. Maybe give me feedback in the comments on LinkedIn?I would definitely recommend to use the -Verbose
parameter as this shows you everything and exactly what the script does. So a output using the -Verbose
parameter would look like this…telling you about every step (I wanted to have a very detailed log when using -Verbose
so its easy to follow the script or if needed troubleshoot it):
VERBOSE: Created temporary directory C:\Users\NRAST\AppData\Local\Temp\mctcli\driverpack...
VERBOSE: Created temporary directory C:\Users\NRAST\AppData\Local\Temp\mctcli\setupwim...
VERBOSE: Created temporary directory C:\Users\NRAST\AppData\Local\Temp\mctcli\bootwim...
VERBOSE: Created temporary directory C:\Users\NRAST\AppData\Local\Temp\mctcli\installwim...
VERBOSE: Parameters
VERBOSE: Architecture: amd64
VERBOSE: Operating System Version Support: Windows 11 (Win11 / W11)
VERBOSE: Build: 24H2
VERBOSE: LanguageCode: en-us
VERBOSE: RegionCode: en-us
VERBOSE: Edition: Pro
VERBOSE: UsbDriveLetter: E:
VERBOSE: DriverManufacturer: Dell
VERBOSE: DriverModel: Latitude 5440
VERBOSE: Working Directory: C:\Users\NRAST\AppData\Local\Temp\mctcli
VERBOSE: ------------------------------------------------------
VERBOSE: Starting Windows Media Creation CLI at 12:43:03
VERBOSE: Pulling Pro from CLIENTBUSINESS_VOL...
VERBOSE: Build version converted to 26100...
VERBOSE: Architecture converted to x64...
VERBOSE: Downloading Manifest from https://go.microsoft.com/fwlink/?LinkId=2156292 to C:\Users\NRAST\AppData\Local\Temp\mctcli...
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 29251-byte response of content type application/octet-stream
VERBOSE: File Name: manifest.cab
VERBOSE: Extracting Manifest to C:\Users\NRAST\AppData\Local\Temp\mctcli\manifest_products.xml...
VERBOSE: Removing temporary file C:\Users\NRAST\AppData\Local\Temp\mctcli\manifest.cab...
VERBOSE: Parsing XML file C:\Users\NRAST\AppData\Local\Temp\mctcli\manifest_products.xml...
VERBOSE: Found ESD URL: http://dl.delivery.mp.microsoft.com/filestreamingservice/files/fc053c7c-7fca-4c3c-bde5-e1c49fa6189c/26100.2033.241004-2336.ge_release_svc_refresh_CLIENTBUSINESS_VOL_x64FRE_de-de.esd
VERBOSE: Downloading ESD file from http://dl.delivery.mp.microsoft.com/filestreamingservice/files/fc053c7c-7fca-4c3c-bde5-e1c49fa6189c/26100.2033.241004-2336.ge_release_svc_refresh_CLIENTBUSINESS_VOL_x64FRE_de-de.esd to C:\Users\NRAST\AppData\Local\Temp\mctcli...
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 4086371836-byte response of content type application/octet-stream
VERBOSE: File Name: Pro-en-us-24H2-amd64.esd
VERBOSE: Extracting setup from ESD to WIM format...
VERBOSE: Found setup.wim in index: 1. Exporting the image to WIM format...
VERBOSE: Extracting boot from ESD to WIM format...
VERBOSE: Found boot.wim in index: 3. Exporting the image to WIM format...
VERBOSE: Extracting install from ESD to WIM format...
VERBOSE: Found install.wim for Pro in index: 8. Exporting the image to WIM format...
VERBOSE: Mounting setup.wim file...
VERBOSE: Mounting install.wim file...
VERBOSE: Formatting USB drive E:...
DriveLetter FriendlyName FileSystemType DriveType HealthStatus OperationalStatus SizeRemaining Size
----------- ------------ -------------- --------- ------------ ----------------- ------------- ----
D BOOT FAT32 Removable Healthy OK 1019.99 MB 1020 MB
E windowsmedia NTFS Removable Healthy OK 113.5 GB 113.6 GB
VERBOSE: USB drive E: is corretly formatted as NTFS.
VERBOSE: Copying Windows Setup files to USB drive E:...
VERBOSE: Unmount Setup WIM...
VERBOSE: Copying Windows boot.wim to USB drive E:...
VERBOSE: Copying Windows install.wim to USB drive E:...
VERBOSE: Copying EFI Files to MSFT_Partition (ObjectId = "{1}\\COMPUTERNAME\root/Microsoft/Win...).DriveLetter...
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 28672-byte response of content type application/octet-stream
VERBOSE: File Name: bootaa64.efi
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 17632-byte response of content type application/octet-stream
VERBOSE: File Name: bootarm.efi
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 19456-byte response of content type application/octet-stream
VERBOSE: File Name: bootia32.efi
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 20736-byte response of content type application/octet-stream
VERBOSE: File Name: bootx64.efi
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 188416-byte response of content type application/octet-stream
VERBOSE: File Name: ntfs_aa64.efi
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 147872-byte response of content type application/octet-stream
VERBOSE: File Name: ntfs_arm.efi
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 180544-byte response of content type application/octet-stream
VERBOSE: File Name: ntfs_ia32.efi
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 175040-byte response of content type application/octet-stream
VERBOSE: File Name: ntfs_x64.efi
VERBOSE: Adding driver directory...
VERBOSE: Searching Dell drivers for Latitude 5440 ...
VERBOSE: Replacing spaces in DriverModel with dashes...
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 319329-byte response of content type application/vnd.ms-cab-compressed
VERBOSE: File Name: delldrivercatalog.cab
VERBOSE: Found Dell driver URL for Latitude-5440 FOLDER12425806M/1/Latitude-5440-X5JF4_Win11_1.0_A11.exe
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 2721910904-byte response of content type application/octet-stream
VERBOSE: File Name: Latitude-5440-X5JF4_Win11_1.0_A11.exe
VERBOSE: Extracting Dell driver Latitude-5440-X5JF4_Win11_1.0_A11.exe to C:\Users\NRAST\AppData\Local\Temp\mctcli\driverpack ...
VERBOSE: Copying Dell driver to E:\drivers\Dell-Latitude-5440...
VERBOSE: Cloning Troubleshooting tools...
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 response of content type text/plain of unknown size
VERBOSE: File Name: Get-AutopilotDiagnosticsCommunity.ps1
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 response of content type text/plain of unknown size
VERBOSE: File Name: Get-WindowsAutopilotInfoCommunity.ps1
VERBOSE: Requested HTTP/1.1 GET with 0-byte payload
VERBOSE: Received HTTP/1.1 response of content type text/plain of unknown size
VERBOSE: File Name: Get-IntuneManagementExtensionDiagnostics.ps1
VERBOSE: Creating autounattend.xml file...
VERBOSE: Using SetupUILanguage: en-us, InputLocale: 0409:00000409, SystemLocale: en-us, UILanguage: en-us, UserLocale: en-us, OSImage: Pro...
VERBOSE: Cleaning up temporary files
Finished Windows Media Creation CLI in: 00:14:05
The last line also tells you how long it took (which of course depends on your Internet speed, admin-device and usb-sticks performance) to download everything and create the usb-drive ;)
Maybe you had it in mind yet, when working in an IT department you often need to handle multiple devices and models. So Ive added a small script, called add-driver.ps1
to the project which only has the part for downloading, exctracting and adding drivers to the usb-drive. This way you can easily add more driverpacks afterwards or if you need other device models you can change it without needing to create the whole usb-stick from scratch.
You also find that script in my Github repo with the name add-driver.ps1. Execute it like this, it also supports Dell
, Lenovo
and HP
like the first script:
.\add-driver.ps1 -Architecture amd64 -UsbDriveLetter "E:" -DriverManufacturer Dell -DriverModel "Latitude-7450" -DriverInjectionType DISM
Because of an Issue
starting with Windows 11 24H2 I´ve implemented a switch to control how you inject drivers.
drivers
where the oem driverpack is stored and applied trough autounattend.xml
-> this doesnt work with 24H2 because Microsoft changed something in the setup.install.wim
.This is what a typical structure for a boot-stick bootloader looks, here using the Rufus bootloader. For this example it was the partition which got the driveletter “D:”.
As you can see, the usb-stick has the windows setup files, within the folder \sources\
you can find boot.wim
and install.wim
. For this example it was the partition which got the driveletter “E:”. … also our custom autounattend.xml
as well as the “Autopilot Troubleshooting” scripts are in the root path of the usb-drive - you can use them with the WIN + F10
trick in OOBE:
And the oem driverpack is here as well, in this example for a Dell Latitude 7450:
This of course only applies when using
-DriverInjectionType AUTOUNATTEND
, as DISM
would inject the drivers in the install.wim
under /sources/
;)
Once you have created your bootstick, simply plug it into a device that needs to be reinstalled with a fresh copy of Windows 11 and boot the device from this usb-stick. The key for changing the boot device depends on your device, often times its F10
, F11
, F12
or DEL
…maybe check for your sepecific device model.
For me this project was a very interessting learning and it will help me with “bare metal” deployment or reinstalling broken devices from different hardware model. It was fun to get deeper insight on how windows setup media tools work and where they get content from. Also it was quiet funny how “easy” I could query Dell
, Lenovo
and HP
for enterprise driverpacks, download them and silenty extract those in a Windows setup media attached with a autounattend.xml
for a fully automated installation where all you need to do is to boot from the usb-stick. This script will help me at my day-to-day tasks and I hope it could help someone else - thats why I published it on Github and wrote this post to fully explain how it works.
If you have feedback, or other ideas that could make this solution even better feel free to add a Comment on LinkedIn or open a Feature Request / Idea Issue on Github - I will have a look into them and think about ideas - or if you want, code it yourself and create a PR ;)
Made with ❤️ by Niklas Rast