Migrating to the SCCM UDI for OSD, part 3a: Operating System Selection

Continued from part 2f:
http://blog.uvm.edu/jgm/2015/03/09/sccm-udi-2f/

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 ” 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:

$images = Get-WmiObject -namespace root/sms/site_[SiteCode] -Class SMS_ImagePackage | %{$_.__Path}

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.

# build-UDIImageList.ps1
# J. Greg Mackinnon
# Created: 2015-01-26
# Updated: 2015-03-17 - Added host output to indicate task progress.
# Populates the UDI Configuration Wizard XML file with all Operating System images gathered from
# Configuration Manager.  
# Requires: a local installation of the Configuration Manager administration tools.
#   Modify $udiXmlIn, $udiXmlOut, $CMSiteCode, and $CMBinPath to match your environment.

[string] $udiXmlIn = 'O:\sources\os\mdt\files\Scripts\UDIWizard_Config.xml'
[string] $udiXmlOut = 'O:\sources\os\mdt\files\Scripts\UDIWizard_Config.xml'


[string] $CMSiteCode = 'UVM'

[string] $CMBinPath = 'F:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\'
[string] $CMModName = 'ConfigurationManager.psd1'
[string] $CMModPath = Join-Path -Path $CMBinPath -ChildPath $CMModName

[string] $CMDrive = $CMSiteCode + ':\'

Import-Module -Name $CMModPath | Out-Null

Push-Location $CMDrive

write-host "Gathering OS Images from SCCM..." -ForegroundColor Yellow
$osImages = Get-CMOperatingSystemImage | select -Property Name,ImageProperty

write-host "Loading the current UDI Wizard configuration file..." -ForegroundColor Yellow
$udiXml = Get-Content $udiXmlIn
$dataElement = ($udixml.wizard.pages.page | ? -Property Name -eq 'VolumePage').data
# XPath variation, not working for some reason:
#$imgSel = $udiXml.SelectNodes("wizard/pages/page[@Name=""VolumePage""]")

#Clear the existing Nodes:
$dataElement.RemoveAll()
#Add the name/Imageselection attribute back in to the element:
$dataElement.SetAttribute('Name','ImageSelection')

write-host
foreach ($image in $osImages) {
    #Create a new DataItem element for each OS Image:
    $dataItemElement = $udiXml.CreateElement('DataItem')
    $dataElement.AppendChild($dataItemElement) | out-null

    # Read information from the existing image:
    $imageXml = $image.ImageProperty
    [string]$ImageName = $image.Name
    [string]$Index = $imageXml.WIM.IMAGE.Index
    [string]$archNumber = ($imageXml.WIM.IMAGE.Property | ? -Property Name -eq 'Architecture').'#text'
    if ($archNumber -eq '9') {
        [string]$Architecture = 'amd64'
    } elseif ($archNumber -eq '0') {
        [string]$Architecture = 'x86'
    } else {
        [string]$Architecture = ''
    }
    #The UDI DisplayName value does not need to be tied to a property in SCCM, 
    # but we will use the matching Display Name in the SCCM GUI, which is mapped out below:
    [string]$DisplayName = $imageXml.WIM.IMAGE.name
    
    write-host "Adding image named: $DisplayName" -ForegroundColor Yellow

    #Add collected image info to a new array
    [array[]]$setters = @(
        @('DisplayName', $DisplayName),
        @('Index', $Index),
        @('Architecture', $Architecture),
        @('ImageName', $ImageName)
    )

    #Now feed data from the info array as "setter" elements under the "DataItem" element:
    foreach ($setter in $setters) {
        write-host "    Adding element: '"$setter[0]"' with property '"$setter[1]"'" -ForegroundColor cyan
        $setterElement = $udiXml.CreateElement('Setter')
        $setterElement.SetAttribute('Property',$setter[0])
        $setterElement.InnerText = $setter[1]
        $dataItemElement.AppendChild($setterElement) | out-null
    }
}

$udiXml.Save($udiXmlOut)

Pop-Location

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).

Next: Operating Systems – Update the Task Sequence with new OS Image data
http://blog.uvm.edu/jgm/2015/03/10/sccm-udi-3b-os/


Series Index:

2 thoughts on “Migrating to the SCCM UDI for OSD, part 3a: Operating System Selection

  1. Pingback: Migrating to the SCCM UDI for OSD, part 3b: Operating System Selection (Continued) | jgregscorral

  2. Pingback: Migrating to the SCCM UDI for OSD, part 4: Applications | jgregscorral

Comments are closed.