How can I present a dynamic OU Selection prompt for MDT/SCCM?

By | December 18, 2014
Share

First thing you will need to installf Maik Koster’s “Deployment Webservice“. This will give you the ability to do cool stuff like query AD for a list of OUs, or move computers around to different OUs, and add/remove computers from SCCM collections. Any many other actions similar to that.

Once you have it installed and working, use the ad.asmx page to verify the GetOUs service functions.

Create a new package containing INI files for each action you wish to perform from your task sequence.

Here are my GetOUs examples:

My GetOUs.ini file:

[Settings]

Priority=Init,GetOUs

Properties=Path(*),ParentPath,Level

 [Init]

ParentPath=OU=Laptops,OU=ViaMonstra,DC=corp,DC=viamonstra,DC=com

Level=1

 [GetOUs]

WebService=http://cm01.corp.viamonstra.com/WebService/ad.asmx/GetOUs

Parameters=ParentPath,Level

 

  • I am creating the Path() list variable to store all of the returned Path elements.
  • I then set the two required input arguments; ParentPath and Level.

To test that it works, I added a pause step to my MDT Deployment Task Sequence.

My Pause Script:

MsgBox “OK”

Then I copied a Gather step and changed the package to my newly created package containing MyGetOUs.ini.

In the “Rules files” field, I enter the full name of my INI file.

  • Note: Gather steps must occur after a “Use Toolkit Package” step, because this step copies the MDT scripts local which are utilized during the Web Service calls.
  • Place the GetOUs web service call before the pause, so you can review the ZTIGather.log output to ensure the PATH variable is populated.

Next we need to prompt the user with the captured OUs. For this, I used a Powershell script. So I first needed to add Powershell to my WinPE Boot Image.

Last, I added a package with my Powershell script. I do not add a program, because I’m going to call the script via a Run a Command Line step.

Here is the script contents:

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

Function Set-OSDComputerName

{

$ErrorProvider.Clear()

$Error.Clear()

if ($objComputerName.Text.Length -eq 0)

{

$ErrorProvider.SetError($objComputerName, "Please enter a computer name.")

}

 

#Validation Rule for computer names.

elseif ($objComputerName.Text -match "^[-_]|[^a-zA-Z0-9-_]")

{

$ErrorProvider.SetError($objComputerName, "Computer name invalid, please correct the computer name.")

}

 

else

{

$OSDComputerName = $objComputerName.Text.ToUpper()

$TSEnv.Value("OSDComputerName") = $OSDComputerName

}

}

 

Function Set-OUPath

{

if (($objListBox.Items.Count -ne 0) -and `

    ($objListBox.SelectedItem.Length -eq 0))

{

$ErrorProvider.SetError($objListBox, "Please select an OU.")

}

else

{

$TSEnv.Value("OUPath") = $objListBox.SelectedItem

}

}

 

$ErrorProvider = New-Object System.Windows.Forms.ErrorProvider

$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

 

$objForm = New-Object System.Windows.Forms.Form

$objForm.Text = "Computer Configuration"

$objForm.Size = New-Object System.Drawing.Size(300,300)

$objForm.StartPosition = "CenterScreen"

 

$objForm.KeyPreview = $True

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")

{$x=$objListBox.SelectedItem;$objForm.Close()}})

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")

{$objForm.Close()}})

 

$OKButton = New-Object System.Windows.Forms.Button

$OKButton.Location = New-Object System.Drawing.Size(10,230)

$OKButton.Size = New-Object System.Drawing.Size(75,23)

$OKButton.Text = "OK"

$OKButton.Add_Click({

Set-OSDComputerName

Set-OUPath

#If ($Error.Count -eq 0){$objForm.Close()}

if (($ErrorProvider.GetError($objListBox) -eq "") -and `

($ErrorProvider.GetError($objComputerName) -eq ""))

{

    Write-Host "Populated ComputerName: $objComputerName.Text"

    Write-Host "Populated OUPath: $objListBox.SelectedItem.Text"

    $objForm.Close()

}

})

$objForm.Controls.Add($OKButton)

 

$objLabel = New-Object System.Windows.Forms.Label

$objLabel.Location = New-Object System.Drawing.Size(10,20)

$objLabel.Size = New-Object System.Drawing.Size(280,20)

$objLabel.Text = "Please Select a Target OU:"

$objForm.Controls.Add($objLabel)

 

$objListBox = New-Object System.Windows.Forms.ListBox

$objListBox.Location = New-Object System.Drawing.Size(10,40)

$objListBox.Size = New-Object System.Drawing.Size(260,20)

$objListBox.Height = 135

$objListBox.ScrollAlwaysVisible = $true

 

$TSEnv.GetVariables() | ?{$_ -like "PATH*"} | %{

$objListBox.Items.Add($TSEnv.Value("$_"))

}

 

If ($objListBox.Items.Count -eq 0) {

    Write-Error "No OUPaths located"

}

else {$objListBox.SetSelected(0, $true)}

 

$objComputerNameLabel = New-Object System.Windows.Forms.Label

$objComputerNameLabel.Location = New-Object System.Drawing.Size(10,180)

$objComputerNameLabel.Size = New-Object System.Drawing.Size(280,20)

$objComputerNameLabel.Text = "Please Specify a ComputerName:"

$objForm.Controls.Add($objComputerNameLabel)

 

$objComputerName = New-Object System.Windows.Forms.TextBox

$objComputerName.Location = New-Object System.Drawing.Size(10,200)

$objComputerName.Size = New-Object System.Drawing.Size(260,20)

$objComputerName.MaxLength = 15

$objComputerName.Text = $TSEnv.Value("OSDComputerName")

$objForm.Controls.Add($objComputerName)

 

$objForm.Controls.Add($objListBox)

 

$objForm.Topmost = $True

 

$objForm.Add_Shown({$objForm.Activate()})

[void] $objForm.ShowDialog()

This script populates a TS variable named OUPath, which I use at the end of the Task Sequence calling a web service to move the computer to the selected OU. I perform the move at the end, to avoid having GPO settings interfere with my Task Sequence.

 

/Brian Gonzalez

How Can I Display An MDT Wizard Screen Only When A Certain Task Sequence Is Selected?

By | November 26, 2014
Share

If you need to display a wizard screen ONLY if a certain Task Sequence is selected, this is a method to accomplish this.

1. Add a custom step in the Task Sequence.

CustomTaskSequenceStep

2. Using the Wizard Studio, build your custom page and use the following condition to force it to display only when your custom step is detected.

FindTaskSequenceStep(“//step[@name=’Test’]”, “” )

Note: The FindTaskSequenceStep function is case sensitive.

FindTaskSequenceStep

 

/BG

How Can I Set The AssetTag in A Panasonic Toughbook or Toughpad’s BIOS using MDT 2013 or SCCM 2012?

By | November 22, 2014
Share

If you MUST input the ComputerName manually on a machine once, then store it in the BIOS, so the next time the unit is imaged, it can be pulled from the BIOS’s AssetTag value.

The first step to this setup is telling MDT2013 to attempt to use the AssetTag for the ComputerName value.  This is easily accomplished using the “%AssetTag%” variable as the OSDComputerName CustomSettings.ini rule.

[Default]
OSDComputerName=%AssetTag%

Next, we need to use the Panasonic’s AssetTag.exe utility to import the value into the BIOS.  This utility relies on the Panasonic Drivers being installed as well as the unit being booted into Windows.  So it is best handled in the State Restore phase, after the appropriate Panasonic One-Click Bundle is executed (https://panaconsulting.egnyte.com/fl/tdu1nkidMT).  Here is a the “application” source files, which I use to set the AssetTag value: OneDrive Link

The script uses the AssetTag.exe utility (Download Link).  This is included in the application source files.

UpdateAssetTagProperties

The script logs to the BDD.log as well as its own log file Z-AssetTag.log.

 

Here is the script source:

<job id="Z-SetAssetTag.wsf"> 
<script language="VBScript" src="..\..\Scripts\ZTIUtility.vbs"/> 
<script language="VBScript"> 
 
' //*************************************************************************** 
' // ***** Script Header *****
' // 
' // Solution: Solution Accelerator for Microsoft Deployment 
' // File: Z-SetAssetTag.wsf
' // 
' // Purpose: Sets AssetTag to the ComputerName for re-imaging purposes.
' // 
' // Usage: cscript Z-SetAssetTag.wsf [/debug:true] 
' // 
' // Panasonic Build Version: 1.0
' // Customer History: 
' // Mar 10, 2016 - First Build.
' // 
' // ***** End Header *****
' //*************************************************************************** 
 
'//---------------------------------------------------------------------------- 
'// 
'// Global constant and variable declarations 
'// 
'//---------------------------------------------------------------------------- 
'Option Explicit
Dim iRetVal 
'//---------------------------------------------------------------------------- 
'// End declarations 
'//---------------------------------------------------------------------------- 
 
'//---------------------------------------------------------------------------- 
'// Main routine 
'//---------------------------------------------------------------------------- 
'On Error Resume Next 
iRetVal = ZTIProcess 
ProcessResults iRetVal 
On Error Goto 0 
 
'//--------------------------------------------------------------------------- 
'// 
'// Function: ZTIProcess() 
'// 
'// Input: None 
'// 
'// Return: Success - 0 
'// Failure - non-zero 
'// 
'// Purpose: Perform main ZTI processing 
'// 
'//--------------------------------------------------------------------------- 
Function ZTIProcess() 
    iRetVal = Success 
    ZTIProcess = iRetval 

    '/ Create text file containing the ComputerName
    sCNameFilePath = oFileHandling.GetTempFileEx("txt")
    oLogging.CreateEntry "Z-SetAssetTag.wsf: Computername file set to """ & sCNameFilePath & """.", LogTypeInfo
    Set oCNameFile = oFSO.CreateTextFile(sCNameFilePath,True)
    oCNameFile.Write oNetwork.ComputerName
    oLogging.CreateEntry "Z-SetAssetTag.wsf: Wrote " & oNetwork.ComputerName & "to file.  Return: " & Err.number, LogTypeInfo
    oCNameFile.Close

	'// Execute the Assettag.exe with the new text file
	sAssetTagFilePath = oUtility.ScriptDir & "\assettag.exe"
	If NOT oFSO.FileExists(sAssetTagFilePath) then
		oLogging.CreateEntry "Z-SetAssetTag.wsf: " & sAssetTagFilePath & " was not found, unable to execute.", LogTypeError
		ZTIProcess = Failure
		Exit Function
	End if

	sCmd = sAssetTagFilePath & " /Y /F:" & sCNameFilePath
	oLogging.CreateEntry "Z-SetAssetTag.wsf: Running: " & sCmd, LogTypeInfo
	iRetVal = oUtility.RunWithHeartbeat(sCmd)
	
	If (iRetVal = 0) or (iRetVal = 3010) then
		ZTIProcess = Success 
	Else 
		ZTIProcess = Failure
	End If
	
	oLogging.CreateEntry "Z-SetAssetTag.wsf: Execute AssetTag.exe: Return code from command = " & iRetVal, LogTypeInfo
	oLogging.CreateEntry "Z-SetAssetTag.wsf: Execute AssetTag.exe: Complete", LogTypeInfo

End Function
</script> 
</job>

 

/BG

MDT 2013 Bug Alert: MDT2013 Natively Does Not Support BitLocker for Windows 8x Professional

By | November 20, 2014
Share

MDT 2013 only checks for the following OS SKU types when validating BitLocker is supported.

 

ZTIUtility code, which is used when validating BitLocker support before displaying the BitLocker Wizard page:

	Function IsHighEndSKUEx( sSKU )
	
		' Windows Ultimate/Enterprise and Server SKU's allow for some
		' higher-end features, like Bitlocker and Multiple Language Packs.
		
		select case (ucase(trim(sSKU)))
			case "ULTIMATE", "ULTIMATEE", "ULTIMATEN"
				IsHighEndSKUEx = TRUE
			case "ENTERPRISE", "ENTERPRISEE", "ENTERPRISEN"
				IsHighEndSKUEx = TRUE
			case "HYPERV"
				IsHighEndSKUEx = TRUE
			case "PRERELEASE"
				IsHighEndSKUEx = TRUE
			case else
				If Instr(1, ucase(trim(sSKU)), "SERVER", vbTextCompare) > 0 then
					IsHighEndSKUEx = TRUE
				Else
					IsHighEndSKUEx = FALSE
				End if
		End Select
		
	End function

It also performs OSSKU validation in the ZTIBDE.wsf script.

'//----------------------------------------------------------------------------
		'//  Check to see if BDE is supported in this OS
		'//----------------------------------------------------------------------------	
		
		'// Check to see if we are running Vista or later and exit if we are not
		If Left(oEnvironment.Item("OSCurrentVersion"),1) < 6 Then
			oLogging.CreateEntry "Bitlocker is not supported on this version of Windows", LogTypeInfo
			Main = iRetVal
			Exit Function
		'// Check to see if the SKU supportes Bitlocker
		ElseIf not oUtility.IsHighEndSKU then
			oLogging.CreateEntry "Bitlocker is only supported on Windows Enterprise or Windows Ultimate or Windows Server", LogTypeInfo
			Main = iRetVal
			Exit Function
		Else
			oLogging.CreateEntry "We are running a OS that supports BitLocker", LogTypeInfo
		End if

The easiest way I found to workaround this bug is the following.

First use the MDT Wizard Studio, and remove the condition check for the BitLocker page that checks the OSFlag.

CorrectedBitLockerPageCondition

Lastly,  I comment out the validation statement in the ZTIBde.wsf script:

'//----------------------------------------------------------------------------
		'//  Check to see if BDE is supported in this OS
		'//----------------------------------------------------------------------------	
		
		'// Check to see if we are running Vista or later and exit if we are not
		If Left(oEnvironment.Item("OSCurrentVersion"),1) < 6 Then
			oLogging.CreateEntry "Bitlocker is not supported on this version of Windows", LogTypeInfo
			Main = iRetVal
			Exit Function
		'// Check to see if the SKU supportes Bitlocker
		'ElseIf not oUtility.IsHighEndSKU then
		'	oLogging.CreateEntry "Bitlocker is only supported on Windows Enterprise or Windows Ultimate or Windows Server", LogTypeInfo
		'	Main = iRetVal
		'	Exit Function
		Else
			oLogging.CreateEntry "We are running a OS that supports BitLocker", LogTypeInfo
		End if

Now, I should see my Bitlocker dialog, assuming that I do NOT have any of the following CS rules applied:

DoCapture=YES
SkipBitLocker=YES

/BG

How can you get information from a WWAN embedded card from the command-line?

By | September 11, 2014
Share

Very useful broadband card information accessible via a quick command line:

netsh mbn show interfaces

View post on imgur.com

Unfortunately, configuring the broadband card doesn’t appear to work.  I’m working with Microsoft and Sierra on this, but here is the error.

netsh mbn add profile interface=”Mobile Broadband” name=”C:\profile.xml”

returns either:

Add Profile Failure: Invalid Profile XML.

or

The Profile cannot be loaded.

/Brian