The Pursuit of a Low Effort ZTI
By Steve Bowman
Published May 25, 2016
Estimated Reading Time: 3 minutes

Recently I was engaged on a project to consolidate an SCCM 2012 environment and bring it up to the current branch version of 1602. One of the focuses of this engagement was providing a windows 10 task sequence to help provision new devices in a “New Computer” scenario. Imaging devices with Windows 10 is much kinder than most of the previous versions of Windows, but Powershell with WinPE makes life much simpler. Long ago when time was young, doing zero touch installations normally involved things like the MDT database. That database was queried to provide conditionals for logic in your task sequence as well as set task sequence variables to limit the amount of human involvement in the imaging process. With Powershell becoming the uber tool it has, you can now incorporate the power of Powershell into WinPE to go from an extremely complex ZTI infrastructure to a single script ran at the beginning of your task sequence.


So while working on OSD in the client’s environment, they had a few automation desires. First was naming the computer which is normally a piece of cake when you have a standard in place. Second was a dynamic Organizational Unit placement when joining the domain. This was a bit silly in this environment as they have 250+ OUs that a computer could potentially land in…no one wants a 250+ object combo box! Finally, there was a large amount of driver packages due to a large supported model platform that is updated with new models frequently.


There’s a million ways to skin this cat as OSD is an art not a science. The client utilized a solar winds Web based ticketing system that also tracked their inventory. Funny enough, the majority of corresponding task sequence variables and or their conditional values were stored in this web system. So with the ability to use PowerShell from WinPE, we simply updated our bootimage to support Powershell and created a step to execute the following script during the task sequence:
We start by grabbing the Serial Number of the device from WMI:

#Get Serial Number from WmiObject
$SerialNumber = (Get-WmiObject -Class Win32_BIOS | Select-Object SerialNumber).SerialNumber


We then pass this value to the ticketing system to pull back information already entered by another department when asset tagging the device:


#Use Serial Number to Get Asset Number from WebHelpDesk
$A = Invoke-WebRequest "" -UseBasicParsing | Select -ExpandProperty Content | ConvertFrom-Json


We then pass the asset value back with another webrequest to pull all the device information necessary to set up our TS variables:

#Use Asset to Get Detailed Info for Device from WebHelpDesk
$Asset = $A.assetNumber
$DeviceInfo = Invoke-WebRequest """ -UseBasicParsing| Select -ExpandProperty Content | ConvertFrom-Json

From this point we are simply using simple powershell logic to parse our array of values from inventory and set TS variables:


#Get Compname (networkname) from deviceinfo
$CompName = $DeviceInfo.networkName

#Define TS Variables Based on $DeviceInfo
$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$TSEnv.Value("OSDComputerName") = $CompName

# Strip out dept from computer name

$dept = $CompName.Substring(4,3)
if ($dept.Substring(2,1) = "-") {$dept = $dept.TrimEnd("-")}


No one likes a bunch of WMI queries hogging up their time in a TS, so by pulling the model value and setting that to a TS variable…we can use the standard conditions in a task sequence step to prevent the need for an abundance of WMI work:


#Set model variable for driver package

$model = $DeviceInfo.model.modelname

$TSEnv.Value("Model") = $model

# Identify Standard or Non-Standard

$ADLocation = $DeviceInfo.assetcustomfields.restvalue[3]

# Build OU path

switch ($ADLocation) {
Standard {
$OU = ""
#$OUexists = Get-ADOrganizationalUnit -LDAPFilter "(distinguishedname=$OU)"
# if (!$OUexists){$OU = $OU.Substring(6)}
Non-Standard {
$OU = ""
#$OUexists = Get-ADOrganizationalUnit -LDAPFilter "(distinguishedname=$OU)"
#if (!$OUexists){$OU = $OU.Substring(6)}
default {$OU = ""}
$TSEnv.Value("MachineObjectOU") = $OU


This was my take on getting the client to a low effort ZTI and there are plenty of routes you can take so please go with whatever path you feel best fits your organization. I’d also like to mention Brandon Harris He helped develop the PowerShell going forward (Can’t show an Org’s internal information on the internet ! ) and presented the idea of using the ticketing system to harvest information to automate OSD. This effort interested me as much as any recent project, so I may be expanding on things like webrequests/JSON or go in depth on how to configure this on the task sequence side/SCCM. Let me know what you think!

Post Tags:
Article By Steve Bowman
Steve Bowman is a Partner at Model Technology as well as their Vice President of Sales and Marketing. Steve is a father, husband, Franciscan, and lover of technology. He's bilingual in business and technology and have over 30 years of experience in selling enterprise technology solutions in a variety of industries.

Related Posts