The following is a procedure for updating Operating System image data in UDI that is specific to the UVM environment. Use it as a template for your own operations:

Add the new WIM image to SCCM. The WIM must contain only one OS image (e.g. at index 1).

Run c:localscriptsCM-TaskSequencesbuild-udiInfoFiles.ps1.(This make a CSV files available to the UDI client that matches the OS Image Name to the version of the OS within the image.) (Required for driver injection.)

Run c:localscriptsCM-TaskSequencesbuild-udiImageList.ps1.(This updates the UDI XML-based control file that generates the OS selection options to the end-user in the UDI Wizard.)

Run c:localscriptsUpdate-OSApplyTaskSequence.ps1. When prompted, provide the name of the UDI task sequence to be updated.(This script updates the task sequence so that the OS selected in the UDI Wizard can be applied to the UDI target machine.)

Locate the “MDT 2013 Files” package in the SCCM console under Software Library->Application Management->Packages, and run an “Update Distribution Points” action. Verify that distribution was successful before proceeding.(This makes the new CSV info files and Wizard configs available to end-users.)

Create a new folder under the matching OS version folder (i.e. Win7 or Win8) within the driver import source directory: “\confman3sourcesdriversimport“. The name of this new folder must match the model information discovered in step 2. Extract the new drivers into this folder.

If updating a model: Update the driver source:

Locate the source folder for the driver package to update. Remove all contents of the directory including the “.hash” file in the root.

Extract the new drivers into this folder.

If updating a model: Cleanup existing drivers in SCCM:

Find the package to be updated in the SCCM management console. Delete it.

Right-click and get the properties on any driver in the SCCM console. Call up the list of driver categories, and delete the category for the driver to be updated.

Import the drivers from source:

Run C:localscriptsCM-DriversImportDrivers.ps1 to import the new drivers into the SCCM environment. The script will create new packages and driver categories for each new folder that you created.

Wait.

Distribute the drivers:

Refresh the SCCM console to reveal the new driver packages and categories.

Right-click the driver package and select “Distribute Content”. Distribute the drivers to “Confman2”.

Monitor the distribution process in the bottom pane of the SCCM console. Make sure distribution succeeds before proceeding.

If adding a model/package: Update the MDT files with the new driver information:

Run C:localscriptsCM-TaskSequencesbuild-UdiInfoFiles.ps1 on Confman3

Locate the “MDT 2013 Files” package in the SCCM console under Software Library->Application Management->Packages, and run an “Update Distribution Points” action. Verify that distribution was successful before proceeding. This will publish a new list of drivers packages to the UDI clients.

If adding a model/package: Update the OS Installation Task Sequence:

Run C:localscriptsCM-TaskSequencesUpdate-DriverInjectionTaskSequence.ps1. Specify the name of the Task Sequence to update when prompted, or provide the name using the “-name” parameter. This script will update the Task Sequence to allow for injection of the new driver package, if one is available for the current model.

If adding or updating WinPE, Peripheral, or “Other” drivers: Update the boot media:

In the SCCM console under Software Library->Operating Systems->Drivers, select “Saved Searches”, then select WinPE 64-bit or WinPE 32-bit. Once the drivers have been filtered, Select All, and then right-click and select Edit->Boot Images. Select the MDT boot image for your architecture (32-bit or 64-bit).

For boot media, select the MDT boot image that you updated in part 8a. For distribution point, select CONFMAN2. For Management Point, select CONFMAN3.

Complete the wizard, and then distribute the boot media to the usual locations (\filessoftwaredeploy).

As noted above, you need a custom Workstation Authentication certificate to generate the boot media. If your certificate has expired or you want to generate a new certificate for any other reason, use the following procedure, adopted from:

From a workstation that has access to your Certificate Authority web interface, open Internet Explorer using your admin account, and access:https://caServer.domain.edu/certsrv/
Logon as a user with rights to generate workgroup certificates. Currently this is scoped to high-level admins in our organization.

Add the site to the “Trusted sites” zone in your Internet Settings Control Panel.

Activate “compatibility view” if your CA is still running on Server 2008 R2, otherwise the required ActiveX controls will not load.

Note: This is a lightly-modified copy of the stock “Workstation Authentication” certificate template. As per MS requirements, the certificate has been forced to use the legacy “Server 2003” certificate format, not the Vista+ “CNG” format.

An Enterprise Admin can add permissions to the template to allow enrollment rights for additional users/groups, if necessary.

Fill in the identifying information and friendly name for the certificate. Make sure to select the option to “Mark keys as exportable”, then click “Submit”.

When prompted, install the certificate. The certificate will be installed into the “Personal” or “My” store for the user running Internet Explorer.

Run MMC.EXE as the user who requested the certificate:

Add the “Certificates” snap-in for the current user.

Navigate to the “personal” store. Locate the new certificate.

Right-click the certificate and select All Tasks -> Export.

In the certificate export wizard, select the option “Yes, export the private key.”

Select Personal Information Exchange – PCKS #12 (.PFX), and ensure that “Include all certificates in the certification path if possible” AND “Export all extended properties” are checked, then click Next.

Type in a password and confirm it in the boxes provided on the Password screen, then click Next. (Save this password for later use)

Browse for a location to which to export the certificate. Make sure that it is somewhere accessible from SCCM, give it a name (i.e. ‘WinPE-Cert.pfx’) and click Save.

In the previous parts of this blog series I have shown how PowerShell and VBScript can be used to automate Driver, Application, and Operating System selection and installation in MDT/UDI. In this final post I will discuss a few final UDI quirks that we worked though without using scripts.

UDI Boot Media:

We experienced an odd problem during our OS Deployments when booting from SCCM/UDI media. The deployment process starts, as documented, with a dialog allowing the user to configure the networking environment for OS deployment, followed by a Task Sequence selection dialog. After selecting the task sequence, we expected some scripts to run, followed by the initiation of the UDI Wizard dialogs. Instead what we found was that UDI would first format an partition the local drive, copy a new WinPE environment to the drive, and then restart into WinPE running from local disk before brining up the UDI Wizard. This created a substantial delay between Task Sequence selection and the start of the Wizard. My impression was that users would find this delay unacceptable.

Our MS consultant suggested that this was happening because the revision of the UDI/WinPE environment on our boot media did not match boot image referenced by our active task sequence. To test this, we rebuilt all of the boot images in our environment from the Windows 8.1 ADK sources, then created a new MDT boot image from the ADK image, created a new task sequence referencing the ADK image, and finally generated new UDI Boot Media with the MDT boot image as a source. After completing these actions and updating our distribution points, we were able to get the UDI Wizard to start after Task Sequence selection without first requiring a reboot.

Improper OS Drive Letter Assignment

In our first deployments, we found that at the end of the Task Sequence, our operating system was left running on a D: or E: drive, instead of the usual “C:” drive. Knowing full well that this could cause massive end user confusion, I set out to correct this problem.

After weighing the options, I chose to try the “Delete Mounted Devices from registry” option. This required me to import a custom task sequence into our SCCM instance, and then copy/paste the required Task Sequence steps into our production Task Sequence. This approach instantly was successful, so I am sticking with it. Thanks again, Michael.

Failure of UserExit Script Processing

Under MDT/LTI, we made use of the “User Exit Script” capabilities of MDT to generate unique default computer names for UDI clients. Cursory inspection of the docs suggested that User Exit script functionality also is supported under SCCM/UDI, so I decided to transplant our script. However, after doing so I found that the default presented in the UDI Wizard was #GenUniComp()#, rather than a generated computer name.

#GenUniComp()# is the value assigned in our CustomSettings.ini file for the OSDComputerName variable. However, MDI/UDI is supposed to “exit” any code placed between the hash tags (#) out to the Windows Scripting Host. “GenUniComp” is the name of a VBScript function that I defined in our “ZUVMUserExit.vbs” User Exit script. The function works well enough under MDT/LTI, so what is going wrong in UDI?

To diagnose this problem, it helps to know a bit about how User Exit scripts are processed. “UserExit” is set as a variable in the CustomSettings.ini for your environment. This variable is detected and processed by the ZTIGather.wsf script that is run several times during each MDT/LTI and SCCM/UDI deployment. To troubleshoot problems with the script, you should look to the SCCM/UDI log files generated by ZTIGather.wsf. When I examined the ZTIGather logs, I could find no reference at all to the UserExit variable getting processed by the ZTIGather script. The next logical question is, why not?

Logically, the problem is not likely to be caused by an error in the script. First, the same script works just fine under MDT/LTI. Additionally, the script uses the MDT logging functions, so if it had executed, we would have expected to see at least some log output. I thus assumed that the script was not getting executed at all. I started looking at the ZTIGather logs from the top, and found reported “processing [Settings]…” followed immediately by “processing [Default]…”. Interestingly, I had defined the UserExit variable under the [Settings] section of CustomSettings.ini, which worked find under MDT/LTI. However, the SCCM version of ZTIGather appears to process only “Priority” and “Properties” settings under the [Settings] section. My UserExit definition was getting ignored because it was in the wrong place. After moving the “UserExit” definition to the [Default] section, UDI started to process the GenUniComp() function of my User Exit script just as it had under MDT/UDI.

While our UserExit script is not really involved in driver handling, I am including it below just for the sake of completeness:

In the final section of this series, I will present operational instructions for the use of these scripts in our environment. These documents are tailored for the UVM environment, but might serve as a template for instructions at other sites.

Previously in this series I demonstrated how you can manage Operating System selection and application in UDI, and one (rather complicated) method for managing drivers in SCCM/UDI. To complete our UDI experience, I now present a handy script for automation of populating select SCCM applications into UDI.

There is some conventional wisdom floating around out there in the ‘tubes that you should not deploy the new SCCM 2012-style “Applications” in SCCM OSD Task Sequences. Instead, it is asserted that you should use only traditional application “Packages”. Since we have developed all or our application installer using the new “Application” objects, I have chosen to ignore this guidance. Fortunately, it appears that the earlier bugs that led to dispensing of this advice have been corrected in the 2012 R2 CU2-CU3 timeframe.

The script below will make use of Configuration Manager application tags to determine which Applications should be populated into UDI. Additionally, the tags are used to generate application groups in the UDI wizard. If you don’t want an application to appear in UDI, don’t tag it. Applications can have multiple tags, and thus can end up getting defined more than once un UDI. This does not appear to cause any problems during deployment.

This script will re-write the entire UDI designer “.app” file, which is an XML-formatted document that defines all of the applications and groups that will be displayed during the UDI Wizard (the default name for this file is ‘UDIWizard_Config.xml.app’). Because I am writing out the entire file, I chose to use the System.Xml.XmlTextWriter .Net Framework class to do the heavy lifting for me. I probably could have used System.Xml.XmlDocument (which I used in part 3 of this series for updating the main UDI XML control file), but the XmlTextWriter seemed to be a more direct route to getting the job done in this case.

Note that in this code I am again using the SCCM PowerShell cmdlets. In this case, I am using Get-CMCategory and Get-CMApplication. These commands easily could be replaced with simple WMI queries (as seen in part 3 of this series). I also am using some SCCM managed code. I call the “Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer” class in order to use the “Deserialize” method. This method converts the large volume of data in the SDMPackageXML attribute of the application object into somewhat more accessible PowerShell objects.

To use this script in your environment, you will need to update the $outPath, $CMSiteCode, and $CMBinPath variables to match your environment. After running the script, you will need to redistribute the content of your MDT Files package to your distribution points. You UDI clients will read the new data as soon as it is made available on your DP.

In part 3a of this series, I provided a script that automates updating of the OS selection dialog boxes in UDI. I also noted that while UDI presents that OS selection, the UDI client ignores the selection and instead installs whichever OS image was specified at image creation time. This was very frustrating because I was able to verify that the syntax of the generated UDI XML file was correct. In examining the task sequence logs, I even could see that the “OSDImageName” and “OSDImageIndex” variables had been set as expected. Yet still UDI would not apply the select image. Why?

The observant reader will notice that the “Apply Operating System Image” task sequence step does not contain a variable for supplying an image name or path. You only can provide an image index. It looks like MS only supports selection of different images indexed in one monolithic WIM image. I am not enamored with this limitation, so I have authored the following script which will create one “Apply Operating System Image” for each OS in the SCCM inventory. Each step will have a condition that will allow the step to run only if the OSDImageName environment variable matches the name of the image specified in the task sequence step. Note that we are assuming only one image per WIM file in this case, so the image index of the selected WIM has to be ‘1’.

The script will create a single group of Apply Operating System tasks (one task for each OS Image Package in the infrastructure) in the Task Sequence, using the group name supplied in the $TSPackageName variable. If the group already exists, it will be updated. Additionally, if the stock "Apply Operating System Image" step is still present, it will be removed. Each time you add or remove an OS Image, you will need to re-run the script and re-copy/paste the actions.

We have now dealt with handling Drivers and Operating Systems in SCCM/UDI OS deployment. That leaves managing UDI application selection, which I will discuss in part four of this series, coming up next.

In this part of the series, I will make it possible for the end-user to select from a list of available operating system images. I will provide required scripting logic to update this selection automatically, and I will provide an additional script to make these selections work as expected. (The out-of-box UDI image selection process makes no intuitive sense at all, as we shall soon see.)

Under MDT/LTI, we used Task Sequences as the unit to control the selection of operating systems by the end user. This was necessary because the LTI wizard did not provide an operating system selection dialog. We could have authored our own OS selection dialog, but back when UVM was new to MDT (then BDD) I was a wet-behind-the-ears programmer, and programming of BDD was more difficult. However, under UDI we have the option to allow the user to select different operating systems within the UDI Wizard, so we no longer need one Task Sequence per operating system. I think that this is a positive development, although maintenance of this option proved to be more difficult than expected.

First challenge: Programmatic updating of OS Selections in the UDI Wizard

Anyone who has done experimentation with UDI surely is familiar with the UDI Designer tool. This tool provides a GUI which generates a somewhat large XML file that controls the options that are presented to UDI clients. The UDI designer allows the administrator to select the objects within SCCM that will be presented to the end-user. While this presentation granularity may be desirable for some, it presents a maintenance challenge for us. Any time an object is updated in the SCCM inventory, we need to update the UDI dialogs as well, and Microsoft provides no out-of-box means of updating these links. While this is only a minor problem for OS Image updates, it is a major hassle for Application updates. Since we really needed to solve this problem for Application updates, adding logic for operating systems was an easy extension.

To solve this problem, we need to script the reconfiguration of our UDI wizard XML file. Microsoft likes to claim that PowerShell provides “powerful” XML handling capabilities. In my experience, this claim is debatable as the built-in cmdlets have limited XML formatting capabilities. However, the .NET framework upon which PowerShell is built does provide many classes for XML handling. In this script we will be using the ‘[xml][/xml]’ type accelerator. This accelerator represents the System.Xml.XmlDocument .NET Class, for which full documentation is available in MSDN:https://msdn.microsoft.com/en-us/library/system.xml.xmldocument(v=vs.110).aspx

I also use the “Get-CMOperatingSystemImage” SCCM PowerShell cmdlet. As mentioned previously, I recommend avoiding the use of the cmdlets as they behave unpredictably. However, this particular cmdlets appears to work as well as we need it to. If you hate it, the commands could replaced with a WMI calls, although you would need to first discover the OS images:

And then retrieve the “full object”, since the above query will not retrieve the required “ImageProperty” attribute (which Microsoft calls a “loosely bound” attribute):

$fullImages = @()
$fullImages += $images | % {[wmi] $_}

To use this script in your environment, you would need to update the $udiXmlIn and $udiXmlOut paths to match the desired locations of the UDIWizard_Config.xml in your environment. These paths can be the same, if desired. You also will need to update the $CMSiteCode and $CMBinPath variables.

After running this script, our UDI Wizard correctly displays all available OS Images in our environment. However, we found that the selections were not being honored by the UDI process. The fault is not in this script, but rather in the logic used by UDI. We will explore the fix for this in the next part of the series (3b).

So, my driver handling routine is probably looking pretty scary right now. There are a lot of scripts that need to be run, and I have not discussed where to put them, or in which order they should be executed. In part 6 of this series, I will provide playbook procedures for using the scripts. Here I will provide a sys admin’s overview of where the scripts should be stored, and how they work with each other.

Script location and customization:

Copy ImportDrivers.ps1, Update-DriverInjectionTaskSequence.ps1, UVM-ConfigurationManager.psm1, Create-UDIInfoFiles.ps1, and Build-UDIImageList.ps1 (see part 3) to a local directory on your Management Point or Site Server. We use “c:localscripts”, with “CM-[Category]” subdirectories for each category of script. I keep dependencies such as the “UVM-ConfigurationManager.psm1 in the “Script Root” directory.

Review the starting sections for each file for local references that you might need to customize for your site.

Update the path to the “UVM-ConfigurationManager.psm1” PowerShell module in the Create-UDIInfoFiles script.

Update the path to the “UVM-ConfigurationManager.psm1” file in the Update-DriverInjectionTaskSequence script.

Update the path to your MDT Files package source in the Create-UDIInfoFiles script.

Copy the ZUVMDetectDriverPackage.wsf file into the “Scripts” directory of your MDT Files package.

Script sequence and dependency chains:

Run “ImportDrivers.ps1” – creates the Driver Packages and groups referenced by all future scripts and operations. Note that the script does not distribute the packages that get created. You must do this manually. Anyone want to share a tip on programmatic package distribution?

The remaining server side scripts can be run in any order. After running the scripts, you must re-distribute your MDT Files to your distribution points or the UDI Task Sequence will fail with missing file or missing dependency errors.

I think that covers the procedure. I will work on streamlining the process to make it simpler to implement.