Skip to content

Instantly share code, notes, and snippets.

@ocelotsloth
Last active May 30, 2023 22:35
Show Gist options
  • Save ocelotsloth/18186406f10ba6d7381abae3f3825052 to your computer and use it in GitHub Desktop.
Save ocelotsloth/18186406f10ba6d7381abae3f3825052 to your computer and use it in GitHub Desktop.
MDT Dropdown OU Selector Modifications
' // ***************************************************************************
' //
' // Copyright (c) Microsoft Corporation. All rights reserved.
' //
' // Microsoft Deployment Toolkit Solution Accelerator
' //
' // File: DeployWiz_Initialization.vbs
' //
' // Version: 6.3.8450.1000-ocelotsloth-1.0
' //
' // Purpose: Main Client Deployment Wizard Initialization routines
' //
' // ***************************************************************************
' //
' // Modified by: Mark Stenglein <mark@stengle.in>
' //
' // Purpose: Added support for human-readable drop-down selection of OUs.
' //
' //
' // Notes: Domain OUs must be added to a file called `DomainOUList.xml`
' // in this same deployment scripts directory. Format this file
' // as follows (this file can be dynamically generated by the
' // included powershell file):
' //
' // ```xml
' // <DomainOUs>
' // <DomainOU value="OU=Staff,DC=someschool,DC=org">
' // Staff Comps
' // </DomainOU>
' // <DomainOU value="OU=Faculty,DC=someschool,DC=org">
' // Faculty Comps
' // </DomainOU>
' // <DomainOU value="OU=Students,DC=someschool,DC=org">
' // Student Comps
' // </DomainOU>
' // </DomainOUs>
' // ```
' //
' // Be sure to clear any existing OU entries in the other config
' // areas, as they are likely to conflict with this script. Also
' // do not skip the domain configuration options.
' //
' // If you feel creative, you can emulate a tree'ed menu by
' // prefixing the human readable names as follows:
' //
' // |-- Staff Computers
' // | |-- Business Department
' // |-- Faculty Computers
' // |-- Science Department
' // |-- Math Department
' //
' // The modifications to this script do not change any core
' // functionality, and actually restores functionality that was
' // once present in an older version of this script released by
' // Microsoft.
' //
' // If this script ceases to work in the future when I do not work
' // here anymore, send me an email with your error and I'll see if
' // I can help. Alternatively, just create a new deployment share
' // for a reference of the old script.
' //
' // BACK THIS FILE UP BEFORE UPGRADING THE DEPLOYMENT SHARE
' //
' // Every time you install a new ADK or update MDT and then
' // need to upgrade the deployment share this file is
' // overwritten. They do actually make changes so please do not
' // simply overwrite the new file with the old one. You will
' // want to analyze the new file by diffing it with this one to
' // see what changes need to be applied to the new version.
' //
' // If you have trouble with this and want help feel free to
' // send me an email.
' //
' // ***************************************************************************
Option Explicit
Function InitializeComputerName
If oProperties("OSDComputerName") = "" then
OSDComputerName.Value = oUtility.ComputerName
End if
If UCase(oEnvironment.Item("SkipComputerName")) = "YES" then
OSDComputerName.disabled = true
End if
End Function
Function ValidateComputerName
' Check Warnings
ParseAllWarningLabels
If Len(OSDComputerName.value) > 15 then
InvalidChar.style.display = "none"
TooLong.style.display = "inline"
ValidateComputerName = false
ButtonNext.disabled = true
ElseIf IsValidComputerName ( OSDComputerName.Value ) then
ValidateComputerName = TRUE
InvalidChar.style.display = "none"
TooLong.style.display = "none"
Else
InvalidChar.style.display = "inline"
TooLong.style.display = "none"
ValidateComputerName = false
ButtonNext.disabled = true
End if
End function
''''''''''''''''''''''''''''
Function AddItemToMachineObjectOUOpt(item,value)
Dim oOption
set oOption = document.createElement("OPTION")
oOption.Value = value
oOption.Text = item
oOption.Title = item
MachineObjectOUOptional.Add oOption
MachineObjectOUOptionalBtn.style.display = "inline"
End function
Function InitializeDomainMembership
Dim oLDAP, oOptOU, oItem
Dim sFoundFile
Dim iRetVal
' Prepopulate the join account details if they are presently blank
If Property("DomainAdmin") = "" and Property("DomainAdminDomain") = "" and Property("DomainAdminPassword") = "" then
If Property("UserID") <> "" and Property("UserDomain") <> "" and Property("UserPassword") <> "" Then
DomainAdmin.value = Property("UserID")
DomainAdminDomain.value = Property("UserDomain")
DomainAdminPassword.value = Property("UserPassword")
End if
End if
If JoinWorkgroup.value <> "" then
JDRadio2.checked = TRUE
ElseIf JoinDomain.Value = "" then
On Error Resume Next
JoinDomain.value = CreateObject("ADSystemInfo").DomainDNSName
On Error Goto 0
If JoinDomain.Value = "" then
JoinWorkgroup.value = "WORKGROUP"
JDRadio2.checked = TRUE
Else
JDRadio1.checked = TRUE
' Domain.value = JoinDomain.Value
On error resume next
' Will extract out the existing OU (if any) for the current machine.
set oLDAP = GetObject("LDAP://" & CreateObject("ADSystemInfo").ComputerName)
MachineObjectOU.Value = oLDAP.Get("Organizational-Unit-Name")
On error goto 0
End if
End if
''''''''''''''''''''''''''''''''
'
' Populate OU method #1 - Query ADSI
'
MachineObjectOUOptionalBtn.style.display = "none"
''''''''''''''''''''''''''''''''
'
' Populate OU method #2 - Read MachineObjectOUOptional[1...n] property
'
If MachineObjectOUOptionalBtn.style.display <> "inline" then
oOptOU = Property("DomainOUs")
If isarray(oOptOU) then
For each oItem in oOptOU
AddItemToMachineObjectOUOpt oItem
Next
MachineObjectOUOptionalBtn.style.display = "inline"
ElseIf oOptOU <> "" then
AddItemToMachineObjectOUOpt oOptOU
End if
End if
''''''''''''''''''''''''''''''''
'
' Populate OU method #3 - Read ...\control\DomainOUList.xml
'
' Example:
' <?xml version="1.0" encoding="utf-8"?>
' <DomainOUs>
' <DomainOU>OU=Test1</DomainOU>
' <DomainOU>OU=Test2</DomainOU>
' </DomainOUs>
'
If MachineObjectOUOptionalBtn.style.display <> "inline" then
iRetVal = oUtility.FindFile( "DomainOUList.xml" , sFoundFile)
if iRetVal = SUCCESS then
For each oItem in oUtility.CreateXMLDOMObjectEx( sFoundFile ).selectNodes("//DomainOUs/DomainOU")
AddItemToMachineObjectOUOpt oItem.text, oItem.Attributes.getNamedItem("value").value
Next
End if
End if
If MachineObjectOUOptionalBtn.style.display = "inline" then
document.body.onMouseDown = getRef("DomainMouseDown")
document.body.onKeyDown = getRef("MachineObjectOUOptionalKeyPress")
End if
ValidateDomainMembership
End Function
Function MachineObjectOUOptionalKeyPress
dim OUOpt
on error resume next
set OUOpt = MachineObjectOUOptional
on error goto 0
If isempty(OUOpt) then
KeyHandler
ElseIf window.event.srcElement is MachineObjectOUOptional then
If window.event.keycode = 13 then
' Enter
MachineObjectOU.value = MachineObjectOUOptional.value
PopupBox.style.display = "none"
ElseIf window.event.keycode = 27 then
' escape
PopupBox.style.display = "none"
End if
Else
KeyHandler
End if
End function
Function DomainMouseDown
If not window.event.srcElement is MachineObjectOUOptional and not window.event.srcElement is MachineObjectOUOptionalBtn then
PopupBox.style.display = "none"
End if
End function
Function HideUnHideComboBox
If UCase(PopupBox.style.display) <> "NONE" then
HideUnhide PopupBox, FALSE
document.body.onMouseDown = ""
document.body.onKeyDown = getRef("KeyHandler")
Else
HideUnhide PopupBox, TRUE
MachineObjectOUOptional.focus
document.body.onMouseDown = getRef("DomainMouseDown")
document.body.onKeyDown = getRef("MachineObjectOUOptionalKeyPress")
End if
End function
Function ValidateDomainMembership_Final
If JDRadio1.checked then
RMPropIfFound("JoinWorkgroup")
JoinWOrkgroup.Value = ""
Else
RMPropIfFound("JoinDomain")
JoinDomain.Value = ""
End if
ValidateDomainMembership_Final = true
End function
'''''''''''''''''''''''''''''''''''''
' Validate Domain Membership
'
Function ValidateDomainMembership
Dim IsDomain
Dim r
MissingCredentials.style.display = "none"
InvalidCredentials.style.display = "none"
InvalidOU.style.display = "none"
isDomain = JDRadio1.checked
If not isDomain then
RMPropIfFound("BdeInstall")
RMPropIfFound("BdeInstallSuppress")
RMPropIfFound("DoCapture")
RMPropIfFound("BackupFile")
If Property("DeploymentType") <> "REFRESH" and Property("DeploymentType") <> "REPLACE" then
RMPropIfFound("ComputerBackupLocation")
End if
End if
If UCase(oEnvironment.Item("SkipDomainMembership")) = "YES" then
' Hide all the domain/workgroup settings
DomainSection.style.display = "none"
JDRadio1.disabled = true
JDRadio2.disabled = true
JoinDomain.disabled = true
DomainAdmin.disabled = true
DomainAdminDomain.disabled = true
DomainAdminPassword.disabled = true
MachineObjectOU.disabled = true
MachineObjectOUOptionalBtn.disabled = true
MachineObjectOUOptional.disabled = true
JoinWorkgroup.disabled = true
ValidateDomainMembership = true
' Don't do any more validation because this has been disabled
Exit Function
Else
JoinDomain.disabled = not isDomain
DomainAdmin.disabled = not isDomain
DomainAdminDomain.disabled = not isDomain
DomainAdminPassword.disabled = not isDomain
MachineObjectOU.disabled = not isDomain
MachineObjectOUOptionalBtn.disabled = not isDomain
MachineObjectOUOptional.disabled = not isDomain
JoinWorkgroup.disabled = isDomain
End if
' Check Warnings
ValidateDomainMembership = ParseAllWarningLabels
' Check domain settings (without validation of credentials)
If IsDomain then
' Make sure the join account details are specified
If Trim(DomainAdmin.value) = "" or Trim(DomainAdminPassword.value) = "" or (Instr(DomainAdmin.Value, "@") = 0 and Trim(DomainAdminDomain.Value) = "") then
MissingCredentials.style.display = "inline"
ValidateDomainMembership = false
End if
' Check OU to make sure it is a valid format
If MachineObjectOU.Value <> "" then
' Make sure it starts with "OU=" or "OU " (equal could be preceeded by spaces)
If Left(UCase(Trim(MachineObjectOU.Value)), 3) <> "OU=" and Left(UCase(Trim(MachineObjectOU.Value)), 3) <> "OU " then
InvalidOU.style.display = "inline"
ValidateDomainMembership = false
End if
End if
End if
' Check credentials
If IsDomain and ValidateDomainMembership and (not window.event is Nothing) then
' Only check credentials when the next button is clicked
If window.event.srcElement is ButtonNext or window.event.KeyCode = 13 then
oLogging.CreateEntry "Validate Domain Credentials [" & DomainAdminDomain.value & "\" & DomainAdmin.value & "]", LogTypeInfo
If oEnvironment.Item("OSVersion") <> "WinPE" then
' Check using ADSI (not possible in Windows PE)
r = CheckCredentialsAD(DomainAdminDomain.value, DomainAdmin.value, DomainAdminDomain.value, DomainAdminPassword.value)
If r <> TRUE then
InvalidCredentials.innerText = "* Invalid credentials: " & r
InvalidCredentials.style.display = "inline"
ValidateDomainMembership = false
End if
ElseIf oEnvironment.Item("ValidateDomainCredentialsUNC") <> "" then
' Check using ADSI (not possible in Windows PE)
oLogging.CreateEntry "Validate Domain Credentials against UNC: " & oEnvironment.Item("ValidateDomainCredentialsUNC") , LogTypeInfo
r = CheckCredentials( oEnvironment.Item("ValidateDomainCredentialsUNC") , DomainAdmin.value, DomainAdminDomain.value, DomainAdminPassword.value)
oLogging.CreateEntry "Validate Domain Credentials against UNC: result = " & r , LogTypeInfo
If r <> TRUE then
InvalidCredentials.innerText = "* Invalid credentials: " & r
InvalidCredentials.style.display = "inline"
ValidateDomainMembership = false
End if
End if
End if
End if
' We need to clean up the keyboard hook
If ValidateDomainMembership then
document.body.onMouseDown = ""
End if
End Function
# Filename: generateDomainOUList.ps1
#
# Adapted from https://social.technet.microsoft.com/Forums/en-US/b9dc1d73-c94b-404d-afeb-b8576fc0ab70/populate-ou-method-in-mdt-2012?forum=mdt
# by Mark Stenglein <mark@stengle.in>
#
# Before running this script be sure to modify the variables below to suit your
# environment. Additionally, under the "ForEach ($Item In $OUs)" loop around
# line 49 you may want to add your own OU Name substitutions. If you have long
# OU Names the dropdown menu in LiteTouch can be very long. Substitutions allow
# that menu to be far more useful.
#
# This file should be placed in and run from the Scripts directory in your MDT
# Share.
#Define Variables
# Put your Windows Domain Name
$Server = 'int.contoso.com'
# Put the root OU for your Computers
$SearchBase = "OU=CONTOSO COMPS,DC=int,DC=CONTOSO,DC=com"
# Leave as default if you want this to work properly with the MDT integration
$ExportPath = ".\DomainOUList.xml"
# Leave as default or change. This is where your backup goes.
$BackupPath = (Split-Path -Path $ExportPath -Parent) + "\DomainOUList_PreviousVersion.xml"
#Define ASCII Characters
$NewLine = "`r`n"
$Tab = "`t"
#Create Secure Credential Object
$Credentials = (Get-Credential -Message "Please enter the appropriate credentials to allow this script to query active directory (read only access is all that is required)." -UserName "$ExecutingUser_Domain\$ExecutingUser_UserName")
#Define Functions
#Determine The Parent Of An Active Directory Object
Function Get-ADObjectParent ($DistinguishedName)
{
$Parts = $DistinguishedName -Split "(?<![\\]),"
Return $Parts[1..$($Parts.Count - 1)] -Join ","
}
#Make A Backup Copy Of "DomainOUList.xml"
If (Test-Path -Path "$ExportPath") {Copy-Item -Path "$ExportPath" -Destination "$BackupPath" -Force | Out-Null}
#Create "DomainOUList.xml"
$DomainOUList_Create = (New-Item -ItemType File -Path "$ExportPath" -Force).FullName
#Retrieve Organizational Units From Active Directory And Sort The Results Based On CanonicalName
$OUs = Get-ADOrganizationalUnit -Filter * -Credential $Credentials -Properties * -SearchBase $SearchBase -SearchScope Subtree -Server $Server | Select *, @{Name="FriendlyName";Expression={($_.CanonicalName).Split("/")}}, @{Name="Parent";Expression={Get-ADObjectParent -DistinguishedName $_.DistinguishedName}} | Sort-Object CanonicalName
#Export To "DomainOUList.xml" for use with Microsoft Deployment Toolkit
If ($OUs.Count -gt 0)
{
$Output = ("<?xml version=`"1.0`" encoding=`"utf-8`"?>" + $NewLine + $NewLine)
$Output += ("<DomainOUs>" + $NewLine + $NewLine)
ForEach ($Item In $OUs)
{
#If You Want To Remove Portions Of The "$Item.FriendlyName" Property, Experiment With The "+ 4" Value. Example - Change It To + 3, etc... This May Make It Easier To See The Names When Selecting Them During Deployment.
$Item.FriendlyName = (($Item.FriendlyName)[($Item.FriendlyName.GetLowerBound(0) + 3)..($Item.FriendlyName.GetUpperBound(0))] -Join " \ ")
$Item.FriendlyName = $Item.FriendlyName -replace ' Comps',''
$Item.FriendlyName = $Item.FriendlyName -replace 'Student Labs','Labs'
$Item.FriendlyName = $Item.FriendlyName -replace 'Student Wireless','Wireless'
$Item.FriendlyName = $Item.FriendlyName -replace 'Science Laptops','Sci Lap'
$Item.FriendlyName = $Item.FriendlyName -replace 'Lab ',''
$Item.FriendlyName = $Item.FriendlyName -replace 'ENGINEERING LAB','ENGLAB'
$Item.FriendlyName = $Item.FriendlyName -replace 'Art Lab Computers','Art'
#Write Each Result To The Console Host
Write-Host "Now Exporting `"$($Item.FriendlyName)`" to `"$($ExportPath)`"" -BackgroundColor Black -ForegroundColor Yellow
#Comment/Uncomment The Follwing Line If You Want To Make Use Of FriendlyNames, Only One Value May Be Used At A Time!
$Output += ($Tab + "<DomainOU value=`"$($Item.DistinguishedName)`">" + $NewLine + $Tab + $Tab + $($Item.FriendlyName) + $NewLine + $Tab + "</DomainOU>" + $NewLine + $NewLine)
#Comment/Uncomment The Follwing Line If You Want To Make Use Of DistinguishedNames, Only One Value May Be Used At A Time!
#$Output += ($Tab + "<DomainOU>" + $NewLine + $Tab + $Tab + $($Item.DistinguishedName) + $NewLine + $Tab + "</DomainOU>" + $NewLine + $NewLine)
}
$Output += ("</DomainOUs>")
#Export Data To "DomainOUList.xml"
$Output | Out-File "$ExportPath" -Append -Encoding utf8
}
#Write The Results To The Console Host (Uncomment If You Would Like)
#@"
# $Output
#"@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment