MDT

The ol' 'Quick & Dirty' method - Image provided by Max Pixel

MDT Performance Boost Part 2

I need all the help I can get in terms of speeding up the build & capture process so in addition to the steps mentioned in my previous post, I use this “one weird trick” (smh) to help speed up the actual WIM capturing or generation process.

Speedup Process Overview

  • Copy the base install.wim of your B&C OS to your capture location
  • Rename the .WIM to something meaningful like 1809_install.wim
  • Use that same name for the WIM file name for the capture
  • During B&C your image will be added to the existing WIM
  • Split the captured image into it’s own .WIM
  • Delete the index

Baseline Testing (Optional)

This isn’t required but it’s the only way to validate that the speedup procedure actually works.   In order to do that, you’re just going to start by performing a regular Build & Capture using the normal process to see how long the actual .WIM capture process takes.  This will be our baseline number.  In my test lab, after running several B&C’s I’m finding the capture process takes anywhere from 35 to 40 minutes in my lab.

MDTSpeedup2-001

Apply the Speedup Procedure

To keep things simple, let’s say we’re working on capturing an 1809 image.

Copy the stock 1809 install.wim to your Captures directory and rename it to something meaningful like 1809_install.wim.

Check the details of the WIM you just copied:

dism /get-wininfo /image:"\\MDTServer\DeploymentShare$\Captures\1809_install.wim"

Deployment Image Servicing and Management tool
Version: 10.0.14393.0

Details for image : \\MDTServer\DeploymentShare$\Captures\1809_install.wim

Index : 1
Name : Windows 10 Education
Description : Windows 10 Education
Size : 14,356,142,049 bytes

Index : 2
Name : Windows 10 Education N
Description : Windows 10 Education N
Size : 13,548,111,095 bytes

Index : 3
Name : Windows 10 Enterprise
Description : Windows 10 Enterprise
Size : 14,356,212,795 bytes

Index : 4
Name : Windows 10 Enterprise N
Description : Windows 10 Enterprise N
Size : 13,548,004,622 bytes

Index : 5
Name : Windows 10 Pro
Description : Windows 10 Pro
Size : 14,356,028,734 bytes

Index : 6
Name : Windows 10 Pro N
Description : Windows 10 Pro N
Size : 13,547,960,587 bytes

Index : 7
Name : Windows 10 Pro Education
Description : Windows 10 Pro Education
Size : 14,356,071,811 bytes

Index : 8
Name : Windows 10 Pro Education N
Description : Windows 10 Pro Education N
Size : 13,548,039,957 bytes

Index : 9
Name : Windows 10 Pro for Workstations
Description : Windows 10 Pro for Workstations
Size : 14,356,106,696 bytes

Index : 10
Name : Windows 10 Pro N for Workstations
Description : Windows 10 Pro N for Workstations
Size : 13,548,075,292 bytes

Index : 11
Name : Windows 10 Enterprise for Virtual Desktops
Description : Windows 10 Enterprise for Virtual Desktops
Size : 14,356,177,402 bytes

The operation completed successfully.

Now perform a B&C to get the updated timing details. In my lab, I’m seeing it take about 9 minutes*.

MDTSpeedup2-002

Once the .WIM is created, verify the new index was created:


dism /get-wininfo /image:"\\MDTServer\DeploymentShare$\Captures\1809_install.wim"

Deployment Image Servicing and Management tool
Version: 10.0.14393.0

Details for image : \\MDTServer\DeploymentShare$\Captures\1809_install.wim

Index : 1
Name : Windows 10 Education
Description : Windows 10 Education
Size : 14,356,142,049 bytes

Index : 2
Name : Windows 10 Education N
Description : Windows 10 Education N
Size : 13,548,111,095 bytes

Index : 3
Name : Windows 10 Enterprise
Description : Windows 10 Enterprise
Size : 14,356,212,795 bytes

Index : 4
Name : Windows 10 Enterprise N
Description : Windows 10 Enterprise N
Size : 13,548,004,622 bytes

Index : 5
Name : Windows 10 Pro
Description : Windows 10 Pro
Size : 14,356,028,734 bytes

Index : 6
Name : Windows 10 Pro N
Description : Windows 10 Pro N
Size : 13,547,960,587 bytes

Index : 7
Name : Windows 10 Pro Education
Description : Windows 10 Pro Education
Size : 14,356,071,811 bytes

Index : 8
Name : Windows 10 Pro Education N
Description : Windows 10 Pro Education N
Size : 13,548,039,957 bytes

Index : 9
Name : Windows 10 Pro for Workstations
Description : Windows 10 Pro for Workstations
Size : 14,356,106,696 bytes

Index : 10
Name : Windows 10 Pro N for Workstations
Description : Windows 10 Pro N for Workstations
Size : 13,548,075,292 bytes

Index : 11
Name : Windows 10 Enterprise for Virtual Desktops
Description : Windows 10 Enterprise for Virtual Desktops
Size : 14,356,177,402 bytes

Index : 12
Name : W10_1809_Entx64
Description : 
Size : 24,935,992,683 bytes

The operation completed successfully.

Success!

 

*So, What’s the Catch?

Alright – so maybe I cut a corner or two.

I’ll admit, it might not be helpful to have one giant .WIM with 12+ indexes, so you’d probably want to export that newly created index to it’s own .WIM:

dism /export-image /sourceimagefile:\\MDTServer\DeploymentShare$\Captures\1803_install.wim /sourceindex:12 /destinationimagefile:\\MDTServer\DeploymentShare$\Captures\1803_bnc.wim

I find this process takes about 90 seconds putting us at about 10m30s.

And if you’re doing that you might also want to delete the new index you created in the original install.wim:

dism /delete-image /imagefile:\\MDTServer\DeploymentShare$\Captures\1803_install.wim /index:12

This process takes about 2 seconds putting us at about 10m32s.

On the surface, capturing or generating a WIM in 8-10 minutes sounds like some appreciable gains but this is where the corner cutting begins.

Like a fine wine, I find this process gets [somewhat] better with age:

  • Without any funny business my first capture typically takes anywhere from 35 to 40 minutes.
  • When I use this technique I might shave 5-10 minutes off my first capture depending on what’s in there.  It’s something but not significant.
  • However, when I do my second (third, fourth etc.) capture with this technique – like when I’m doing another B&C to include this/last month’s patches and/or updated software etc. – that’s when I begin to appreciate the speed difference and now the actual WIM capture/generation process takes ~8 to ~11 minutes.

After the first big capture – thick image with everything in it – that usually becomes it’s own .WIM and the differential .WIMs are appended to it.  From here we can either export those differential indexes into their own .WIMs or we leave them in the ‘master’ .WIM which allows for easy regression to a previous ‘version’ by just using a lower number index in the Task Sequence.

In Conclusion

I don’t think this is ground breaking and there are some caveats – specifically being that you have go through one capture before you can truly realize the benefits – but like I said, I need all the help I can get so every little bit counts!

So hopefully this “one weird trick” helps you 🙂

Good Providence!

Advertisements

MDT Performance Boost Part 1

I need all the help I can get in terms of speeding up the build or build & capture process so I leverage the available hardware to help speed things up.  But before we get to it, let’s give credit where it’s due!

Recommended Reading

I can’t recall exactly when I first discovered those posts, but I didn’t have robust hardware at the time; In fact, I didn’t have SSD’s but I did have access to servers with significant amounts of RAM which is why this was so attractive.  I do want to warn you however that you should curb your expectations as your mileage may vary.

Speedup Process Overview

  • Use a RAM Disk or SSD
  • Give your B&C VM plenty of resources

It’s all About the Hardware

I’m blessed in that I do a lot of my development work on fairly robust hardware:

  • At home: Dell PowerEdge R710 with Dual E5649’s, 192GB of RAM and 8x146GB 15K SAS Drives in a RAID 10 configuration
  • On the go: Lenovo W541 i7-4810MQ with 32GB of RAM, 2x Sandisk Extreme Pro SSD’s in RAID 1 for dev work (VM’s, MDT etc.)
  • At work: Lenovo P500 E5-1620 v3, 128GB of RAM, 2x SSD’s in RAID 1 for dev work (VM’s, MDT etc.)

All of this allows me to leverage the additional cores and RAM to squeeze a bit of extra performance in build & capture scenarios.

Hyper-V Host Configuration

Because my host has gobs of RAM, I create a RAM Disk (or RAM Drive if you prefer) that is ultimately used to store ‘build & capture’ virtual machine’s .VHDX.  I typically allocate 60GB becuase I’m testing full load out scenarios but you can get away with considerably less for more bare bones builds.  There are a variety of RAM Disk solutions out there including, but not limited to:

  • ATI Radeon RAMDisk / DataRAM
  • ImDisk
  • MSI RAMDisk
  • SoftPerfect RAM Disk
  • StarWind RAM Disk

I landed on the no-frills StarWind RAM Disk product because it’s been maintained over the years and at the time of writing – as well as for the past several years – StarWind’s RAM Disk product has made available free of charge, doesn’t have any limitations I’m aware of and most importantly it just works.  Oh – and by “free of charge” I mean yes it doesn’t cost any money but they do ask that you offer up your personal details (name, email address etc.) “to accommodate your requests, keep in touch with you, and offer a better customer experience.

I know I know, this may be a pain point for you but this is a requirement as the download link comes via email.  I can say that I personally can’t remember the last time StarWind emailed me so I feel comfortable offering it up.  If you don’t like sacrificing personal details, consider the other products on the market most of which offer additional features like being able to save and restore the state of your RAM disk.

I do want to point out that this only works if you have excess RAM to spare.  If you don’t have enough RAM to create a RAM Disk for VM use, the next best thing would be to add an SSD to your machine or swap your mechanical drive for an SSD.  In a pinch I suppose you could use a large (64GB+) microSD/SD card or USB 3.0 thumb drive, but I don’t recommend that as a long term solution.  Just because you can doesn’t mean you should though! (^_^)

Virtual Machine Configuration

When creating a ‘build & capture’ VM, I typically give it 4 virtual processors and 8GB of RAM.  I’ve done B&C’s with 1 & 2 virtual processors an 2-4GB of RAM and the performance isn’t great.  You might be asking yourself:

Why not use 8 virtual processors and 16GB of RAM?

You absolutely can, but there is a point where the performance increase levels off at which point the resource cost outweighs the benefit. (i.e.: you’re not making good use of your resources.)  This 4 virtual CPU and 8GB of ram has worked well for me so far which is why I haven’t bothers measuring the performance benefits of 4+ virtual processors and 8+ GB of RAM.  If you’re feeling up to the task, I’ll leave you to do that and you might as well play around with the scheduler to ensure that B&C machine has the highest priority.

Putting It All Together

Installing StarWind RAM Disk

Download & install StarWind RAM Disk – it’s very much double click the EXE and Next, Next, Next to completion.

Configuring StarWind RAM Disk

Launch RAM Disk

StarWind_RAMDisk001

Click ‘Add Device’ to create a new RAM Disk and configure it to your liking

StarWind_RAMDisk002

The process may appear to hang while it creates the RAM Disk.  Go refill you cup of water or visit the loo and it’ll be done by the time you get back.

StarWind_RAMDisk003

When it’s complete you’ll see the new device and you should receive a notification

StarWind_RAMDisk004StarWind_RAMDisk005

Configuring the RAM Disk

After creation the new RAM disk will be offline so fire up Disk Management (or Server Manager whatever) to finish configuring it:

  1. Online the disk
  2. Initialize the disk
  3. Select GPT (or MBR if you prefer)
  4. Create a new simple volume
  5. Assign it a letter – I like to use R: for RAM Disk
  6. Use the NTFS file system
  7. OPTIONAL: Set the volume label – I like to use RAMDisk
  8. Select quick format

StarWind_RAMDisk006

Configuring Your B&C VM

Now that the disk is ready for use, it’s time to configure your B&C VM

If you don’t already have a B&C VM

  1. Create a new BnC VM
  2. Give it at least 8GB of RAM
  3. When asked where to place the .VHDX, change the path to the RAM disk
    • StarWind_RAMDisk007
  4. Once finished, edit the VM settings and give it at least 4 virtual processors

If you already have a BnC VM

  1. Edit the VM settings
  2. Give it at least 2 virtual processors; 4 if you can spare it
  3. Give it at least 4GB of RAM; 8 if you can spare it
  4. When asked where to place the .VHDX, change the path to the RAM disk
    • StarWind_RAMDisk008
    • StarWind_RAMDisk009
    • StarWind_RAMDisk010

That’s it – now you’re cooking with gas!  Start your VM and test an image.

In Closing

When I initially did this, I did notice an appreciable decrease in machine build out time.  We’re not talking going from 60 minutes to 20 minutes, but it was a noticeable improvement nonetheless.  If I can improve my build times by up to 15-25% then I’ll take it!  Now that we have a mostly automated build process, speeding it up it just gravy allowing for more B&C’s throughout the day.

In any event, I hope you find this tip as useful as I do!

Good Providence to you!

MDT Tutorial Part 12: Wrap Up

Living Table of Contents

What These Guides Are:
A guide to help give you some insight into the MDT imaging & troubleshooting process in general.

What These Guides Are Not:
A guide to create a one-size fits all solution that fixes all the issues you’re ever going to encounter.

Why Bother with My Tutorials?

You totally don’t have to take my word on it!  I’m not world-reknowned like others listed on the Resources page – heck I’m not even county-reknowned so you totally should scrutinize the content and provide me with any constructive criticism you may have. 🙂

However I’ve learned from experience, as well as from others in the circles I travel in, that although turn-key solutions are great, once implemented those who implemented them are not fully equipped to maintain the environment.

Please do not misconstrue what I’m saying here: There is nothing wrong with the turn-key solutions out there!  It’s simply that we’re not all at the same level from a technical perspective and we all have knowledge gaps.  But it’s that combination that makes it challenging for some to support those turn-key solutions.

For me anyway I find that having a good base and some reference points better equips me for the road that lies ahead.  And when something breaks it’s an excellent opportunity to review my depth of knowledge on the subject to troubleshoot my way back into a functioning state.  But that’s me and it may not be you.  Maybe you’re just some savant and it comes naturally.

If you were brave enough to go through this process and successfully built, captured & deployed images, then you should have sufficient functional knowledge to efficiently use the turn-key solution below.

More Labs & Test Environments from Microsoft

Turn-Key Solution from Microsoft: Microsoft 365 Powered Device Lab Kit (Formerly Windows 10 Deployment and Management Lab Kit)

The Microsoft 365 powered device lab kit (formerly Windows 10 Deployment and Management Lab Kit) is a complete pre-configured virtual lab environment including evaluation versions of:

  • Windows 10 Enterprise, version 1803 (Windows 10 April 2018 Update)
  • System Center Configuration Manager, version 1802
  • Windows Assessment and Deployment Kit for Windows 10, version 1803
  • Microsoft Deployment Toolkit
  • Microsoft Application Virtualization (App-V) 5.1
  • Microsoft BitLocker Administration and Monitoring 2.5 SP1
  • Windows Server 2016
  • Microsoft SQL Server 2014
  • Connected trials of:
    • Office 365 Enterprise E5
    • Enterprise Mobility + Security

The best part is that it also includes illustrated step-by-step lab guides to take you through multiple deployment and management scenarios, including:

Servicing

  • Windows Analytics Update Compliance
  • Servicing Windows 10 with Configuration Manager
  • Servicing Office 365 ProPlus with Configuration Manager

Deployment and management

  • Modern Device Deployment
  • Modern Device Management with AutoPilot
  • Modern Device Co-Management
  • Office 365 ProPlus Deployment
  • BIOS to UEFI Conversion
  • Modern Application Management with Intune
  • Enterprise State Roaming
  • Remote Access (VPN)

Security

  • Windows Information Protection
  • Windows Defender Advanced Threat Protection
  • Windows Defender Application Guard
  • Windows Defender Application Control
  • Windows Defender Antivirus
  • Windows Defender Exploit Guard
  • Windows Hello for Business
  • Credential Guard
  • Device Encryption (BitLocker)
  • Remote Access (VPN)

Compatibility

  • Windows App Certification Kit
  • Windows Analytics Upgrade Readiness
  • Browser Compatibility
  • Windows App CertificationKit
  • Desktop Bridges

 

This is an amazing kit because of its holistic approach to helping IT Pros transition to the ‘Modern Desktop’.  As such it’s a hefty download and the hardware requirements are steep.

Turn-Key Solution from Johan Arwidmark: Hydration Kit

Johan has been churning out Hydration Kits since as far back as ConfigMgr 2007 SP2 and MDT 2010 so he’s one of the top 5 go-to’s for this sort of thing.

From the author:

This Kit builds a complete ConfigMgr CB 1702, and ConfigMgr TP 1703, with Windows Server 2016 and SQL Server 2016 SP1 infrastructure, and some (optional) supporting servers. This kit is tested on both Hyper-V and VMware virtual platforms, but should really work on any virtualization platform that can boot from an ISO. The kit offers a complete setup of both a primary site server running ConfigMgr Current Branch v1702 (server CM01, as well as a primary site server running ConfigMgr Technical Preview Branch v1703 (server CM02). You also find guidance on upgrading current branch platform to the latest build.

There’s plenty of documentation in the link:

https://deploymentresearch.com/Research/Post/580/Hydration-Kit-For-Windows-Server-2016-and-ConfigMgr-Current-Technical-Preview-Branch

 

Turn-Key Solution from Mikael Nystrom: Image Factory for Hyper-V

Mikael has been working on this for at least 2 years and is another in the top 5 go-to’s for this sort of thing.

From the author:

The image factory creates reference images using Microsoft Deployment Toolkit and PowerShell. You run the script on the MDT server. The script will connect to a hyper-v host specified in the XML file and build one virtual machine for each task sequences in the REF folder. It will then grab the BIOS serial number from each virtual machine, inject it into customsettings.ini, start the virtual machines, run the build and capture process, turn off the virtual machine and remove them all.

There’s some great documentation here but plenty to browse through in the link:

https://github.com/DeploymentBunny/ImageFactoryV3ForHyper-V

 

Turn-Key Solution from Mike Galvin: Image Factory for Microsoft Deployment Toolkit

I happened upon this by accident but I like how straight forward it appears to be.

From the author:

Recently I’ve been looking into automating my image build process further using PowerShell to create an Image Factory of sorts. There are other similar scripts that I’ve found online, but I like the relatively simple and straightforward method I’ve developed below. If like me you’re looking to automate your image build process so that you can have a fully up-to-date image library after patch Tuesday each month, then this may be for you.

This link is the original post where the script is introduced but I strongly urge you to start with the below link then work your way backwards from there.

https://gal.vin/2017/08/26/image-factory/

 

Turn-Key Solution from Coretech: Image Factory

This unfortunately is not something I can link without burning a bridge.  This solution is only obtainable from [select (?)] Coretech training classes or simply if Kent Agerlund likes you.  It’s conceptually similar to many others here, relying on Hyper-V to spin up VM’s, start them, boot, start a specific build & capture task sequence, run through the task sequence then destroy the VM.  Done.

 

In Closing

As you can see there are plenty of training, lab and turn key imaging solutions out there but to quote Browning:

Image the whole, then execute the parts
          Fancy the fabric
Quite, ere you build, ere steel strike fire from quartz,
          Ere mortar dab brick!

In other words, get the total picture of the process; and I argue there are two ways of doing that: with a telescope and a microscope.

Start with the telescope to look at all of it from thirty-thousand feet and you’ll see almost all these require a dab of elbow grease to get going.  In fact, most make assumptions about the environment as well as a certain amount of proficiency with the various technologies being used: PowerShell, MDT, Hyper-V, SCCM, Active Directory etc.

In the same vain that I’d rather learn to drive a manual transmission on an old beater car before I jump into an STI, GT3 RS, or <insert other absurdly expensive manual transmission vehicle here> , it makes more sense to have a slightly more-than-basic understanding of how the technology works before diving in head first.

Good Providence to you!

MDT Tutorial Part 11: Troubleshooting Part 7: Non-Fatal OSD Errors & Warnings

Living Table of Contents

What These Guides Are:
A guide to help give you some insight into the troubleshooting process in general.

What These Guides Are Not:
A guide to fix all issues you’re going to encounter.

We’re going to role-play a bunch of scenarios and try to work through them.  Remember in math where you had to show your work?  Well, what follows is like that which is why this post is [more than] a [little] lengthy.

 

[Some] Non-Fatal OSD Errors & Warnings:

  • No networking adapters found, the network drivers for your device ar enot present

  • An invalid SLShareDynamicLogging value of <path> was specified

  • Unable to Create WebService class

You made a bunch of changes to your lab environment, tested the CS.INI before imaging but after performing a B&C you see these errors/warnings:

Yikes a bunch of errors here!

Yikes a bunch of errors here!

  • No networking adapters found, The network drivers for your device are not present
  • An invalid SLShareDynamicLogging value of \\ITF1MDT01\DeploymentShare$\TSLogs\BnC-22404895 was specified.
  • 2x Unable to create WebService class

To be sure, you delete the logs for that machine, run another B&C and confirm the BDD.log was indeed present and getting populated.  But at the end of the second B&C you received the same error and inspected the BDD.log further:

Troubleshoot-031.PNG

Starting from the top of the log:

  • The”Apply Windows PE” Task Sequence step completed successfully as evidenced by “Event 41001 sent: LTIApply processing completed successfully.”
    .
  • Then the “Add mass storage drivers to sysprep.inf for XP and 2003” Task Sequence step completed successfully as evidenced by “Event 41001 sent: ZTIDrivers processing completed successfully.”
    • Furthermore, the process is able to reach and write to \\ITF1MDT01\DeploymentShare$\TSLogs\BnC-22404895 so we know it was good at this point.
      This is important!
      .
  • After that the “Execute Sysprep” Task Sequence step completed successfully as evidenced by “Event 41001 sent: LTISysprep processing completed successfully.”
    • And that process was also able to reach and write to \\ITF1MDT01\DeploymentShare$\TSLogs\BnC-22404895.
      This is also important!
      .
  • Then we get to the “Apply Windows PE (BCD)” Task Sequence Step and almost as soon as it starts we see our errors:
    • No networking adapters found, The network drivers for your device are not present
    • An invalid SLShareDynamicLogging value of \\ITF1MDT01\DeploymentShare$\TSLogs\BnC-22404895 was specified.

From here you hypothesize that it’s the sysprep process that is creating this problem.
And like a wise man frequently tells me: We gotta peel this onion!

  • Found the error text in ZTIUtility.vbs: “An invalid SLShareDynamicLogging value”
  • Just above the error code it, two functions are called:
    • ValidateConnection
    • VerifyPathExists
      .
  • ValidateConnection
    • Is what drops the “Validating connection to” text in the log
    • Calls the ValidateNetworkConnectivity function which
      • Executes the query ​select * from win32_NetworkAdapter where Installed = true and adaptertypeid = 0" and evaluates the count of the results
      • If the result count is 0, the function exits after dropping “No networking adapters found, The network drivers for your device are not present” text in the log.
        .
  • VerifyPathExists checks the path of SLShareDynamicLogging, creating the directory if missing.  We know the directory exists because the files are where we expect them to be.
    .
  • Finally, the line that generates the “An invalid SLShareDynamicLogging” log entry is part of an if block, and is generated if the directory doesn’t exist.

With a better understanding of the process, we may have a good idea as to what might be happening:

  1. everything’s fine up until sysprep
  2. sysprep might be removing the NIC drivers and thus the adapter doesn’t work
  3. when the ‘Apply Windows PE (BCD)’ Task Sequence step (LTIApply.wsf) is executed immediately after sysprep, it fails to connect to the share because of Step 2 above
  4. once in WinPE the NIC is once again fully functional so everything works as expected

But what about the two Unable to create WebService class warning?  Thinking back to the recent changes you made, one of them was enabling Monitoring.   A little sleuthing might take you to a post by Michael Niehaus on Troubleshooting MDT 2012 Monitoring via a TechNet response by Johan Arwidmark.

After going through the guide, it still doesn’t work so you disable Monitoring, reimage, and the error goes away.  You re-enable Monitoring, image again, get the same result.

The good news is you’ve confirmed Monitoring is “to blame” for those errors.

A closer inspection of the BDD.log shows it’s part of the same LTIApply step it and that’s when it clicks: If there’s no network connectivity, there’s no way for the WebService to succeed.

At the very least, this is a plausible cause.

So for these errors and warnings, it probably “is what it is” and likely not that big of a deal in the grand scheme of things.

FWIW: I can reproduce this behavior with MDT8443 & ADK 1703 on Gen 2 and Gen 1 VM’s using both the Network Adapter and Legacy Network Adapter.  : (

Is it Possible to Fix All of These Errors?

Probably – in fact I’m fairly certain I have an older lab environment where I do not have this problem.  But there’s also something to be said about the return on investment and the law of diminishing returns.

If I can consistently reproduce something, and it really does create problems, I personally believe there’s value in looking into further.  It may be a typo or faux pas on my part or perhaps a valid ‘bug’ for a certain scenarios.

If it’s a one-off, something I see one in 30, it may not be worth investing a significant amount of time & effort for so little reward.

Copypasta Closing

Hopefully these examples will help give you an idea of the overall troubleshooting process.  Most of the time the problems you’ll encounter will be caused by a typso, order of operations or a ‘known issue’ that requires a specific process to be followed.

As you make changes to your environment, here’s what I recommend:

  • Be diligent about keeping a change log so you can easily backtrack
  • Backup your CS.INI or Bootstrap.ini before you make any changes
  • Backup your ts.xml or unattend.xml (in DeploymentShare\Control\TaskSequenceID) before you make any changes
  • Introduce small changes at time with set checkpoints in between and set milestones markers where you backup core files (e.g cs.ini bootstrap.ini ts.xml unattend.xml etc) to help minimize frustration troubleshooting.

And if when you do run into some turbulence, upload relevant logs (at least smsts.log but be prepared to submit others depending on the issue) to a file sharing service like OneDrive, post on TechNet then give a shout to your resources on Twitter.

Good Providence to you!

MDT Tutorial Part 11: Troubleshooting Part 6: Unable to mount the WIM, so the update process cannot continue

Living Table of Contents

 

What These Guides Are:
A guide to help give you some insight into the troubleshooting process in general.

What These Guides Are Not:
A guide to fix all issues you’re going to encounter.

We’re going to role-play a bunch of scenarios and try to work through them.  Remember in math where you had to show your work?  Well, what follows is like that which is why this post is [more than] a [little] lengthy.

Unable to mount the WIM, so the update process cannot continue

When updating your deployment share it fails almost immediately with error Unable to mount the WIM, so the update process cannot continue.

This slideshow requires JavaScript.

Error Text:


=== Making sure the deployment share has the latest x86 tools ===

=== Processing LiteTouchPE (x86) boot image ===

Building requested boot image profile.
Determining if any changes have been made in the boot image configuration.
No existing boot image profile found for platform x86 so a new image will be created.
Calculating hashes for requested content.
Changes have been made, boot image will be updated.
Windows PE WIM C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\en-us\winpe.wim will be used.
Unable to mount the WIM, so the update process cannot continue.

=== Completed processing platform x86 ===

=== Making sure the deployment share has the latest x64 tools ===

=== Processing LiteTouchPE (x64) boot image ===

Building requested boot image profile.
Determining if any changes have been made in the boot image configuration.
No existing boot image profile found for platform x64 so a new image will be created.
Calculating hashes for requested content.
Changes have been made, boot image will be updated.
Windows PE WIM C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us\winpe.wim will be used.
Unable to mount the WIM, so the update process cannot continue.

=== Completed processing platform x64 ===

=== Processing complete ===

You might try a variety of things like:

  • Use DISM to get-wiminfo to confirm the WIMs are OK
  • Bounce the MDT machine
  • Perform a repair installation of the ADK
  • Use DISM to mount the WIM manually and you get an error 577

We talked about this in Part 2 : Did you remember to patch the ADK?  🙂

Copypasta Closing

Hopefully these examples will help give you an idea of the overall troubleshooting process.  Most of the time the problems you’ll encounter will be caused by a typso, order of operations or a ‘known issue’ that requires a specific process to be followed.

As you make changes to your environment, here’s what I recommend:

  • Be diligent about keeping a change log so you can easily backtrack
  • Backup your CS.INI or Bootstrap.ini before you make any changes
  • Backup your ts.xml or unattend.xml (in DeploymentShare\Control\TaskSequenceID) before you make any changes
  • Introduce small changes at time with set checkpoints in between and set milestones markers where you backup core files (e.g cs.ini bootstrap.ini ts.xml unattend.xml etc) to help minimize frustration troubleshooting.

And if when you do run into some turbulence, upload relevant logs (at least smsts.log but be prepared to submit others depending on the issue) to a file sharing service like OneDrive, post on TechNet then give a shout to your resources on Twitter.

Good Providence to you!

MDT Tutorial Part 7: Customizing Base MDT Template & ADK WinPE Template WIM

Living Table of Contents

 

Totally Optional NOT Required!

Nothing in this post is required for following along.  It’s merely here to make you aware that this level of customization is possible.  Think of this as an extension of Part 6.

Customizing the MDT Template

When you create a new Deployment Share a set of files and folders are populated in the desired location.  This isn’t generated on the fly from thin air but rather pulled from a template which can be found here:


C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution

If for whatever reason you find yourself constantly creating deployment shares, you can modify this template to include your customizations:

  • Pre-configured CustomSettings.ini
  • Pre-configured Bootstrap.ini
  • Modifications to out-of-box scripts
    • This is a no no to be honest so I recommend avoiding that at all costs.
      If you must, make sure you backup the original file(s).
  • Including your own custom scripts

A good example of this would be making sure that DaRT was an option for any newly created deployment shares.  To do that, add the appropriate architecture DaRT .CABs into the appropriate directories below


C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64

C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x86

Once you make your changes to the ‘template’, create a new Deployment Share and you’ll see all of your customizations.

Note: Although you could include a pre-built bootable .ISO, it’s not ideal as it would be hard-coded to look at DeploymentShareA not NewDeploymentShareB requiring you to update the deployment share anyway.

Customizing WinPE Templates

Similarly you can also customize the base WinPE .WIM file by editing the winpe.wim file here:


C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us

C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\en-us

Make a copy of the existing .WIM file


Copy-Item -Path "${env:ProgramFiles(x86)}\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us\winpe.wim" -Destination "${env:ProgramFiles(x86)}\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us\winpe.wim.orig"

Create a temporary mount directory & mount the .WIM


New-Item -Path "$env:SystemDrive\tmpDISMMount" -Type Directory

dism /mount-wim /wimfile:"${env:ProgramFiles(x86)}\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us\winpe.wim" /index:1 /mountdir:$env:SystemDrive\tmpDISMMount

Make your changes to the mounted .WIM


Copy-Item -Path "\\MDTServer\DeploymentShare$\Boot\ExtraFiles\amd64" -Destination "$env:SystemDrive\tmpDISMMount" -Recurse

Commit the changes


dism /Commit-Wim /MountDir:$env:SystemDrive\tmpDISMMount

Unmount the .WIM


dism /Unmount-Wim /MountDir:C:\test\offline /commit

Repeat for the x86 architecture

Why Should I Even Bother?

Paraphrasing Stephen Owen of FoxDeploy.com: TO solve the REAL problems!  By now, you’ve probably had to use CMTrace in WinPE a few times, and each time you launch it, you have to answer that ridiculous question:

Do you want to make this program the default viewer for log files?

Mike Terrill posted some very easy to follow instructions on his site, to solve this problem that has plagued many of us.

The process is fairly easy, and I altered Mike’s instructions for the MDT audience.

  1. Create DISM Mount Directory like:
    mkdir C:\tmpDISMMount
  2. Mount your winpe.wim from an elevated command prompt:
    dism /mount-wim /wimfile:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us\winpe.wim" /index:1 /mountdir:C:\tmpDISMMount
  3. Load the DEFAULT registry hive from the WinPE image:
    reg load HKU\winpe C:\tmpDISMMount\Windows\System32\config\default
  4. Create the entries needed to suppress that annoying pop up box:
    reg add HKU\winpe\Software\Classes\.lo_ /ve /d Log.File /f
    reg add HKU\winpe\Software\Classes\.log /ve /d Log.File /f
    reg add HKU\winpe\Software\Classes\Log.File\shell\open\command /ve /d "\"X:\Windows\System32\CMTrace.exe\" \"%1\"" /f
  5. Unload the WinPE registry hive:
    reg unload HKU\winpe
  6. Unmount the WIM file and commit the changes:
    dism /unmount-wim /mountdir:C:\tmpDISMMount /commit
  7. Repeat the process with the x86 media in “C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\en-us\winpe.wim”

In Closing

This is a good little nugget to keep in mind.  Is this everything you can do?  No, just scratching the surface.  Remember, the objective of this tutorial is to just help you get started and get those creative juice flowing.

Just remember that every time a new MDT build or ADK is released, you’ll have to re-do these customizations for the new environment.  I’d recommend creating a script to do these customizations for you and keep good notes in the script to justify why you did it so you can easily ‘rebuild’ in the future.  But before you do anything, jump on Twitter or the TechNet forums to seek guidance; chances are someone else has already overcome the challenge you’re facing so there’s no need to recreate the wheel.

While you decide whether or not you want to do this, I bid you Good Providence!

MDT Tutorial Part 5: Bootstrap.ini

Living Table of Contents

 

Today’s Agenda:

  • Bootstrap.ini Overview
  • Facilitating Authentication
  • Skipping the Welcome Screen
  • Putting it All Together

Recommended Reading

Bootstrap.ini Overview

The BootStrap.ini is similar to the CustomSettings.ini in that the format, structure and processing logic is the same.  The major difference is mainly that the Bootstrap.ini is processed first and once when you boot into WinPE.  The CustomSettings.ini on the other hand is processed after the Welcome screen and at various points during the Task Sequence.

Just like the CustomSettings.ini, the Bootstrap.ini is accessible two ways:

  1. Via the ‘Edit Bootstrap.ini’ button on the ‘Rules’ tab of the Deployment Share properties.
  2. Via the Bootstrap.ini in the Control subdirectory of your Deployment Share, for example:
    1. C:\DeploymentShare\Control
    2. \\MDTServer\DeploymentShare$\Control

Currently your Bootstrap.ini is more bare bones than your CustomSettings.ini:


[Settings]
Priority=Default

[Default]
DeployRoot=\\ITF1MDT01\DeploymentShare$

Unlike the CustomSettings.ini however, when you make changes to your Bootstrap.ini, the changes are not ‘live’ immediately:  Because the Bootstrap.ini is baked into your boot media – hence its ability to be processed when WinPE loads – anytime you update your Bootstrap.ini you must update your Deployment Share to generate new media that contains your updated Bootstrap.ini.  Because of this, you probably want to keep edits to this file to a minimum, adding just the essentials to get you connected to the Deployment Share.

According to the documentation, there are only a handful of properties configured by Bootstrap.ini; so few I’ll include them here for reference:

_SMSTSOrgName Database DBID
DBPwd DeployRoot DestinationDisk
DestinationLogicalDrive DestinationPartition Instance
KeyboardLocale KeyboardLocalePE Location
NetLib Order Parameters
ParameterCondition Port Priority
Properties ResourceRoot Role
SkipBDDWelcome SQLServer SQLShare
StoredProcedure Table UserDomain
UserID UserPassword

However that same document doesn’t state you can use the ‘DefaultGateway’ in the Bootstrap.ini which is a completely valid configuration, so I’ll assume the documentation is dated or it was an oversight.

It’s also been said that you can customize the Bootstrap.ini to nearly the same degree as the CustomSettings.ini.  I personally have not done this so I can’t validate that (e.g.: will User Exit scripts work etc.) but since the documentation is clearly not complete, I also refute it either.  So yes, you can create new sections and custom properties but I will say this: Because edits to the Bootstrap.ini require rebuilding the media each time a change is made, I personally prefer to to keep it simple with the most static information possible.

Facilitating Authentication

The first thing I typically do is rid myself of that dreadful authentication prompt that appears after clicking the ‘Run the Deployment Wizard…’ button:

SBTS-002

And I accomplish that by adding the UserID, UserPassword and UserDomain properties to the Bootstrap.ini:


[Settings]
Priority=Default

[Default]
DeployRoot=\\ITF1MDT01\DeploymentShare$
UserID=Administrator
UserPassword=my sekret 1337 Cyph3r!
UserDomain=ITF1MDT01

The documentation states:

For a completely automated LTI deployment, provide this property in both CustomSettings.ini and BootStrap.ini.  However, note that storing the user credentials in these files stores the credentials in clear text and therefore is not secure.

This is an important thing to remember when setting this up and a documented risk for the security team.  Leading practice would be to use a dedicated MDT account with limited rights (like execute) to the Deployment Share and write access to the ‘Captures’ directory.  I would advise against using a privileged account, be it local to the ‘MDT Server’ or the a domain account.

Skipping the Welcome Screen

If you’re not a big fan of this screen:

SBTS-001

You can suppress it by adding the SkipBDDWelcome property and setting it to YES to the Bootstrap.ini.


[Settings]
Priority=Default

[Default]
DeployRoot=\\ITF1MDT01\DeploymentShare$
UserID=Administrator
UserPassword=my sekret 1337 Cyph3r!
UserDomain=ITF1MDT01
SkipBDDWelcome=YES

To undo, set it to NO or comment the code by placing a semicolon in front of it like ;SkipBDDWelcome=YES.

The documentation states:

For this property to function properly, it must be configured in both CustomSettings.ini and BootStrap.ini. BootStrap.ini is processed before a deployment share (which contains CustomSettings.ini) has been selected.

I’ll tell you that I don’t always add it to my CustomSetting.ini and yet the Welcome screen is been suppressed for every build and build & capture with that configuration.  Again, this could be a change in MDT behavior that wasn’t reflected in the documentation but I always recommend following the documentation.

Putting It All Together

Ok so now you’ve got the hang of it, let’s make some changes common to many environments.  Comments added to emphasize certain elements.


[Settings]
Priority=Init,DefaultGateway,BootStrapSection,Default
Properties=Office,MyBootStrapProperty

[Init]
DeployRoot=\\DFS\Namespace\DeploymentShare$
;SkipBDDWelcome=YES

[DefaultGateway]
; Put your real gateway for HQ
10.0.1.1=HQ
10.10.1.1=DC

[HQ]
; HQ is your current environment so put real information here
Office=HQ
; Point this to the real Deployment Share you setup
DeployRoot=\\ITF1MDT01\DeploymentShare$
; Use real credentials to connect to the above share
UserID=svc_ImagingAccount
UserPassword=Tr0ub4dor&3
UserDomain=ITF1MDT01

[DC]
; This is a fake location for illustration purposes
; But you could be in an environment with multiple Deployment Shares
Office=DC
DeployRoot=\\DCServer\DeploymentShare$
UserID=lclMDTUser
UserPassword=Correct Horse Battery St4pl3!
UserDomain=DCServer
SkipBDDWelcome=NO

[BootStrapSection]
MyBootStrapProperty=THIS IS MY BOOTSTRAP PROPERTY
_SMSTSOrgName=MDT Lab@%Office%

[Default]
SkipBDDWelcome=YES
; This is fake information because I set the real information above
; Again purely for illustration purposes
UserID=MDTAccount
UserPassword=my sekret 1337 Cyph3r!
UserDomain=DOMAIN.FQDN

And here’s how it’s going to be processed:

  1. [Init] Section – This is the ‘Init’ section where I can set some default settings.  This isn’t required and you may or may not need something like this; just know that you can do something like this.
    1. DeployRoot is set to \\DFS\Namespace\DeploymentShare$
      This would be a catch-all default for offices that don’t have a separate Deployment Share.  In this scenario, if someone’s gateway was 10.20.20.1 they would default to this Deployment Share because there’s no rule below for that particular gateway.
      .
    2. SkipBDDWelcome was initially set to YES at some point but commented out because technicians in some offices wanted to use the other options on the Welcome screen.
      SkipBDDWelcome, like most MDT properties, is a write-once property so if we set it to ‘YES’ in [Init] we can’t alter it later.  Better to leave it alone to allow offices to customize it to their liking.
      .
  2. [DefaultGateway] Section
    1. 10.0.1.1 – If the default gateway matches this, it will go to the [HQ] section
      1. [HQ] Section
        1. We set a new property called Office to HQ.
          This could be useful for a variety of things like naming computers based on location
        2. The DeployRoot is set to \\ITF1MDT01\DeploymentShare$.
          DeployRoot is one of 9 properties that are re-writable out of the box so I can set this as many times as I need to.
        3. UserID is the username we’re going to use to connect to the above Deployment Share, in DeployRoot.  We have to do this because they’re smart and not using common username & password like other offices.
        4. UserPassword is the password for the above user
        5. UserDomain is the domain we’re authenticating against, in this case the DCServer.
        6. SkipBDDWelcome is set to NO because this office prefers to see the screen.
          .adsasdasd..
    2. 10.10.1.1 – If the default gateway matches this, it will go to the [DC] section.
      1. [DC] Section
        1. We set a new property called Office to DC.
        2. The DeployRoot is updated to point to a local Deployment Share in that office.
        3. UserID is the username we’re going to use to connect to the above Deployment Share, in DeployRoot.  We have to do this because they’re smart and not using common username & password like other offices.
        4. UserPassword is the password for the above user
        5. UserDomain is the domain we’re authenticating against, in this case the DCServer.
        6. SkipBDDWelcome is set to NO because this office prefers to see the screen.
          .
  3. [BootStrapSection] Section – An arbitrary section I created just because I can
    1. A new property called MyBootStrapProperty is set to ‘THIS IS MY BOOTSTRAP PROPERTY” – again purely to show that it can be done.
    2. The _SMSTSOrgName property is set and it references the Office code set further up.
      .
  4. ​​[Default] Section
    1. SkipBDDWelcome is set to YES because most offices don’t want to see it.
      If it’s not already set, it will get set to YES.
    2. UserID is the username we’re going to use to authenticate to the default Deployment Share, held in property DeployRoot, that we set in the [Init] section.
    3. UserPassword is the password for the above username
    4. UserDomain is the domain we’re authenticating against.

The proof is in the pudding:

  • After making the changes to the Bootstrap.ini, update your Deployment Share to create new media
  • Boot your new media
  • You will no longer see the Welcome screen
  • You will no longer receive an authentication prompt
  • You will be taken directly to the Task Sequence page
  • If you run a Task Sequence (build or build & capture) you’ll see the updated text in the progress bar area:
    • Bootstrap-002

I recommend opening the BDD.log file to review the processing, but this is something we haven’t touched on yet so brace yourself.

While in WinPE – say when you’re looking at the Task Sequence list – press F8 on your keyboard to open a command prompt which is unequivocally indispensable when it comes to troubleshooting!  Please note that on some laptops you may need to press the Function (Fn) key and F8 simultaneously to get this to work.  This isn’t an MDT problem but a hardware specific issue.

Bootstrap-003

In the command window just type notepad hit return and notepad will open.  From there you can go to File > Open & browse to find the BDD.log, which is in one of two locations depending on the state of the hard drive of the machine you’re testing:

  • Drive has NOT been partitioned:
    The BDD.log – and others – can be found in X:\MININT\SMSOSD\OSDLOGS
    .
  • Drive HAS been partitioned:
    The BDD.log – and others can be found in C:\MININT\SMSOSD\OSDLOGS

This slideshow requires JavaScript.

Once you navigate to that location, you won’t see anything because of the default ‘Files of type’ filter in notepad.  Change the drop down from ‘Text documents (*.txt)’ to ‘All Files’ and like magic a bunch of files will appear.  Now open the BDD.log

MDT generated logs are a little difficult to navigate in notepad but this is the kind of thing that really builds character.  In the log, search (CTRL+F) for one of the properties you set, like _SMSTSOrg or ‘MDT Lab@’ and you should find what you’re looking for it pretty quickly.

Below is my marked up version of the BDD.log highlighting the custom properties, the order of operations (Rule Priority) as well as the sections it processed; between each you’ll find log entries for the actions performed, like setting Properties (aka variables) like UserID, MyBootstrapProperty etc.

Bootstrap-001

As you can see, everything was processed accordingly and set correctly.

In Closing

This Bootstrap.ini example is a little complex only because it accounts for possible real world scenarios: Office specific configuration, Multiple Deployment Shares (aka DeployRoot), Different Credentials for each Deployment Share, customizing the progress bar with your branding/corporate information and so on.

For your lab environment, you really just need a bare bones config like this:


[Settings]
Priority=Default

[Default]
; Customize this to your liking
_SMSTSOrgName=My Custom MDT Lab
; Point this to the real Deployment Share you setup
DeployRoot=\\ITF1MDT01\DeploymentShare$
; Use real credentials to connect to the above share
UserID=svc_ImagingAccount
UserPassword=Tr0ub4dor&3
UserDomain=ITF1MDT01
; You might want to skip this but maybe not - your call
SkipBDDWelcome=YES

But at least you know how to handle those scenarios and scale up.

Good Providence to you!

MDT Tutorial Part 3: Imaging

Living Table of Contents

 

Today’s agenda: Image All The Things!

  • Image a machine with the Build Task Sequence
  • Image a machine with the Build, Sysprep & Capture Task Sequence

Prerequisites

  • Copy the bootable ISOs from the Boot directory in the Deployment Share Share (e.g.: \\MDTServer01\DeploymentShare$\Boot) to your Hyper-V server
  • Add the ISO to your VM
  • Set the DVD Drive as the first boot device
  • Boot your VM
  • Press any key to boot the media.

Build Task Sequence

Once the WinPE environment loads, you’ll be greeted by this window.

SBTS-001

Click ‘Run the Deployment Wizard to install a new Operating System‘ and it will prompt you for credentials.  If you created a dedicated MDT account, good on you – use those.  In my lab (torn down & rebuilt regularly) I just use the local Administrator account.SBTS-003

Assuming you entered the proper credentials, you’ll see the available Task Sequences.
Choose the Task Sequence you created and click next.

SBTS-004

On the ‘Computer Details’ step feel free to enter in a computer name and workgroup name; Or don’t – that’s fine too.

SBTS-005

On the ‘Move Data and Settings’ step you can leave the default, ‘Do not move user data and settings.‘, since there’s nothing to backup/move.

SBTS-006

On the ‘User Data (Restore)’ step leave the default, ‘Do not restore user data and settings.‘ because there’s nothing to restore from.

SBTS-007

On the ‘Locale and Time’ step, adjust the settings accordingly.

SBTS-008

On the ‘Capture Image’ step you can leave the default, ‘Do not capture an image of this computer.‘  Right now we’re just looking to lay down the OS and the B&C will come later.

SBTS-009

On the ‘BitLocker’ step you can leave ‘Do not enable BitLocker for this computer.

SBTS-010

The ‘Ready’ step is really just a summary of the configuration you set above.
Give it a once over to make sure it’s correct and click begin.

SBTS-011

Will run, doing the steps listed in the Task Sequence.  I like to follow along with the VM on one side of the screen and the Task Sequence on the other to ensure things are executing as I expect.  A number of steps take place in WinPE, like laying down the WIM on the disk.

Afterwards the machine will reboot and boot into Windows

Eventually you’ll see the desktop and you might think ‘it’s done’ or that ‘it stalled’ and be tempted to start playing around with it but please don’t!

SBTS-022

Give it a minute and you’ll see the process continue.

After a sigh of relief it’ll move on and finish up very quickly after that.

SBTS-025

Mid Boss Battle Complete!

This is the halfway mark and if this goes smoothly the next step should be just as easy.

Build, Sysprep & Capture Task Sequence

If you didn’t already guess, the Build, Sysprep & Capture – or B&C for Build & Capture because it’s assumed you’re going to sysprep the machine since you don’t want to be in an unsupported situation – process is the same as the above.

  • Add the ISO to your B&C VM
  • Boot from the media
  • Click ‘Run the Deployment Wizard to install a new Operating System
  • Enter your authentication credentials

This time you want to select your B&C Task Sequence

Cap-001

The screens that follow are identical to what you had before, and for the most part everything is the same…

EXCEPT when you get to the ‘Capture Image’ step!
This time we are going to select ‘Capture an image of this reference computer.‘ so that we can capture an image of this machine.  You’re welcome to adjust the Location and File name but the defaults are fine for our purposes.

Cap-007

Again, review your configuration to ensure it’s correct before clicking ‘Begin’

Cap-008

For the most part, it’s exactly the same as before: A number of steps take place in WinPE before rebooting into the OS.

Once in the OS, MDT will start up again, finish up the normal tasks

This slideshow requires JavaScript.

Run sysprep

Cap-010

Stage the boot media

Cap-009

Reboot into WinPE

Cap-012

Initialize the WinPE environment

Cap-013

Capture the WIM

This slideshow requires JavaScript.

Display a summary when complete

Cap-017

A High Five is in Order: Your First B&C via MDT!

Seriously, this is a big deal so request the highest of fives from someone.

The Importance of MDT in a WaaS World

I do not like doing the same thing over and over again, and the idea of building a physical machine that I need to patch, load software onto and configure is not how I want to spend my day.  You can expect a feature update release for Windows 10 twice a year which means you could be asked to perform a B&C twice a year.

So instead of spending days:

  • installing Windows 10
  • thumbing through a 40 page build document
  • locating build change notes scattered across sticky notes scattered throughout desk and emails

I would much rather spend a few hours or a couple of days:

  • cataloguing the OS level configurations required for the organization
  • packaging applications & testing them to ensure they’re complete and work
  • putting it all together in scripts
  • loading all these into MDT

This way I can have reliable, repeatable process for building machines & capturing images.

I promise, once you get this going you’ll never look back.

Good Providence to you!

MDT Tutorial Part 2: Initial Configuration

Living Table of Contents

 

Today’s agenda is to focus on the basics so you can start imaging.

  • Creating a Deployment Share
  • Import an OS into MDT
  • Create a stock Build Task Sequence in MDT
  • Create a stock Build, Sysprep & Capture Task Sequence in MDT
  • Update the Deployment Share

MDT Workbench

The MDT Workbench is where all the action is: It’s where you add your Operating Systems, create & edit your Task Sequences, import your Drivers – basically everything you need to image.  Fire it up and you should see a wonderful blank canvas.

MDT-001

Create Deployment Share

Secondary mouse-click the top-level ‘Deployment Shares’ node and select the option to create a new Deployment Share.

Enter the desired location to create the Deployment Share.NDS-001

Enter a share name for the Deployment Share

NDS-002

Enter a name for your Deployment Share – how you want it to show up in the Deployment Workbench.

NDS-003

These are the default options – I left them as is just for the purposes of documenting the out-of-box experience.

NDS-004

Review the summary to confirm all is well

NDS-005

Within seconds your new Deployment Share will be created.

NDS-006

NDS-007

I want to highlight something really important: The View Script button that exists on just about every MDT screen.  It kicks out code for each action like Creating Deployment Shares, Importing Operating Systems, Updating Deployment Shares etc.

Behind the scenes, this is the underlying code used to create the Deployment Share


New-Item -Path "C:\DeploymentShare" -ItemType directory
New-SmbShare -Name "DeploymentShare$" -Path "C:\DeploymentShare" -FullAccess Administrators
Import-Module "C:\Program Files\Microsoft Deployment Toolkit\bin\MicrosoftDeploymentToolkit.psd1"
new-PSDrive -Name "DS001" -PSProvider "MDTProvider" -Root "C:\DeploymentShare" -Description "MDT Deployment Share" -NetworkPath "\\ITF1MDT01\DeploymentShare$" -Verbose | add-MDTPersistentDrive -Verbose

If you’re new to MDT and PowerShell, this is going to help you turn things around fairly quickly.

Import OS into MDT

Expand the top-level ‘Deployment Shares’ node then expand your newly created ‘MDT Deployment Share’ node to reveal the ‘Operating Systems’ node.

Create a Stock ‘Build’ Task Sequence

Secondary mouse-click on the ‘Task Sequence’ node & select ‘New Task Sequence’

On the first screen enter a Task Sequence ID – this is an identifier for this specific Task Sequence and all ID’s must be unique.

BTS-001

Under ‘Select Template’ leave the default, ‘Standard Client Task Sequence’.BTS-002

Select the Operating System you’re going to deploy.

BTS-003

Accept the default, ‘Do not specify a product key at this time.’

BTS-004

Set the ‘Full Nam’, ‘Organization’ and ‘Internet Explorer Home Page’ options.

BTS-005

Specify a password for the built-in local Administrator account.

BTS-006

Here’s your summary – review everything to ensure it’s correct.

BTS-007

Within seconds your Task Sequence will build.

BTS-008

As before, don’t forget about the ‘View Script’ button:


Import-Module "C:\Program Files\Microsoft Deployment Toolkit\bin\MicrosoftDeploymentToolkit.psd1"
New-PSDrive -Name "DS001" -PSProvider MDTProvider -Root "C:\DeploymentShare"
import-mdttasksequence -path "DS001:\Task Sequences" -Name "Build 1511 amd64 Ent" -Template "Client.xml" -Comments "" -ID "B151164Ent" -Version "1.0" -OperatingSystemPath "DS001:\Operating Systems\Windows 10 Enterprise in 1511_amd64_Ent install.wim" -FullName "Name Full" -OrgName "Org" -HomePage "about:blank" -AdminPassword "my s3kr3t" -Verbose

Create a Stock Build, Sysprep & Capture Task Sequence in MDT

On the heels of creating your build Task Sequence, we’re going to create a Build, Sysprep & Capture Task Sequence something I affectionately call a B&C.

The process is exactly the same as before: Secondary mouse-click on the ‘Task Sequence’ node, select ‘New Task Sequence’ and enter the details:

BCTS-001

Fill in the other fields as you did before, review the summary and execute.

BCTS-002BCTS-004

There’s no difference between what you did before and what you just created; this is intentional.  Later we’ll build off this and it’ll be handy to have a reusable B&C TS ready to go.

Update the Deployment Share

Since the objective is to take MDT for a spin in a straight out of the box configuration, we’re not going to make any customizations to the Deployment Share.  That will come later for sure – let’s just make sure it works before we invest time doing so.

The Deployment Share update process is simple, requires minimal input but does take a while to complete.  The reason we have to do this is to generate the bootable .ISO we’ll need for booting into the MDT WinPE environment to image our test VM’s.

Secondary mouse click on your Deployment Share root node – this would be the ‘MDT Deployment Share’ below:

MDT-002

For our purposes we can leave the default options set and click next.

The process will run for a while.

And it’ll look like it’s stuck in a loop.

This is expected because it’s building the x86 and amd64 images.

UDS-011

Finally it’ll finish

UDS-009

You should see some output like this:

<pre>=== Making sure the deployment share has the latest x86 tools ===

=== Processing LiteTouchPE (x86) boot image ===

Building requested boot image profile.
Determining if any changes have been made in the boot image configuration.
Loading the existing boot image profile for platform x86.
The Windows PE source has changed since a boot image was last generated, so a new image will be created.
Discarding existing boot image profile because a complete rebuild is required.
Calculating hashes for requested content.
Changes have been made, boot image will be updated.
Windows PE WIM C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\en-us\winpe.wim will be used.
WIM file mounted.
Set Windows PE system root.
Set Windows PE scratch space.
Added component winpe-hta
Added component winpe-scripting
Added component winpe-wmi
Added component winpe-securestartup
Added component winpe-fmapi
Added component winpe-mdac
Copy: C:\DeploymentShare\Control\Bootstrap.ini to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Bootstrap.ini
Copy: C:\Program Files\Microsoft Deployment Toolkit\Templates\Unattend_PE_x86.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Unattend.xml
Copy: C:\Program Files\Microsoft Deployment Toolkit\Templates\winpeshl.ini to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Windows\system32\winpeshl.ini
Copy: C:\DeploymentShare\Scripts\LiteTouch.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\LiteTouch.wsf
Copy: C:\DeploymentShare\Scripts\ZTIUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIUtility.vbs
Copy: C:\DeploymentShare\Scripts\ZTIBCDUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIBCDUtility.vbs
Copy: C:\DeploymentShare\Scripts\ZTIDiskUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIDiskUtility.vbs
Copy: C:\DeploymentShare\Scripts\ZTIDataAccess.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIDataAccess.vbs
Copy: C:\DeploymentShare\Scripts\ZTIConfigFile.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIConfigFile.vbs
Copy: C:\DeploymentShare\Scripts\ZTIGather.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIGather.wsf
Copy: C:\DeploymentShare\Scripts\ZTIGather.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIGather.xml
Copy: C:\DeploymentShare\Scripts\Wizard.hta to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Wizard.hta
Copy: C:\DeploymentShare\Scripts\Credentials_ENU.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Credentials_ENU.xml
Copy: C:\DeploymentShare\Scripts\Credentials_scripts.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Credentials_scripts.vbs
Copy: C:\DeploymentShare\Scripts\WizUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WizUtility.vbs
Copy: C:\DeploymentShare\Scripts\Wizard.css to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Wizard.css
Copy: C:\DeploymentShare\Scripts\Wizard.ico to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Wizard.ico
Copy: C:\DeploymentShare\Scripts\BackButton.jpg to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\BackButton.jpg
Copy: C:\DeploymentShare\Scripts\plusicon.gif to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\plusicon.gif
Copy: C:\DeploymentShare\Scripts\minusico.gif to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\minusico.gif
Copy: C:\DeploymentShare\Scripts\Summary_Definition_ENU.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Summary_Definition_ENU.xml
Copy: C:\DeploymentShare\Scripts\Summary_scripts.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Summary_scripts.vbs
Copy: C:\DeploymentShare\Scripts\LTICleanup.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\LTICleanup.wsf
Copy: C:\DeploymentShare\Scripts\BDD_Welcome_ENU.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\BDD_Welcome_ENU.xml
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Choice.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Choice.xml
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Choice.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Choice.vbs
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_DeployRoot.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_DeployRoot.xml
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_DeployRoot.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_DeployRoot.vbs
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Initialize.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Initialize.xml
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Initialize.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Initialize.vbs
Copy: C:\DeploymentShare\Scripts\SelectItem.jpg to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\SelectItem.jpg
Copy: C:\DeploymentShare\Scripts\WelcomeBanner.jpg to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeBanner.jpg
Copy: C:\DeploymentShare\Scripts\btnout.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\btnout.png
Copy: C:\DeploymentShare\Scripts\btnover.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\btnover.png
Copy: C:\DeploymentShare\Scripts\btnsel.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\btnsel.png
Copy: C:\DeploymentShare\Scripts\LTIGetFolder.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\LTIGetFolder.wsf
Copy: C:\DeploymentShare\Scripts\NICSettings_Definition_ENU.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\NICSettings_Definition_ENU.xml
Copy: C:\DeploymentShare\Scripts\ZTINicUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTINicUtility.vbs
Copy: C:\DeploymentShare\Scripts\ZTINicConfig.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTINicConfig.wsf
Copy: C:\DeploymentShare\Scripts\BackButton.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\BackButton.png
Copy: C:\DeploymentShare\Scripts\FolderIcon.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\FolderIcon.png
Copy: C:\DeploymentShare\Scripts\ItemIcon1.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ItemIcon1.png
Copy: C:\DeploymentShare\Scripts\MinusIcon1.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\MinusIcon1.png
Copy: C:\DeploymentShare\Scripts\PlusIcon1.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\PlusIcon1.png
Copy: C:\DeploymentShare\Scripts\SelectItem.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\SelectItem.png
Copy: C:\DeploymentShare\Scripts\header-image.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\header-image.png
Copy: C:\DeploymentShare\Scripts\NavBar.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\NavBar.png
Copy: C:\DeploymentShare\Scripts\Computer.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Computer.png
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Background.jpg to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Background.jpg
Copy: C:\DeploymentShare\Scripts\DeployWiz_Administrator.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\DeployWiz_Administrator.png
Copy: C:\DeploymentShare\Tools\x86\BDDRUN.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Windows\system32\BDDRUN.exe
Copy: C:\DeploymentShare\Tools\x86\WinRERUN.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\WinRERUN.exe
Copy: C:\DeploymentShare\Tools\x86\CcmCore.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\CcmCore.dll
Copy: C:\DeploymentShare\Tools\x86\CcmUtilLib.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\CcmUtilLib.dll
Copy: C:\DeploymentShare\Tools\x86\Smsboot.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\Smsboot.exe
Copy: C:\DeploymentShare\Tools\x86\SmsCore.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\SmsCore.dll
Copy: C:\DeploymentShare\Tools\x86\TsCore.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\TsCore.dll
Copy: C:\DeploymentShare\Tools\x86\TSEnv.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\TSEnv.exe
Copy: C:\DeploymentShare\Tools\x86\TsManager.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\TsManager.exe
Copy: C:\DeploymentShare\Tools\x86\TsmBootstrap.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\TsmBootstrap.exe
Copy: C:\DeploymentShare\Tools\x86\TsMessaging.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\TsMessaging.dll
Copy: C:\DeploymentShare\Tools\x86\TsmBootstrap.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\TsmBootstrap.exe
Copy: C:\DeploymentShare\Tools\x86\TsProgressUI.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\TsProgressUI.exe
Copy: C:\DeploymentShare\Tools\x86\TSResNlc.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\TSResNlc.dll
Copy: C:\DeploymentShare\Tools\x86\CommonUtils.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\CommonUtils.dll
Copy: C:\DeploymentShare\Tools\x86\ccmgencert.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\ccmgencert.dll
Copy: C:\DeploymentShare\Tools\x86\msvcp120.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\msvcp120.dll
Copy: C:\DeploymentShare\Tools\x86\msvcr120.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\msvcr120.dll
Copy: C:\DeploymentShare\Tools\x86\00000409\tsres.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\00000409\tsres.dll
Copy: C:\DeploymentShare\Tools\x86\Microsoft.BDD.Utility.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x86\Microsoft.BDD.Utility.dll
Copy: C:\Program Files\Microsoft Deployment Toolkit\Samples\Background.bmp to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Windows\system32\winpe.bmp
Copying WIM to the deployment share.
Creating an ISO.
Copying ISO to the deployment share.

=== Completed processing platform x86 ===

=== Making sure the deployment share has the latest x64 tools ===

=== Processing LiteTouchPE (x64) boot image ===

Building requested boot image profile.
Determining if any changes have been made in the boot image configuration.
Loading the existing boot image profile for platform x64.
The Windows PE source has changed since a boot image was last generated, so a new image will be created.
Discarding existing boot image profile because a complete rebuild is required.
Calculating hashes for requested content.
Changes have been made, boot image will be updated.
Windows PE WIM C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us\winpe.wim will be used.
WIM file mounted.
Set Windows PE system root.
Set Windows PE scratch space.
Added component winpe-hta
Added component winpe-scripting
Added component winpe-wmi
Added component winpe-securestartup
Added component winpe-fmapi
Added component winpe-mdac
Copy: C:\DeploymentShare\Control\Bootstrap.ini to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Bootstrap.ini
Copy: C:\Program Files\Microsoft Deployment Toolkit\Templates\Unattend_PE_x64.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Unattend.xml
Copy: C:\Program Files\Microsoft Deployment Toolkit\Templates\winpeshl.ini to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Windows\system32\winpeshl.ini
Copy: C:\DeploymentShare\Scripts\LiteTouch.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\LiteTouch.wsf
Copy: C:\DeploymentShare\Scripts\ZTIUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIUtility.vbs
Copy: C:\DeploymentShare\Scripts\ZTIBCDUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIBCDUtility.vbs
Copy: C:\DeploymentShare\Scripts\ZTIDiskUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIDiskUtility.vbs
Copy: C:\DeploymentShare\Scripts\ZTIDataAccess.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIDataAccess.vbs
Copy: C:\DeploymentShare\Scripts\ZTIConfigFile.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIConfigFile.vbs
Copy: C:\DeploymentShare\Scripts\ZTIGather.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIGather.wsf
Copy: C:\DeploymentShare\Scripts\ZTIGather.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTIGather.xml
Copy: C:\DeploymentShare\Scripts\Wizard.hta to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Wizard.hta
Copy: C:\DeploymentShare\Scripts\Credentials_ENU.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Credentials_ENU.xml
Copy: C:\DeploymentShare\Scripts\Credentials_scripts.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Credentials_scripts.vbs
Copy: C:\DeploymentShare\Scripts\WizUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WizUtility.vbs
Copy: C:\DeploymentShare\Scripts\Wizard.css to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Wizard.css
Copy: C:\DeploymentShare\Scripts\Wizard.ico to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Wizard.ico
Copy: C:\DeploymentShare\Scripts\BackButton.jpg to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\BackButton.jpg
Copy: C:\DeploymentShare\Scripts\plusicon.gif to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\plusicon.gif
Copy: C:\DeploymentShare\Scripts\minusico.gif to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\minusico.gif
Copy: C:\DeploymentShare\Scripts\Summary_Definition_ENU.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Summary_Definition_ENU.xml
Copy: C:\DeploymentShare\Scripts\Summary_scripts.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Summary_scripts.vbs
Copy: C:\DeploymentShare\Scripts\LTICleanup.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\LTICleanup.wsf
Copy: C:\DeploymentShare\Scripts\BDD_Welcome_ENU.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\BDD_Welcome_ENU.xml
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Choice.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Choice.xml
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Choice.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Choice.vbs
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_DeployRoot.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_DeployRoot.xml
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_DeployRoot.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_DeployRoot.vbs
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Initialize.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Initialize.xml
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Initialize.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Initialize.vbs
Copy: C:\DeploymentShare\Scripts\SelectItem.jpg to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\SelectItem.jpg
Copy: C:\DeploymentShare\Scripts\WelcomeBanner.jpg to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeBanner.jpg
Copy: C:\DeploymentShare\Scripts\btnout.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\btnout.png
Copy: C:\DeploymentShare\Scripts\btnover.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\btnover.png
Copy: C:\DeploymentShare\Scripts\btnsel.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\btnsel.png
Copy: C:\DeploymentShare\Scripts\LTIGetFolder.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\LTIGetFolder.wsf
Copy: C:\DeploymentShare\Scripts\NICSettings_Definition_ENU.xml to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\NICSettings_Definition_ENU.xml
Copy: C:\DeploymentShare\Scripts\ZTINicUtility.vbs to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTINicUtility.vbs
Copy: C:\DeploymentShare\Scripts\ZTINicConfig.wsf to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ZTINicConfig.wsf
Copy: C:\DeploymentShare\Scripts\BackButton.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\BackButton.png
Copy: C:\DeploymentShare\Scripts\FolderIcon.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\FolderIcon.png
Copy: C:\DeploymentShare\Scripts\ItemIcon1.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\ItemIcon1.png
Copy: C:\DeploymentShare\Scripts\MinusIcon1.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\MinusIcon1.png
Copy: C:\DeploymentShare\Scripts\PlusIcon1.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\PlusIcon1.png
Copy: C:\DeploymentShare\Scripts\SelectItem.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\SelectItem.png
Copy: C:\DeploymentShare\Scripts\header-image.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\header-image.png
Copy: C:\DeploymentShare\Scripts\NavBar.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\NavBar.png
Copy: C:\DeploymentShare\Scripts\Computer.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\Computer.png
Copy: C:\DeploymentShare\Scripts\WelcomeWiz_Background.jpg to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\WelcomeWiz_Background.jpg
Copy: C:\DeploymentShare\Scripts\DeployWiz_Administrator.png to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Scripts\DeployWiz_Administrator.png
Copy: C:\DeploymentShare\Tools\x64\BDDRUN.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Windows\system32\BDDRUN.exe
Copy: C:\DeploymentShare\Tools\x64\WinRERUN.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\WinRERUN.exe
Copy: C:\DeploymentShare\Tools\x64\CcmCore.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\CcmCore.dll
Copy: C:\DeploymentShare\Tools\x64\CcmUtilLib.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\CcmUtilLib.dll
Copy: C:\DeploymentShare\Tools\x64\Smsboot.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\Smsboot.exe
Copy: C:\DeploymentShare\Tools\x64\SmsCore.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\SmsCore.dll
Copy: C:\DeploymentShare\Tools\x64\TsCore.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\TsCore.dll
Copy: C:\DeploymentShare\Tools\x64\TSEnv.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\TSEnv.exe
Copy: C:\DeploymentShare\Tools\x64\TsManager.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\TsManager.exe
Copy: C:\DeploymentShare\Tools\x64\TsmBootstrap.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\TsmBootstrap.exe
Copy: C:\DeploymentShare\Tools\x64\TsMessaging.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\TsMessaging.dll
Copy: C:\DeploymentShare\Tools\x64\TsmBootstrap.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\TsmBootstrap.exe
Copy: C:\DeploymentShare\Tools\x64\TsProgressUI.exe to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\TsProgressUI.exe
Copy: C:\DeploymentShare\Tools\x64\TSResNlc.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\TSResNlc.dll
Copy: C:\DeploymentShare\Tools\x64\CommonUtils.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\CommonUtils.dll
Copy: C:\DeploymentShare\Tools\x64\ccmgencert.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\ccmgencert.dll
Copy: C:\DeploymentShare\Tools\x64\msvcp120.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\msvcp120.dll
Copy: C:\DeploymentShare\Tools\x64\msvcr120.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\msvcr120.dll
Copy: C:\DeploymentShare\Tools\x64\00000409\tsres.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\00000409\tsres.dll
Copy: C:\DeploymentShare\Tools\x64\Microsoft.BDD.Utility.dll to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Deploy\Tools\x64\Microsoft.BDD.Utility.dll
Copy: C:\Program Files\Microsoft Deployment Toolkit\Samples\Background.bmp to C:\Users\ADMINI~1\AppData\Local\Temp\2\MDTUpdate.3008\Mount\Windows\system32\winpe.bmp
Copying WIM to the deployment share.
Creating an ISO.
Copying ISO to the deployment share.

=== Completed processing platform x64 ===

=== Processing complete ===

</pre>

Don’t forget to grab that code by the ‘View Script’ button!

So you’re all set!

Wait – did something go wrong?  Are you seeing an error?  Something like this?

UDS-010

With text that reads:

<pre>=== Making sure the deployment share has the latest x86 tools ===

=== Processing LiteTouchPE (x86) boot image ===

Building requested boot image profile.
Determining if any changes have been made in the boot image configuration.
Loading the existing boot image profile for platform x86.
The Windows PE source has changed since a boot image was last generated, so a new image will be created.
Discarding existing boot image profile because a complete rebuild is required.
Calculating hashes for requested content.
Changes have been made, boot image will be updated.
Windows PE WIM C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\en-us\winpe.wim will be used.
Unable to mount the WIM, so the update process cannot continue.

=== Completed processing platform x86 ===

=== Making sure the deployment share has the latest x64 tools ===

=== Processing LiteTouchPE (x64) boot image ===

Building requested boot image profile.
Determining if any changes have been made in the boot image configuration.
Loading the existing boot image profile for platform x64.
The Windows PE source has changed since a boot image was last generated, so a new image will be created.
Discarding existing boot image profile because a complete rebuild is required.
Calculating hashes for requested content.
Changes have been made, boot image will be updated.
Windows PE WIM C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us\winpe.wim will be used.
Unable to mount the WIM, so the update process cannot continue.

=== Completed processing platform x64 ===

=== Processing complete ===

</pre>

Did you remember to apply the patch mentioned in the previous post?  If not, apply the patch and try again.  If you did apply the patch, further troubleshooting is required and I recommend posting on the TechNet Forums and Twitter.  You’re more than welcome to post here – happy to help in anyway I can – but the reality is there your issue will get far more visibility on those two platforms than here 🙂

Objective Complete!

That’s it for now but you’re essentially ready to start imaging.  If you’re feeling adventurous, try imaging one of your VMs.

Until next time, Good Providence to you!

MDT Tutorial Part 1: Installation

Living Table of Contents

 

Today’s agenda: Install Software

  • Install the Windows Assessment & Deployment Kit (ADK)
  • Install the Microsoft Deployment Toolkit (MDT)

ADK Installation

If you read my last post I recommended running the ADK installation and selecting the option to download the files locally in preparation for the installation.  The reason for that is due to the nature of the ADK installation: The bits are retrieved on demand and it takes a while.  It’s very much as game of Hurry Up and Wait!

Run the ADK installation & optionally change the installation path

ADK-001

Decide whether you want to share statistics

ADK-002

Read over the EULA and if you agree, click accept

ADK-003

When you get to the feature selection stage, everything will be checked.  Uncheck everything except

  1. Deployment Tools
  2. Windows Preinstallation Environment (Windows PE)

I personally also recommend checking:

  1. Imaging and Configuration Designer (ICD)
  2. Configuration Designer
  3. User State Migration Toolkit (USMT)

ADK-004

If you downloaded it locally, the installation should move at a decent clip and finish swiftly.  Stand up, stretch, take a quick walk & grab some water.

ADK-005ADK-006

Known Issue

There’s a known issue with the Windows Assessment & Deployment Kit (ADK) where the following prompt is displayed on systems due to two files being signed with an older certificate.

ADK-007

This is a well documented bug:

Fortunately this is easily fixed by applying the patch and instructions and code are included:


xcopy ".\amd64\wimmount.sys" "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\DISM\wimmount.sys"
xcopy ".\amd64\wofadk.sys" "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\DISM\wofadk.sys"

xcopy ".\x86\wimmount.sys" "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\x86\DISM\wimmount.sys"
xcopy ".\x86\wofadk.sys" "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\x86\DISM\wofadk.sys"

xcopy ".\arm64\wimmount.sys" "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\arm64\DISM\wimmount.sys"
xcopy ".\arm64\wofadk.sys" "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\arm64\DISM\wofadk.sys"

Or you can use the workaround suggested by Michael Niehaus.

MDT Installation

This is a straightforward installation with few options to configure since you can leave the defaults.

Run the installer & click next

MDT-001

Read through the EULA

MDT-002

You can leave the default options and optionally change the installation location.

MDT-003

Click next to start the installation and let it run for a few minutes to completion.

MDT-005 MDT-007

MDT-008

Milestone Reached!  A congratulations is in order!

In the next post we’ll crack open the Deployment Workbench and start setting ourselves up for imaging.

For now, I bid you Good Providence!

MDT Tutorial: Prologue & Requirements

I met someone recently who is in a similar IT position looking for some advice with respect to Operating System Deployments (OSD) – both bare metal and upgrades – and application packaging & deployments.  I recommended leveraging the Microsoft Deployment Toolkit (MDT) for imaging and combining it with the PowerShell App Deployment Toolkit (PSADT) to help accomplish his goals.  Although he had used MDT, he wasn’t as experienced with it as I was and so was looking for some guidance which I was happy to do.

Now, I may not be a world renowned expert like some people (hint: see the Resources page) but I can hold my own, and this was an excellent opportunity for me to go over the basics of image building with my new friend.

So over the next few weeks I’ll be going over the basics of building an MDT imaging lab.

One more thing…

I don’t think there’s anything new here.  In fact, this is mostly a consolidation of well known & documented steps in addition to popular or leading practices recommended by those who share a passion for imaging.  So aside for compiling some of these ideas I can’t possibly take all the credit.  Because lots of these steps are now ingrained in my process, I may not be able to cite references to where the original idea came from.  Not trying to steal thunder or take credit away from anyone where it’s due; I just didn’t necessarily catalog the URL or Tweet of every process, tip or trick I’ve come across for the last 5 or so years.

If you’re a seasoned MDT Guru, you’re probably going to find this a little ho-hum elementary.  So while you’re welcome to read on, please curb your expectations. 🙂

Living Table of Contents

 

Prerequisites

Hardware

Preferred Configuration

Ideally you want a beefy machine to spin up some VM’s, and it doesn’t have to be a Dell R730xd.  In fact, before I got a dedicated machine, I used a laptop with 8GB of RAM and a ~200GB or so SSD.  These days it’s not uncommon for a machine to have 12-16GB of RAM and 256GB SSD so I’m thinking that’s a realistic and achievable goal.  Just remember: Can’t have too much RAM but on the storage front if SSD is a premium, put your VM’s on the SSD and the OS and Deployment Share on mechanical/spindle disks.  You could get creative by using USB drives (thumb or external) or even SD cards.  Go Nuts!

Acceptable Minimum for Educational Purposes

While you can use physical assets for testing, it’s not leading practice and will require some extra work with drivers.  That said, if you don’t have access to beefy hardware for creating Virtual Machines, but have a handful of physical assets at your disposal, grab a few machines and get them setup on a gigabit switch with network access.

Software

MDT Server

Be it a physical or virtual machine, install the OS of your choice on your designated MDT server.  At this time, OS selection doesn’t matter so it could be a licensed or evaluation copy of Server 2012 R2, Server 2016 or Windows 10.  Once you install the OS on the MDT server, install .NET 3.5, rename it to something appreciable, like MDTServer, create a workgroup and patch the machine.

All Set!

Once you have everything all setup, you’re ready to move forward!

Good Providence to you as you get this all setup!

Getting Real Lenovo Model Details

Our computer naming convention includes a portion of the model number to make it easier to identify trends and those with old, or new, assets.  Coming from a Dell shop where we did something similar, I was disappointed to learn that Lenovo machines didn’t populate the Model details the same way.  So instead of seeing something like ThinkPad W541, we were seeing something very cryptic: 20EFCTO1WW

Get your Decoder Ring

Thinking something was up with the built-in scripts or logic I ran the below on a Lenovo machine which confirmed it was what it was:


wmic path win32_computersystem get model

Model
20EFCTO1WW

For a while we kept a matrix of sorts that we’d feed into our CustomSettings.ini to ensure machines were named correctly.  We expected this pain as models were phased out and new models came in, but it was also very frustrating as the details would change mid-stream for the same model.  This led us to studying the Lenovo Product Specifications Reference or PSREF.

Not being keen on this, I learned somewhere (unsure of the actual source) that Lenovo stashes the bits we were after in Win32_ComputerSystemProduct under Version


wmic path win32_computersystemproduct get version

Version
ThinkPad W541

Once confirmed across a few machines, I went right to work.

UserExit Script: GetAbbrModel.vbs

This is a modified version of the script we use in production but the result is the same: It gets the human-readable format of the model, trims the parts we don’t want and returns an abbreviated version of the model.  So a ThinkPad W541 ends up being returned to MDT/SCCM as W54.  You can modify to suit, like creating a new property/variable called RealModel and assigning the script output to that or overwrite the existing Model property via the script itself.

The script works on 99% of the machines in our environment but it does occasionally fail:

  • some unexpected data is in there: sometimes it’s really bizzare or mirrors Model in Win32_ComputerSystem or Name in Win32_ComputerSystemProduct.
  • most of the time it’s because the field is blank/null/empty and we typically see this on machines that were serviced, specifically a board replacement, and tech didn’t run the utility to set the bits in the BIOS.  Accidents happen.
  • it’s running on very hardware that should have been retired 🙂

Good Providence to you as you adjust it to suit your needs!


' //***************************************************************************
' //
' // Solution:Get Model Abbreviation for Microsoft Deployment
' // File: jgp_GetAbbrModel.vbs
' //
' // Purpose: Gets & sets the correct model abbreviation for use in computer name and other custom configurations
' //
' // ***** End Header *****
' //***************************************************************************

'//----------------------------------------------------------------------------
'//
'// Global constant and variable declarations
'//
'//----------------------------------------------------------------------------
Option Explicit

'//----------------------------------------------------------------------------
'// End declarations
'//----------------------------------------------------------------------------

'//----------------------------------------------------------------------------
'// Main routine
'//----------------------------------------------------------------------------
Function UserExit(sType, sWhen, sDetail, bSkip)
	UserExit = Success
End Function

Function GetAbbrModel()
	on error goto 0
	Dim sMake : sMake = oEnvironment.Item("Make")
	Dim sModel : sModel = oEnvironment.Item("Model")
	Dim sAbbrModel : sAbbrModel = "UNK"

	Select Case UCase(sMake)

		Case UCase("Dell")

			If InStr(1,sModel,"OptiPlex ",1) > 0 Then
				sAbbrModel = Left(Replace(sModel,"ptiPlex ","",1,-1,1),3)
			elseif InStr(1,sModel,"Latitude ",1) > 0 Then
				sAbbrModel = Left(Replace(sModel,"Latitude ","",1,-1,1),3)
			elseif InStr(1,sModel,"XPS",1) > 0 Then
				sAbbrModel = Left(Replace(sModel,"PS","",1,-1,1),3)
			end if

		Case UCase("Lenovo")
			Dim oCSP
			For Each oCSP in GetObject("winmgmts:").ExecQuery("SELECT Version,Name FROM Win32_ComputerSystemProduct")
				Dim sLenovoModel : sLenovoModel = oCSP.Version
				Dim sLenovoProductType : sLenovoProductType = oCSP.Name
				exit for
			Next

			If InStr(1,sLenovoModel,"ThinkCentre ",1) > 0 Then
				sAbbrModel = Left(Replace(sLenovoModel,"ThinkCentre ","",1,-1,1),3)
			elseif InStr(1,sLenovoModel,"ThinkStation ",1) > 0 Then
					sAbbrModel = Left(Replace(sLenovoModel,"ThinkStation ","",1,-1,1),3)
			elseif InStr(1,sLenovoModel,"ThinkPad ",1) > 0 Then
				if Instr(1,sLenovoModel,"Carbon",1) > 0 Then
					If InStr(1,sLenovoModel,"Carbon 4th",1) > 0 Then
						sAbbrModel = Left(Replace(Replace(Replace(sLenovoModel,"ThinkPad ","",1,-1,1),"arbon 4th","")," ",""),3)
					elseif InStr(1,sLenovoModel,"Carbon 3rd",1) > 0 Then
						sAbbrModel = Left(Replace(Replace(Replace(sLenovoModel,"ThinkPad ","",1,-1,1),"arbon 3rd","")," ",""),3)
					elseif InStr(1,sLenovoModel,"Carbon 2nd",1) > 0 Then
						sAbbrModel = Left(Replace(Replace(Replace(sLenovoModel,"ThinkPad ","",1,-1,1),"arbon 2nd","")," ",""),3)
					elseif InStr(1,sLenovoModel,"Carbon",1) > 0 Then
						sAbbrModel = Left(Replace(Replace(Replace(sLenovoModel,"ThinkPad ","",1,-1,1),"arbon","")," ",""),3)
					end if
				else
					sAbbrModel = Left(Replace(sLenovoModel,"ThinkPad ","",1,-1,1),3)
				end if
			else
				' Alternatively you could build & maintain (yuck) a table of product types
				Select Case UCase(Left(sLenovoProductType,4))
					Case UCase("5032")
						sAbbrModel = "M81"

					case UCase("20EF")
						sAbbrModel = "W54"
				End Select
			end if

		Case UCase("innotek GmbH")
			sAbbrModel = UCase(Left(sMake,1) & Mid(sMake,8,1) & Right(sMake,1))

		Case UCase("VMware, Inc.")
			sAbbrModel = UCase(Left(sMake,3))

		Case UCase("Microsoft Corporation")
			sAbbrModel = "HPV"

	End Select
	GetAbbrModel = sAbbrModel
End Function

Preparing for Windows 10: Move Computers into to Win 10 OUs

One thing that has annoyed me about MDT and SCCM was that there wasn’t a built-in method to move machines into the proper OU.  As such it required creating something from scratch and I opted for something that didn’t require dependencies, like the ActiveDirectory module.

This isn’t the best way and this isn’t the only way – it’s just a way; one of many in fact.

Please note that this is NOT the ideal way to handle any operations that require credentials!  Keeping credentials in a script is bad practice as anyone snooping around could happen upon them and create some problems.  Instead, you should rely on web services to do this and Maik Koster has put together an excellent little care package to help get you started.

Move-ComputerToOU Prerequisites

My script has a few prerequisites:

  • The current AD site
  • A [local] Domain Controller to use (recommended)
  • The current OU of the machine to be moved
  • The new OU to move the machine into

It’s important to know that this script does not rely on the ActiveDirectory module.
One of my [many] quirks is to try to keep everything self-contained where it makes sense to do so, and I liked the idea of not having to rely on some installed component, an EXE and so on.  But to be honest, web services is the way to go for this.

Getting the Current AD Site

Better see this post for that.

Getting a Local Domain Controller

Better see this post for that.

Getting the Current OU

Better see this post for that.

Getting / Setting the New OU

If this is being executed as part of an OSD, yank those details from the MachineObjectOU Task Sequence variable via something like:

Function Get-TaskSequenceEnvironmentVariable
    {
        Param([Parameter(Mandatory=$true,Position=0)]$VarName)
        Try { return (New-Object -COMObject Microsoft.SMS.TSEnvironment).Value($VarName) }
        Catch { throw $_ }
    }
$MachineObjectOU = Get-TaskSequenceEnvironmentVariable MachineObjectOU

Otherwise just feed it the new OU via the parameter

Process Explanation

We first have to find existing object in AD


# This is the machine we want to move
$ADComputer = $env:COMPUTERNAME

# Create Directory Entry with authentication
$de = New-Object System.DirectoryServices.DirectoryEntry($LDAPPath,"$domain\$user",$pass)

# Create Directory Searcher
$ds = New-Object System.DirectoryServices.DirectorySearcher($de)

# Fiter for the machine in question
$ds.Filter = "(&(ObjectCategory=computer)(samaccountname=$ADComputerName$))"

# Optionally, set other search parameters
#$ds.SearchRoot = $de
#$ds.PageSize = 1000
#$ds.Filter = $strFilter
#$ds.SearchScope = "Subtree"
#$colPropList = "distinguishedName", "Name", "samaccountname"
#foreach ($Property in $colPropList) { $ds.PropertiesToLoad.Add($Property) | Out-Null }

# Execute the find operation
$res = $ds.FindAll()

 

Then we bind to the existing computer object


# If there's an existing asset in AD with that sam account name, it should be the first - and only - item in the array.
# So we bind to the existing computer object in AD
$CurrentComputerObject = New-Object System.DirectoryServices.DirectoryEntry($res[0].path,"$domain\$user",$pass)

# Extract the current OU
$CurrentOU = $CurrentComputerObject.Path.Substring(8+$SiteDC.Length+3+$ADComputerName.Length+1)

 

From there setup the destination OU


# This Here we set the new OU location
$DestinationOU = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$SiteDC/$NewOU","$domain\$user",$pass)

 

And finally move the machine from the old/current OU to the new/destination OU


# And now we move the asset to that new OU
$Result = $CurrentComputerObject.PSBase.MoveTo($DestinationOU)

Move-ComputerToProperOU.ps1

So this is a shortened version of the script I’m using in production.  All you need to do is fill in the blanks and test it in your environment.


# There's a separate function to get the local domain controller
$SiteDC = Get-SiteDomainController
# Or you can hard code the local domain controller
$SiteDC = 'localdc.domain.fqdn'

# Build LDAP String
# I //think// there were maybe two cases whre this din't work
$LocalRootDomainNamingContext = ([ADSI]"LDAP://$SiteDC/RootDSE").rootDomainNamingContext
# So I added logic to trap that and pull what I needed from SiteDC
#$LocalRootDomainNamingContext = $SiteDC.Substring($SiteDC.IndexOf('.'))
#$LocalRootDomainNamingContext = ($LocalRootDomainNamingContext.Replace('.',',DC=')).Substring(1)

# Building the LDAP string
$LDAPPath = 'LDAP://' + $SiteDC + "/" + $LocalRootDomainNamingContext

# Set my domian for authentication
$domain = 'mydomain'

# Set the user for authentication
$user = 'myjoindomainaccount'

# Set the password for authentication
$pass = 'my sekret leet-o-1337 creds'

# This is the machine I want to find & move into the proper OU.
$ADComputerName = $env:COMPUTERNAME

# This is the new OU to move the above machine into.
$NewOU = 'OU=Laptops,OU=Win10,OU=Office,OU=CorpWorkstations,DC=domain,DC=fqdn'

# Create Directory Entry with authentication
$de = New-Object System.DirectoryServices.DirectoryEntry($LDAPPath,"$domain\$user",$pass)

# Create Directory Searcher
$ds = New-Object System.DirectoryServices.DirectorySearcher($de)

# Fiter for the machine in question
$ds.Filter = "(&(ObjectCategory=computer)(samaccountname=$ADComputerName$))"

# Optionally, set other search parameters
#$ds.SearchRoot = $de
#$ds.PageSize = 1000
#$ds.Filter = $strFilter
#$ds.SearchScope = "Subtree"
#$colPropList = "distinguishedName", "Name", "samaccountname"
#foreach ($Property in $colPropList) { $ds.PropertiesToLoad.Add($Property) | Out-Null }

# Execute the find operation
$res = $ds.FindAll()

# If there's an existing asset in AD with that sam account name, it should be the first - and only - item in the array.
# So we bind to the existing computer object in AD
$CurrentComputerObject = New-Object System.DirectoryServices.DirectoryEntry($res[0].path,"$domain\$user",$pass)

# Extract the current OU
$CurrentOU = $CurrentComputerObject.Path.Substring(8+$SiteDC.Length+3+$ADComputerName.Length+1)

# This Here we set the new OU location
$DestinationOU = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$SiteDC/$NewOU","$domain\$user",$pass)

# And now we move the asset to that new OU
$Result = $CurrentComputerObject.PSBase.MoveTo($DestinationOU)

 

Happy Upgrading & Good Providence!

Finding a Local Domain Controller

I created this function ages ago as part of a larger script that needed to be executed completely unattended.

Since I started down the System Engineer / Desktop Engineer / Application Packager path a handful of years ago, I’ve seen some interesting behaviors.  For example, when joining a domain, a machine might reach out to a domain controller overseas versus one at the local site or even in the same continent.  And because things were working, those types of anomalies were never really looked into.

This only ever really came up when there were OU structure changes.  For instance, when going from XP to Windows 7, or after completing an AD remediation project.  As machines were being moved around, we noticed the Domain Controller used varied and the time it took to replicate those changes varied from:

  • instantaneously – suggesting the change was made on a local DC OR a DC with change notification enabled
  • upwards of an hour – suggesting a remote DC (and usually verified by logs or checking manually) or on a DC where change notification was not enabled.

So I decided to write a small function for my scripts that would ensure they were using a local Domain Controller every time.

There are a handful of ways to get a domain controller

  • LOGONSERVER
  • dsquery
  • Get-ADDomainController
  • Other third-party utilities like adfind, admod

But either they were not always reliable (as was the case with LOGONSERVER which would frequently point to a remote DC) or they required supporting files (as is the case with dsquery and Get-ADDomainController).  Nothing wrong with creating packages, adding these utilities to %ScriptRoot% or even calling files on a network share.
I simply preferred something self-contained.

Find Domain Controllers via NSLOOKUP

I started exploring by using nslookup to locate for service record (SRV) resource records for domain controllers and I landed on this:

nslookup -type=srv _kerberos._tcp.dc._msdcs.$env:USERDNSDOMAIN

Problem was it returned every domain controller in the organization.  Fortunately  you can specify an AD site name to narrow it down to that specific AD Site:

nslookup -type=srv _kerberos._tcp.$ADSiteName._sites.$env:USERDNSDOMAIN

Bingo!  This gave me exactly what I was hoping to find and the DC’s it returns are in a different order every time which helps to round-robin things a bit.

From there it was all downhill:

  1. Put AD Sites in the script
  2. Figure out which Site the machine is in by it’s gateway IP
  3. Use nslookup to query for SRV records in that site
  4. Pull the data accordingly.

Yes I know – hard coding AD Sites and gateway IP’s is probably frowned upon because

What if it changes?

I don’t know about your organisation but in my [limited] experience the rationale was that AD Sites and gateway IP’s typically don’t change often enough to warrant that level of concern, so it didn’t deter me from using this method.  But I do acknowledge that it is something to remember especially during expansion.

Also, I already had all of our gateway IP’s accessible in a bootstrap.ini due to our existing MDT infrastructure making this approach much simpler workwise.

Get-SiteDomainController

And here’s where I ended up.  The most useful part – to me anyway – is that it works in Windows (real Windows) at any stage of the imaging process and doesn’t require anything extra to work.  The only gotcha is that it does not work in WinPE because nslookup isn’t built-in and I don’t know why after all these years it still isn’t built-in.

Function Get-SiteDomainController
    {
        Param
            (
                [Parameter(Mandatory=$true)]
                    [string]$Site,

                [Parameter(Mandatory=$true)]
                    [string]$Domain
            )
        Try { return (@(nslookup -type=srv _kerberos._tcp.$Site._sites.$Domain | where {$_ -like "*hostname*"}))[0].SubString(20) }
        Catch { return $_ }
    }

Hindsight

I’ve been using the above method for determining the local DC for years and its been super reliable for me.  It wasn’t until recently that I learned that the query I was using would not always return a domain controller since the query simply locates servers that are running the Kerberos KDC service for that domain.  Whoops.

Instead, I should have used this query which will always only return domain controllers:

nslookup -type=srv _kerberos._tcp.$ADSiteName._sites.dc._msdcs.$env:USERDNSDOMAIN

 

Honorable Mention: NLTEST

I would have been able to accomplish the same task with nltest via

nltest /dclist:$env:USERDNSDOMAIN

And then continuing with the gateway IP to AD Site translation to pull out just the entries I need.

nltest /dclist:$env:USERDNSDOMAIN | find /i ": $ADSiteName"

One interesting thing to note about nltest is that it seems to always return the servers in the same order.  This could be good for consistency’s sake, but it could also be a single point of failure if that first server has a problem.

The nslookup query on the other hand returns results in a different order each time it’s executed.  Again, this could also be bad, making it difficult to spot an issue with a Domain Controller, but it could be good in that it doesn’t halt whatever process is using the output of that function.

¯\_(ツ)_/¯

Anyway, since the nslookup script has been in production for some time now and works just fine, I’m not going to change it.  However, any future scripts I create that need similar functionality will likely use the updated nslookup query method.

 

Good Providence!

Determine AD Site

I created this function ages ago as part of a larger script that needed to be executed completely unattended.

For a variety of reasons, I needed a reliable way to determine which AD Site a particular machine was in.  Over the years I’ve seen some really odd behaviors that – technically – shouldn’t happen.  But as with many organizations (one hopes anyway…) things don’t always go as planned so you need that backup plan.

Get-Site Prerequisites

My script has a few prerequisites:

I personally try to keep everything self contained where it makes sense to do so.  It’s one of my [many(?)] quirks.

Finding the Current Default Gateway IP

Better see this post for that.

Get-Site Explained

In our environment, the machine names contain the office location which makes it easy to figure out where the machine is physically.  However, not every machine is named ‘correctly’ (read: follows this naming convention) as they were either renamed by their owners or are running an image prior to this new naming convention.  This is why I’m leveraging a hash table array of IP’s as a backup.

It seemed tedious at first, but since I already had a list of IP’s in the bootstrap.ini so it made this a little easier.  Also, Site IP’s don’t change often which means this should be a reliable method for years to come with only the occasional update.

Function Get-Site
    {
        Param([Parameter(Mandatory=$true)][string]$DefaultGatewayIP)

        Switch($env:COMPUTERNAME.Substring(0,2))
            {
                { 'HQ', 'TX', 'FL' -contains $_ } { $Site = $_ }
                Default
                    {
                        $htOfficeGateways = @{
                            "Headquarters"  = "192.168.0.1","192.168.10.1";
                            "Office1"       = "192.168.1.1","192.168.11.1";
                            "Office2"       = "192.168.2.1","192.168.12.1";
                        }

                        $DefaultGatewayIP = '192.168.0.1'
                        #$DefaultGatewayIP = '192.168.1.1'
                        #$DefaultGatewayIP = '192.168.2.1'

                        Foreach($Office in ($htOfficeGateways.GetEnumerator() | Where-Object { $_.Value -eq $DefaultGatewayIP } ))
                            {
                                Switch($($Office.Name))
                                    {
                                        "Headquarters" { $Site = 'HQ' }
                                        "Office1"      { $Site = 'TX' }
                                        "Office2"      { $Site = 'FL' }
                                    }
                            }
                    }
            }
        return $Site
    }

 

I didn’t add a check prior to returning $Site to confirm it was actually set but that can be handled outside of the function as well.  Otherwise you could do $Site = 'DDOJSIOC' at the top and then check for that later since that should never be a valid site … unless you’re Billy Rosewood.