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.
username=mdtmount userdomain=bork.internal password=aedb8aeb-6073-446d-96dd-aa993b275741
/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.
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:
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.
[Settings] Priority=Default [Default] DeployRoot=\\bork.internal\system\deployment UserDomain=bork.internal UserID=mdtsvc UserPassword=288ea175-c7b6-44aa-8aa8-27075142cb7f SkipBDDWelcome=YES
[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
mdtsvccredentials 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!