Deploy MDT Litetouch on Linux with TFTPD and Syslinux
No, I would not like to say hello, Cortana.
Nothing is as monotonous, boring, and brain-numbingly automatable as installing Windows, installing applications, joining a domain, and clicking all the right boxes in all the right places. And it’s even worse in the latest versions of Windows 10, where we’re greeted by the condescending robot voice of Halo’s deceptive antagonist artificial intelligence during the OOBE setup phase.
I’ve taken a particular liking to MDT, Microsoft’s solution to the absolute eye-glazing snorefest of configuring a new workstation or server. Not only does it automatically apply an answer file to get past the distorted screaming of your PC speaker, it gets you past almost all of the setup routine, so you can focus on more important things.
In seriousness, I’m a big fan of automation for a number of reasons. Not only can a tool like this save you time, it can also make sure that every machine you deploy is consistent and compliant with the policies of your organization. Can you really trust a human to go through all the correct steps during setup?
The licensing problem
First off, volume licensing is required to run MDT, or modify images in any way. So don’t do this unless your org is set up correctly.
Next is the issue of server licensing. To do this the ‘right’ way a WDS server would be used to host the PXE boot for MDT litetouch deploys. To me, this doesn’t make a ton of sense. There are plenty of free alternatives that don’t require thousands of dollars in licensing, and more importantly aren’t as cumbersome. If you update MDT boot media with new drivers or directives it requires an RDP session into your WDS server to add the new WIM files to the deployment directory, then removing the old version of the boot media from the server. At its best it’s a simple way to run PXE boot on a fairly static environment, and at its worst it’s a waste of precious Standard licenses and a waste of time managing and patching a Windows server.
Using a Linux server to deploy Windows
If that isn’t sacrilegious, then I don’t know what is.
Fundamentally, what we’re doing is mounting the MDT boot images network share to the TFTP boot directory (readonly of course), configuring a simple PXELINUX loader with memdisk, and configuring our DHCP server to point to this tftp location for boot media.
The first step is to spin up a Ubuntu 18.04 (or whatever your flavour is!) virtual machine, give it a static address, and get it up to date.
Setting it up
Next, the needed packages are installed on the system:
sudo apt install tftpd-hpa pxelinux syslinux cifs-utils
Mounting the MDT share
To mount the cifs share containing the MDT content, best practice is to use a service account with as little access as possible. In this case, we will make sure our service account is denied interactive logon, restricted in its logon types, and only allowed network access to the MDT share. Lately I’ve taken to using randomly generated GUIDs as service account passwords.
$pw = New-Guid
New-ADUser -Name mdtmount -SamAccountName mdtmount -AccountPassword:($pw | Convertto-SecureString -AsPlainText -Force) -CannotChangePassword:$true -ChangePasswordAtLogon:$false
Now, we hop on over to the Linux server and set up the mount point.
In the interest of best practices, we’re using a credential file that only root has access to.
/root/.cifs
username=mdtmount
userdomain=bork.internal
password=aedb8aeb-6073-446d-96dd-aa993b275741
Then the /etc/fstab
is set up such that the MDT directory will mount automatically.
//bork.internal/system/deployment/boot /var/lib/tftpboot/pxelinux/boot cifs _netdev,user=mdtsvc,credentials=/root/.cifs 0 0
Note that this is a DFS namespace in the example. Depending on domain level and the features enabled on the share, it may be required to configure some additional Kerberos parameters for it to work reliably.
PXELINUX configuration
First, we move the PXELINUX boot files to the TFTP directory.
cp /usr/lib/PXELINUX/pxelinux.0 /var/lib/tftpboot/pxelinux
cp /usr/lib/syslinux/modules/efi64/[menu.c32 ldlinux.c32 libutil.c32] /var/lib/tftpboot/pxelinux
cp /usr/lib/syslinux/memdisk /var/lib/tftpboot/pxelinux
Second, we create a simple config file to boot into the LiteTouch boot media.
DEFAULT menu.c32
MENU TITLE PXE Boot Menu
MENU AUTOBOOT Starting local system in # seconds
label bootlocal
MENU LABEL Boot local device
MENU DEFAULT
LOCALBOOT 0
TIMEOUT 100
TOTALTIMEOUT 9000
label mdt_litetouch
menu label [MDT] LiteTouch PE
KERNEL memdisk
INITRD boot/LiteTouchPE_x64.iso
APPEND iso raw
DHCP Server Config
With the files in place, the DHCP server scope options for the Imaging VLAN are set:
Option | Description | Value |
---|---|---|
066 | TFTP Server | 10.1.10.30 |
067 | File Name | pxelinux/pxelinux.0 |
MDT Share Config
Of course, the standard principles apply for hardening an MDT deployment.
- File share securables:
- Remove Authenticated Users read access
- Add mdt client service accounts with read only access
- AD securables:
- Lock down service accounts
- Delegated access for domain join service account in ‘holding tank’ OU
With that said, we configure the MDT share to generate ISO images (for x64 only) and set up the config files.
Bootstrap.ini
[Settings]
Priority=Default
[Default]
DeployRoot=\\bork.internal\system\deployment
UserDomain=bork.internal
UserID=mdtsvc
UserPassword=288ea175-c7b6-44aa-8aa8-27075142cb7f
SkipBDDWelcome=YES
CustomSettings.ini
[Settings]
Priority=Default
Properties=MyCustomProperty
[Default]
_SMSTSORGNAME=BORK!
OSDComputerName=ws-#right(replace(replace("%SerialNumber%"," ",""),"-",""),10)#
OSInstall=Yes
SkipCapture=YES
SkipAdminPassword=YES
SkipProductKey=YES
SkipComputerBackup=YES
SkipBitLocker=NO
TimeZoneName=Eastern Standard Time
SkipLocaleSelection=YES
SkipTaskSequence=NO
SkipRoles=NO
SkipRoleDisplay=NO
SkipTimeZone=YES
JoinDomain=bork.internal
DomainAdmin=mdtjoin
DomainAdminDomain=bork.internal
DomainAdminPassword=98600de8-e53e-4576-bf86-2f3c80061ce5
MachineObjectOU=OU=Holding Tank,DC=bork,dc=internal
Using this config file template, our deployments will automatically be named after the service tag, serial number, or UUID, then join the domain inside the ‘Holding Tank’ OU, where an administrator can review the deployment and move the machine object to the correct location within their hierarchy.
Bringing it all together
The process for deploying a new machine will look like this:
- Computer boots to UEFI network stack
- Computer receives TFTP information from DHCP server
- Computer loads PXELINUX boot screen
- Technician selects MDT boot from the menu
- Computer loads ISO into memdisk before boot:
- Computer requests ISO file from Linux server
- Linux server loads ISO file from DFS/File Share
- Computer boots into WinPE and uses
mdtsvc
credentials from the bootstrap config to access the network share directly, and loads configuration settings and task sequence info. - Technician selects a deployment task sequence, either accepting the automatically configured hostname or entering a custom one, and starts the deployment.
A couple coffees later, the deployment is done exactly to the spec with little intervention from either technicians or administrators, and most importantly, Microsoft doesn’t get an extra dime from your tight budget!