MDT – Put the domain join where it belongs..

Hi Guys and Gals,

Long time no see. Took me some time to move into our new house which had to be decorated with wallpaper, flooring, additional electric and internet wiring etc. So March 2015 will leave a gap in my blog archive, but I’m hoping to compensate this with writing some new articles.

One of them is this one: Put the domain join where it belongs. If you are like me, I like to work with one MDT deploymentshare to rule them all. When looking on social.technet in the MDT forum’s I see many people struggling to combine build and deployment shares together, or shares that have separate settings regarding computer deployment or domain membership.

Now MDT offers four options to create a deploymentshare so flexible you’ll only need one share to truly rule them all:

  1. The customsettings.ini
  2. Multiple customsettings.ini
  3. The MDT Database
  4. Task Sequence Variables

Allow me to explain each option and the pro’s and con’s:

Customsettings.ini: hey If you can manage it per model, macaddress, tasksequenceid etc. thats fine! But usually you are going to end up with a conflict that either strikes your build deployment or your deploy deployment. Most issues I see here are domainjoin and capture related.

figure 1.1: CustomSettings.ini

customset000

Multiple customsettings.ini, you can specify which ini file to process right into your task sequence “gather” step; this makes your deploymentshare more flexible and forces a specific task sequence to use a different ini file for processing then let’s say the default task sequence. Editing the Gather step is an option, but since you’ll have to edit it multiple times in one task sequence, it’s easy overlooked and prone to error when making typo’s

figure 1.2: Multiple customsetttings.ini

customset002

If you are planning on changing the gather step’s, then please take into consideration there are four of them in every deployment task sequence:

The first is during Initialization, the second during Preïnstall the third during State Restore and the last one can be found during Imaging

figure 1.3: Configuring different CustomSetting.ini

customset001

Then there is the MDT Database, store settings that would otherwise end-up in your customsettings.ini individually based per machine, make and/or model, roles or location, a very good alternative to use but a little bit overpowered when just wanting to make the difference between machines joining a domain or getting captured.

figure 1.4: Using the MDT database integration

mdtdb001

figure 1.5: Properties of a MDT database object (A customsetting.ini of your own)mdtdb002

Task Sequence variables, this to me is the most powerful option of all. Let’s say I want to specify a property which may not occur anywhere else, simply put a task sequence variable at the front of your task sequence.

figure 1.6: Using task sequence variables in your task sequence

tsvars001

Just as you would post information about capturing your reference build in the build task sequence, you could do exactly the same for the following values regarding domain joins:

  • JoinDomain=contoso
  • DomainAdmin=mdt-domainjoin
  • DomainAdminDomain=contoso
  • DomainAdminPassword=P@$$w0rd
  • MachineObjectOU=OU=Computers,OU=Laptops,DC=contoso,DC=local

This prevents machines that are intended to be captured, end up domain joined and machines that are deployed and are domain joined to be captured (which will result in error, since sysprep will not allow a domain joined machine to be generalized for capture).

Hope this helps in gaining insight in how to achieve a more flexible MDT deployment.

Cheers! Rens

62 thoughts on “MDT – Put the domain join where it belongs..

  1. Marc

    Hi Rens,

    I’m just getting started with MDT/WDS and so far things are going okay but from what I’ve read on countless pages, there’s no real 1 way to do this… which can be frustrating for someone new! I’ve run into a bit of a scenario that I was hoping you might be of help with (and this page I thought would answer but I’m still confused).

    From the method I used, my domain join is in the CustomSettings.ini and it works – good – however I notice that after each reboot of the deployment process after the domain join has occurred, the process stops on our logon banner and I need to click Okay in order to proceed to the next stage. I thought about moving the domain join to the last possible step as a task sequence but then the updates would fail because it wouldn’t know how to reach the wsus server (hostname).

    Is there a way to suppress the OKAY click during the deployment? Or maybe there’s a better way to do this.

    I’m going to read over your post again as it was a bit confusing at first…

    Thanks!

    Reply
    1. Rens Hollanders

      Hi Marc,

      If I understand you correctly you have configured a GPO that is linked to the organizational unit where the machine resides under, that set’s a logon message between logging in and entering the user credentials.

      Deploying machines which join the domain into an OU that has policies residing under that OU can cause much pain during deployment. My advise would be to create a separate staging OU and afterwards move the machine to the correct OU automatically with a script or manually. This way machine’s will not be bothered with policies during the deployment.

      Cheers! Rens

      Reply
      1. Marc

        Wow I never would have thought to do that! Good idea 🙂 Thanks Rens for the prompt reply.

        Reply
      2. Marc

        –Update–
        This is going to take some work… the interactive logon message was set in the default domain policy which is applied to Authenticated Users on the whole domain :-S

        I wasn’t responsible for configuring AD/GP waaaay back in the day and I’ve been slowly cleaning it up but haven’t touched the default policy yet… (I remember reading somewhere that you should NEVER use this policy for anything…guess my predecessors didn’t read that same article.. hah).

        They also used the default Computers container…grrr…

        I’m thinking I should just remove the interactive logon portion and place that in it’s own GPO instead of completely overhauling the default policy right now.

        Reply
        1. Rens Hollanders

          Hi Marc,
          Yeah that’s a pain in the butt. Perhaps you can create a designated OU, and enable “Block Inheritance”, although I’m currently not aware if also the default domain policy is blocked by this action. But hey worth a shot, enable block inheritance and do a resultant set of policy (RSOP)

          Cheers! Rens

          Reply
          1. Marc

            Rens if you’re ever in Ottawa I owe you a beer!

            Still learning GPO and I’ve already had my few “oops” moments (like enabling windows firewall across the domain including all servers…)

            Block Inheritance was exactly the feature I was looking for but I didn’t know what it was called or if the option was even available.

            I had a few Enforced policies but I’ve remedied those.

            This should make the deployments much smoother!

          2. Rens Hollanders

            Marc,

            I hold you to that one 🙂 Glad I’d could help. I wish you many luck on your MDT endeavors, and If you ever needed the help again, please let me know.

            Cheers! Rens

  2. Ant

    Hi,
    I already have a working MDT which I have connecting to a domain specified in the CustomSettings.ini. What I now want to do is during the build have the option of joining it to one of 4 domain. Ideally I would like to have a drop down field and then automatically use the correct account name and password for that chosen domain from the customsettings.ini..
    I know I could this by having multiple customsettings.ini files (one for each domain) but as the whole of the ini file, apart from the domain, will be the same, I wondered if there was a cleaner way to do this from the one ini file..?

    Reply
  3. Gregg

    Rens,
    Having much trouble automating the steps for tablets to consistently join the domain wirelessly after deploying the image via USB stick. Seems that task sequence and unattend both run before the wireless connection is complete. I can insert the wireless profiles in a task sequence step without a problem and I even inserted a wait step in the task sequence but the connection still only seems to be consistently available after the desktop finishes loading on the first login. Even the SetupComplete.cmd finishes too early. Once the desktop is loaded I can manually run a script with elevated privileges but that’s not going to work when I’m not at the machine and takes too much time anyway when I have 500 machines to do.

    Any ideas on how I can delay a running a final task sequence step until after the desktop is completely loaded?

    Thanks for any help you might be able to give!

    Reply
    1. Rens Hollanders

      Gregg,

      I’ve never done partially completion of the task sequence with Wifi, I wouldn’t recommend it either, since Wifi isn’t that reliable to me as cable.
      If you want to wait for tasks running in a CMD to complete, you could use START /WAIT, see this link for more information: http://ss64.com/nt/start.html

      Hope that can be helpful to you.

      Cheers! Rens

      Reply
      1. Gregg

        Just wanted to let you know how this has worked out. After reading many forum articles we found that there was no Reverse Lookup Zone established in DNS for this network. This created enough of a delay in retrieving domain info that the process failed half the time. Once this was put in place with the appropriate PTR for the local DC, the domain join began working just fine via wireless. There were (and still are) some tweaks to make things more compact and efficient but it works fine, I’ve had no failures since DNS was fixed.

        We are currently using a method that copies the wireless profile xml files from the %scriptroot% folder during post-install phase, then in SetupComplete.cmd a “netsh wlan add profile” command installs them and waits 30 seconds for a connection to be established. SetupComplete then runs a vbscript which does the domain join as well as placing the machine in the proper OU.

        I have seen that we could probably eliminate the vbscript that does the domain join and just allow the TS to do it but it didn’t work initially so we went with the vbscript. On further experimentation it seems that the TS doesn’t like when the unattend file has the domain join information in it. The deployment hangs for 15-20 minutes waiting for the unattend to do the domain join which fails because the wireless connection isn’t made at that point, but when it finally times out the TS will then do the domain join itself because the SetupComplete has run by then and created the wireless connection.

        As always, thanks for your help! It was a big part of the troubleshooting process.

        Reply
        1. Rens Hollanders

          Hi Gregg,

          Thanks for getting back to me. Good you figured out a way to get around your problem. Also I’m glad I’d could be of some assistance for the troubleshooting part.

          Cheers! Rens

          Reply
  4. Riz

    Hi Rens,

    We have our MDT environment set to join machines to join the domain literally after the OS is installed and drivers injected. This is however caused us many problems because then the task sequence has to install 4 apps and they sometimes fail because of the GPOs that are applied. Would moving the domain join until after the apps are installed do any harm? Don’t really want to create a staging OU with block inheritance on..

    Cheers

    Reply
    1. Rens Hollanders

      Hi Riz,

      It’s worth a try certainly. Just place the “Recover from Domain” in the “State Restore” step after the installation of your applications. But keep in mind that anything domain related will not work before you join the domain. Also it would be a possibility to join the domain force a GPO update, perform a wait and reboot and then install your applications.

      So I think you have some options here!
      Good luck!

      Cheers! Rens

      Reply
      1. Riz

        Hi Rens,

        I’ve moved it but it still seems to be joining the domain before installing apps and not after?

        Reply
        1. Rens Hollanders

          Riz,

          Seems or do you know that for sure? Look at your bdd.log on the deployed machine. To my knowledge if you remove the “Recover From Domain” step it should not recover from the domain. Otherwise an option would be to pass along the domain join variables like Task Sequence Variables after the installation of the applications and then manually call the script that is responsible for the domain join. This is: “ZTIDomainJoin.wsf” and can be find in the .\DeploymentShare\Scripts folder, you can call the script with a variable: cscript.exe [//nologo] %SCRIPTROOT%\ZTIDomainJoin.wsf [/debug:true]

          Cheers! Rens

          Reply
          1. Riz

            Hi Rens,

            I’ve checked and its definitely still joining the domain before the app installs. How would i move this till after the apps have all been installed? Like previously stated i moved the recover from domain task and it didnt make a difference.

          2. Rens Hollanders

            Hi Riz,

            To my knowledge this would only work to remove the recover from domain step, and call the script manually in a later more desirable phase. Have a look in the deploymentshare\scripts folder to find a script called ZTIDomainJoin.wsf, this script can be called by yourself too!

            Cheers! Rens

  5. GraceSolutions

    I have a script that you can use arguments with that allows for joining to the domain. It was written in VBScript, but this can be done using Powershell as well, using the Add-Computer CMDLet. In any case, here is the script.

    It can be used in a task sequence step like

    Name:
    Join “%OSDDomainName%” Domain as “%OSDJoinAccount%”

    Command Line:
    cscript.exe “%SCRIPTROOT%\Custom-ZTIDomainJoin.vbs” /JoinDomain /Domain:”%OSDDomainName%” /SvcAcct:”%OSDJoinAccount%” /SvcAcctPw:”%OSDJoinPassword%”

    This script will pass the values specified in customsettings.ini or the credentials specified from the credential prompt if not provided in bootstrap.ini and join the device to the domain. It will make a new computer object if one does not exist in Active Directory and update an existing object if one does.

    ***The only caveat is that you have to remove any domain lines from Unattend.xml files associated with your task seqences. This way, when MST runs ZTIConfigure.wsf to write values to the Unattend.xml file, it will not have a place to put them and therefore not join the device to the domain until you tell it to do so later in the task sequence. It can be done automatically for all future task sequences by editing the template Unattend files within the MDT install directory.***

    ‘Define Target Computer
    strComputer = “.”

    ‘Set object values
    Set oArguments = WScript.Arguments.Named
    Set oShell = CreateObject(“WScript.Shell”)
    Set oWMI = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\” & strComputer & “\root\CIMV2”)

    ‘Define ASCII Characters
    chrSpace = Chr(32)
    chrSingleQuote = Chr(39)
    chrDoubleQuote = Chr(34)

    ‘Show Script Usage
    If (oArguments.Exists(“?”)) And (WScript.Arguments.Count = “1”) Then
    WScript.Echo(WScript.ScriptName & chrSpace & “Usage:” & _
    vbCrLf & vbCrLf & _
    “Script Interpreter: [cscript.exe] or [wscript.exe]” & _
    vbCrLf & vbCrLf & _
    “Script Location:” & chrSpace & chrDoubleQuote & Replace(oShell.CurrentDirectory & “\” & WScript.ScriptName, “\\”, “\”) & chrDoubleQuote & _
    vbCrLf & vbCrLf & _
    “Optional Arguments:” & _
    vbCrLf & vbCrLf & _
    “[/JoinDomain]” & chrSpace & “And” & chrSpace & “[/Domain:” & chrDoubleQuote & “MyDomain.com” & chrDoubleQuote & “]” & _
    vbCrLf & vbCrLf & _
    “[/JoinWorkgroup]” & chrSpace & “And” & chrSpace & “[/WorkGroup:” & chrDoubleQuote & “MyWorkGroup” & chrDoubleQuote & “]” & _
    vbCrLf & vbCrLf & _
    “[/Rename]” & chrSpace & “And” & chrSpace & “[/Name:” & chrDoubleQuote & “MyDeviceName” & chrDoubleQuote & “]” & _
    vbCrLf & vbCrLf & _
    “[/SvcAcctDmn:” & chrDoubleQuote & “MyDomain” & chrDoubleQuote & “]” & _
    vbCrLf & vbCrLf & _
    “[/SvcAcct:” & chrDoubleQuote & “MyDomain\MySvcAcct” & chrDoubleQuote & “]” & _
    vbCrLf & vbCrLf & _
    “[/SvcAcctPw:” & chrDoubleQuote & “MySvcAcctPw” & chrDoubleQuote & “]” & _
    vbCrLf & vbCrLf & _
    “[/UnjoinDomain]” & _
    vbCrLf & vbCrLf & _
    “[/Restart]”)
    WScript.Quit
    End If

    ‘Define Required Arguments
    argDomain = Trim(UCase(oArguments.Item(“Domain”)))
    argWorkGroup = Trim(UCase(oArguments.Item(“Workgroup”)))
    argSvcAcct = Trim(UCase(oArguments.Item(“SvcAcct”)))
    argSvcAcctDmn = Trim(UCase(oArguments.Item(“SvcAcctDmn”)))
    argSvcAcctPw = oArguments.Item(“SvcAcctPw”)

    ‘Define Optional Arguments
    If (oArguments.Exists(“Name”)) Then
    argName = Left(oArguments.Item(“Name”), 15)
    argName = Replace(argName, chrSpace, “”)
    argName = UCase(argName)
    End If

    If (oArguments.Exists(“OU”)) And Not (oArguments.Exists(“OU”)) = “” And Not IsNull(oArguments.Exists(“OU”)) Then
    argOU = oArguments.Item(“OU”)
    argOU = Trim(argOU)
    Else
    argOU = Null
    End If

    ‘Define Variables
    ‘Amount of seconds to wait “Change the first number only as WScript.Sleep method expects the value in milliseconds.”
    intSeconds = Int(15 * 1000)

    ‘Gather Information From WMI

    ‘Query #1 – Win32_BIOS
    Set oBIOS = oWMI.ExecQuery(“Select * From Win32_BIOS”)
    If (oBIOS.Count > 0) Then
    For Each oItem In oBIOS
    If Not IsNull(oItem.SerialNumber) Then
    strSerialNumber = Left(oItem.SerialNumber, 15)
    strSerialNumber = Trim(UCase(strSerialNumber))
    End If
    Next
    End If

    ‘Query #2 – Win32_OperatingSystem
    Function RestartDevice
    Set oWMI = GetObject(“winmgmts:{(Shutdown)}//” & strComputer & “/root/cimv2”)
    Set oOperatingSystem = oWMI.ExecQuery(“Select * From Win32_OperatingSystem”)
    If (oOperatingSystem.Count > 0) Then
    For Each oItem In oOperatingSystem
    If (oItem.Primary = True) Then
    RestartDevice = oItem.Reboot()
    End If
    Next
    End If
    End Function

    ‘Query #3 – Win32_ComputerSystem
    Set oComputerSystem = oWMI.ExecQuery(“Select * From Win32_ComputerSystem”)

    ‘Process the collection only if the query has results
    If (oComputerSystem.Count > 0) Then

    ‘Begin a for loop on the collection
    For Each oItem In oComputerSystem

    ‘Determine the value of the “DNSHostName” property
    If Not IsNull(oItem.DNSHostName) And Not IsNull(oItem.Domain) Then
    strDNSHostName = Trim(UCase(oItem.DNSHostName & “.” & oItem.Domain))
    End If

    ‘Determine the value of the “Domain” property
    If Not IsNull(oItem.Domain) Then
    strDomain = Trim(UCase(oItem.Domain))
    End If

    ‘Determine the value of the “PartOfDomain” property
    If Not IsNull(oItem.PartOfDomain) Then
    strPartOfDomain = Trim(UCase(oItem.PartOfDomain))
    End If

    ‘Determine the value of the “Name” property
    If Not IsNull(oItem.Name) Then
    strComputerName = Trim(UCase(oItem.Name))
    End If

    ‘Determine the value of the “Username” property
    If Not IsNull(oItem.UserName) Then
    strDomainUserName = Trim(oItem.UserName)
    If InStr(oItem.UserName, “\”) > 0 Then
    strUserName = Mid(oItem.UserName, InStr(oItem.UserName, “\”) + 1)
    strUserName = Trim(strUserName)
    End If
    End If

    ‘Determine the value of the “Workgroup” property
    If Not IsNull(oItem.Workgroup) And (oItem.PartOfDomain = False) Then
    strWorkgroup = Trim(UCase(oItem.Workgroup))
    End If

    ‘Rename the device using the name specified in ArgName (Specified name will be truncated to 15 characters for computer name limit)
    If (oArguments.Exists(“Rename”)) And (oArguments.Exists(“Name”)) And Not (ArgName = “”) Then

    RenameDevice = oItem.Rename(argName, argSvcAcct, argSvcAcctPw)

    WScript.Sleep(intSeconds)

    If (RenameDevice = “0”) Then
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was successfully renamed to” & chrSpace & chrDoubleQuote & argName & chrDoubleQuote & “.” & vbCrLf)
    Else
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was not renamed successfully.” & chrSpace & “(” & RenameDevice & “)” & “.” & vbCrLf)
    WScript.Quit(RenameDevice)
    End If

    ‘Rename the device using its serial number truncated to 15 characters for computer name limit
    ElseIf (oArguments.Exists(“Rename”)) And Not (oArguments.Exists(“Name”)) Then

    RenameDevice = oItem.Rename(strSerialNumber, argSvcAcct, argSvcAcctPw)

    WScript.Sleep(intSeconds)

    If (RenameDevice = “0”) Then
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was successfully renamed to” & chrSpace & chrDoubleQuote & strSerialNumber & chrDoubleQuote & “.” & vbCrLf)
    Else
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was not renamed successfully.” & chrSpace & “(” & RenameDevice & “)” & “.” & vbCrLf)
    WScript.Quit(RenameDevice)
    End If

    End If

    ‘Remove device from the Domain
    If (strPartOfDomain = “TRUE”) And (oArguments.Exists(“UnjoinDomain”)) Then

    UnjoinDomain = oItem.UnjoinDomainOrWorkgroup(argSvcAcctPw, argSvcAcct)

    WScript.Sleep(intSeconds)

    If (UnjoinDomain = “0”) Then
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was successfully removed from the” & chrSpace & chrDoubleQuote & strDomain & chrDoubleQuote & chrSpace & “domain.” & vbCrLf)
    Else
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was unsuccessful” & chrSpace & “(” & UnjoinDomain & “)” & chrSpace & “in being removed from the” & chrSpace & chrDoubleQuote & strDomain & chrDoubleQuote & chrSpace & “domain.” & vbCrLf)
    WScript.Quit(UnjoinDomain)
    End If

    End If

    ‘Join the specified Domain
    If (strPartOfDomain = “FALSE”) And (oArguments.Exists(“JoinDomain”)) And (oArguments.Exists(“Domain”)) And Not (argDomain = “”) And Not (oArguments.Exists(“JoinWorkGroup”)) Then

    Const Join_Domain = 1
    Const Acct_Create = 2
    Const Win9x_Upgrade = 16
    Const Domain_Join_If_Joined = 32
    Const Join_Unsecure = 64
    Const Machine_Password_Passed = 128
    Const Deferred_Spn_Set = 256
    Const Install_Invocation = 262144
    fJoinOptions = Join_Domain + Acct_Create

    JoinDomain = oItem.JoinDomainOrWorkgroup(argDomain, argSvcAcctPw, argSvcAcct, argOU, fJoinOptions)

    WScript.Sleep(intSeconds)

    If (JoinDomain = “0”) Then
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was successful in joining the” & chrSpace & argDomain & chrSpace & “domain.” & vbCrLf)
    Else
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was unsuccessful” & chrSpace & “(” & JoinDomain & “)” & chrSpace & “in joining the” & chrSpace & chrDoubleQuote & argDomain & chrDoubleQuote & chrSpace & “domain.” & vbCrLf)
    WScript.Quit(JoinDomain)
    End If

    End If

    ‘Join the specified Workgroup
    If (strPartOfDomain = “FALSE”) And (oArguments.Exists(“JoinWorkGroup”)) And (oArguments.Exists(“WorkGroup”)) And Not (argWorkGroup = “”) And Not (oArguments.Exists(“JoinDomain”)) Then

    JoinWorkGroup = oItem.JoinDomainOrWorkgroup(argWorkgroup, argSvcAcctPw, argSvcAcct, Null, 0)

    WScript.Sleep(intSeconds)

    If (JoinWorkGroup = “0”) Then
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was successful in joining the” & chrSpace & argWorkgroup & chrSpace & “workgroup.” & vbCrLf)
    Else
    WScript.Echo(chrDoubleQuote & strComputerName & chrDoubleQuote & chrSpace & “was unsuccessful” & chrSpace & “(” & JoinWorkgroup & “)” & chrSpace & “in joining the” & chrSpace & chrDoubleQuote & argWorkgroup & chrDoubleQuote & chrSpace & “workgroup.” & vbCrLf)
    WScript.Quit(JoinWorkGroup)
    End If

    End If

    Next

    End If

    ‘Provide information about the device
    If (oArguments.Exists(“Info”)) Then

    If Not (strDNSHostName = “”) Then
    WScript.Echo(“FDQN:” & chrSpace & strDNSHostName & vbCrLf)
    End If

    If Not (strDomain = “”) Then
    WScript.Echo(“Domain:” & chrSpace & strDomain & vbCrLf)
    End If

    If Not (strPartOfDomain = “”) Then
    WScript.Echo(“Currently joined to a domain:” & chrSpace & strPartOfDomain & vbCrLf)
    End If

    If Not (strComputerName = “”) Then
    WScript.Echo(“Computer name:” & chrSpace & strComputerName & vbCrLf)
    End If

    If Not (strDomainUserName = “”) Then
    WScript.Echo(“Current Username w/ Domain:” & chrSpace & strDOmainUserName & vbCrLf)
    End If

    If Not (strUserName = “”) Then
    WScript.Echo(“Current Username w/o Domain:” & chrSpace & strUserName & vbCrLf)
    End If

    If Not (strWorkgroup = “”) And (strPartOfDomain = “FALSE”) Then
    WScript.Echo(“Workgroup:” & chrSpace & strWorkgroup & vbCrLf)
    End If

    End If

    ‘Optionally Restart Device
    If (oArguments.Exists(“Restart”)) Then
    Call RestartDevice
    End If

    Using this method, you will not have to rearrange you Active Directory policies or containers, just to accommodate deployment as it will somewhere towards the last step.

    If anybody needs help or wants to exchange ideas, just shoot me an email, I will be glad to help when and where I can.

    Hope this helps somebody!

    Reply
  6. Ben

    Rens, Hey I wanted to toss you a question if I may.. I’m moving from a fully working MDT 2013 server to a new (physical) one. The old deployment share is gone 🙁
    I am now on MDT 2013 U2 with the Win10 ADK. I have a nice customsettings.ini that I used previously to join the domain among other things. Currently my apply image task works perfectly except for naming the computer. The gui prompts and we enter a variable but it’s never actually applied. Which (I believe) stops the domainjoin, bitlockering, local admins being set and a few other things.
    If I specify the following:
    SkipDomainMembership=YES
    JoinDomain=domain.org
    MachineObjectOU=”OU=Computers,DC=domain,DC=org”
    DomainAdmin=Deploy
    DomainAdminDomain=domain.org
    DomainAdminPassword=password

    This worked before but not now.. do I have the correct syntax?

    Reply
    1. Rens Hollanders

      Hi Ben,

      Thanks for reaching out to me. What I’m missing is the SkipComputerName=NO, as a test you can provide the OSDComputerName=”name of your computer” in the customsettings.ini or as a Task Sequence Variable in a task sequence.

      Also please have look at these two articles I wrote, to see if this might help:
      http://renshollanders.nl/2015/04/mdt-put-the-domain-join-where-it-belongs/
      http://renshollanders.nl/2013/02/mdt-2012-settings-for-fully-automated-lti-deployment-part-ii-customsettings-ini/

      Cheers! Rens

      Reply
        1. Rens Hollanders

          Ben,

          I’ve looked at your bdd.log and cs.ini. Basically your cs.ini there’s nothing wrong. What I did notice is that in your entire BDD.log not once the property “OSDComputerName” occurs, which means no valid computername has been parsed through. Did you already test with a task sequence variable called “OSDComputerName” and the value: “name of your computer”. To test this, set SkipComputerName to YES in your cs.ini.

          Afterwards view the log file with CMtrace or trace.exe and create a filter “When the entry text” CONTAINS “Property” this will give you a clear sight of which properties are processed.

          If that wouldn’t help, I would suggest you recreate a new deploymentshare, and use a original ISO / media from Microsoft to just do a test deployment to verify everything works as it should.

          Cheers! Rens

          Reply
  7. hasanferoz

    Hello guys

    I am currently in a process of developing windows 10 roll out. My domain join sequence in the Rule is
    JoinDomain=xxx.com
    MachineObjectOU=OU=Workstations,OU=Hardware,DC=xxx,DC=com
    I dunt want to use the Domain Admin credential as it could be a security issue as the password is sent over the network in plain text. Is there anyway i can use other credentials for joining the domain. Like the one which has limited privileges of joining the domain

    Reply
      1. hasanferoz

        Thank you for your prompt response. So if i create an account like this what do i need to put in the rules will it be domainadmin= or something else ?

        Reply
        1. Rens Hollanders

          Hi,

          You are welcome, yes the account you create you will need to provide it instead of the domainadmin.

          Cheers! Rens

          Reply
          1. hasanferoz

            Apologies for being a pain but let say the example account name is MDT then the rules would look like
            JoinDomain=xxx.com
            MachineObjectOU=OU=Workstations,OU=Hardware,DC=xxx,DC=com
            DomainAdmin=MDT
            DomainAdminPassword=abc123
            can you please clarify this

  8. hasanferoz

    HI Rens

    I need to copy some folders into the program files during the installation procedure. The files are present on a shared folder and cannot be moved on the WDS server as the folders get updates periodically. Can you please guide me as to how should i go about my script. I tried to map the drives using the net use cmd in powershell but its doesnt map the drive. Any idea ?

    Reply
    1. Rens Hollanders

      Hi Hasan,

      Thank you for your question. The question you ask is on entire different topic then what my post addresses, but to keep it simple. I would use a CMD based script which does the following:
      1. Map the drive with net use n: \\server\share
      2. Copy the files for example with %~DP0 which represents the absolute path
      3. Deletes the just created mapping

      Make sure your permissions for this share is set so that users can read / append files but cannot alter it, this should be held to the persons maintaining the files.

      See an example here: http://ss64.com/nt/syntax-args.html and http://ss64.com/nt/pushd.html

      Cheers! Rens

      Reply
  9. Jim

    Hi Rens. I am deploying Windows 10 LTSB to a Virtual Machine, on a Windows 10 workstation, using MDT 2013. Everything is working correctly except the computer name is not matching the OSD computer name. It works totally fine on a physical machine. Loading a Windows 7 image on the same virtual works fine also. Any ideas? here are my settings:
    [Settings]
    Priority=Default,Architecture,ByVMType,ByDesktopType,ByLaptopType,Model,SendMail
    Properties=OSDSendMailFrom,OSDSendMailTo,OSDSendMailSubject,OSDSendMailBody,OSDSendMailSMTPServer,OSDSendMailIncludeBDDLog

    [Default]
    OSInstall=Y

    _SMSTSOrgName=xxxxxxxxxxxsktop Image Builder for %OSDComputerName%
    ApplyGPOPack=NO
    AreaCode=517
    CountryCode=001
    Dialing=TONE
    DoCapture=YES
    FinishAction=REBOOT
    FullName=xxxxxxxxxxxxxxxxxxxxxxxxxx
    SkipApplications=YES
    SkipCapture=YES
    ComputerBackupLocation=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxs
    BackupFile=W7ENTSP1x64EN.wim
    SkipAdminPassword=YES
    AdminPassword=xxxxxxxxxx
    ;SkipDomainMembership=YES
    JoinWorkGroup=WORKGROUP
    ;JoinDomain=xxxxxxxxxxx
    ;MachineObjectOU=OU=Computers,OU=xxxx,OU=Corporate,DC=xx,DC=xxxxxxx,DC=org
    ;DomainErrorRecovery=Auto
    SkipBitLocker=YES
    DomainAdmin=xxxxxxxxxxx
    DomainAdminDomain=xxxxxxxxx
    DomainAdminPassword=xxxxxxxx
    SkipProductKey=YES
    SkipSummary=YES
    SkipFinalSummary=YES
    SkipTimeZone=YES
    TimeZoneName=Eastern Standard Time
    SkipUserData=YES
    UserDataLocation=NONE
    UserDomain=ad.caajlh.org
    SkipLocaleSelection=YES
    KeyboardLocale=en-US
    UserLocale=en-US
    UILanguage=en-US
    WSUSServer=http://xxxxxxxxx
    EventService=http://xxxxxxxxx

    [ByVMType]
    Subsection=ISVM-%ISVM%

    [IsVM-True]
    SkipComputerName=NO

    [ByDesktopType]
    Subsection=Desktop-%IsDesktop%

    [ByLaptopType]
    Subsection=Laptop-%IsLaptop%

    [Desktop-True]
    SkipComputerName=YES
    OSDComputerName=%AssetTag%D

    [Laptop-True]
    SkipComputerName=YES
    OSDComputerName=%AssetTag%L

    [Latitude E5500]
    XResolution=1280
    YResolution=800

    [Latitude E5510]
    XResolution=1366
    YResolution=768

    [Latitude E5520]
    XResolution=1366
    YResolution=768

    [Latitude E5530 non-vPro]
    XResolution=1366
    YResolution=768

    [Latitude E5540]
    XResolution=1366
    YResolution=768

    [Latitude E5550]
    XResolution=1366
    YResolution=768

    [Latitude E5570]
    XResolution=1366
    YResolution=768

    [SendMail]
    OSDSendMailFrom=xxxxxxxx
    OSDSendMailTo=xxxxxxxxx
    OSDSendMailSubject=%OSDComputerName% is now reloaded
    OSDSendMailBody=The computer %OSDComputerName% was installed at #Now()#.
    OSDSendMailSMTPServer=email.xxxx.org
    OSDSendMailIncludeBDDLog=NO

    Reply
    1. Rens Hollanders

      Hi Jim,

      Thank you for your question first of all, you can simply your customsettings.ini on the resolution part. Just put the following properties in your cs.ini and it will suffice for all models:
      XResolution=1
      YResolution=1
      This forces Windows to perform an optimization to detect the highest / native resolution. This way you can shorten your cs.ini and aren’t bound any longer to make/model resolution schemes.

      Now for your question, I think you should review your bdd.log since all properties from your customsettings and their order/priority are echoed into that log file. I suspect you need to change the priority of your virtuale machine and desktop. Also check if your VM isn’t detected also as a Desktop, this is often so. This can also be reviewed in your bdd.log.

      Cheers! Rens

      Reply
      1. Jim

        Thanks for the advice Rens. I am very new to MDT (first attempt) and appreciate
        the help.

        Reply
        1. Rens Hollanders

          Hi,

          No problem, glad I’d could help. Altough my site isn’t updated as frequently anymore as I want it to be, I’ll remain giving answers on questions being asked.

          Cheers and good luck! Rens

          Reply
    1. Rens Hollanders

      Hello Esben,

      What happens when you set the SkipDomainMembership to YES and look at the BDD.log. I think it will get parsed through. Otherwise have a look at the log file if no other settings bothers you during deployment.

      Cheers! Rens

      Reply
        1. Rens Hollanders

          Esben,

          Can you provide a copy of your bdd.log? Put the following in your cs.ini then grab the logfile from the computer you are trying to deploy:
          SLShareDynamicLogging=%deployroot%\logs\%computername%

          Cheers! Rens

          Reply
          1. Rens Hollanders

            Hi Esben,

            The BDD.log isn’t complete, usually it’s a file size between 280 and 340 kb. With all the parsed customsettings.ini properties in it.
            So you have to sit and wait out the entire deployment.

            Cheers! Rens

          2. Rens Hollanders

            Hi Esben, I’ve taken a look at your BDD.log and what I can see, first the DomainJoin property is empty, then it gets provided with XX.xx as you have masked your companysettings. Afterwards the DomainJoin property is emptied again, and after this it gets set again. However I cannot see why it is emptied.

            Did you try to do a deployment with SkipDomainMembergship set to YES? Because I really never have any issues with setting and parsing the task sequence variables as I’ve explained in my blogpost.

            Cheers! Rens

          3. Esben

            With SkipDomainMembership=YES and SkipComputerName=NO set in CS.ini:
            http://www2.zippyshare.com/v/n1S5CZSd/file.html

            It did fail to join the domain, but our setup requires the machine-objects to be pre-populated before allowing joins, so unless you see some other issue that’s to be expected since I hadn’t created one…

            For some reason my capture task sequence fails with joindomain in CS.ini, so my initial goal was to be able to prepopulate the fields without joindomain in CS.ini.

          4. Esben

            Update: Nope, didn’t join the domain. Ended up in the “123” workgroup

  10. Frank

    I don’t know what I’m missing.
    The only thing I want is for MDT to ask for computer name.
    I have the customsettings.ini set for the domain and the OU location but when i start the MDM it still show if i want to join a workgroup or a domain.
    Please help

    Reply
    1. Rens Hollanders

      Hi Frank,
      SkipDomainMembership should be set to YES
      SkipComputerName should be set to NO

      Cheers! Rens

      Reply
  11. Scott

    Hi Rens,
    I have tried using the task sequence variables method however it doesn’t appear to be parsing them, is there a way to verify that they are being read?

    Cheers! Scott

    Reply
    1. Rens Hollanders

      Hi,
      sure, try this: cscript \litetouch.vbs /inifile: /tasksequenceid:

      You’ll find a MININT folder on the machine you ran the aboven commandline on, view the bdd.log with CMtrace.exe to see which settings have parsed.

      Cheers! Rens

      Reply
  12. aravind

    Hello Rens,

    How can we move domain join to end of the task sequence?
    We have a TS which works good. But we are making some changes to our policies, taking local admin rights from everyone one, once joined domain. So I want to install applications before joining domain
    Thanks

    Reply
    1. Rens Hollanders

      Hi Aravind,

      Sure you can place the domain join at the end, but this has to be done without the recover from domain step in the MDT task sequence. Either you call the ZTIDomainJoin.wsf script yourself (variables used during the task sequence such as domain join information can still be used) or you use a custom script (again the same variables that are already present can be used)

      Cheers! Rens

      Reply
  13. Syed Safi

    Hi Rens,

    I am glad to see this blog helping a lot everyone for resolving the MDT related issues.

    It would be very helpful to me if you guide me how to fix the issue related to the domain join in my new MDT server.

    First of all I am able to capture the image and deploy the image successfully without any error. However the machine is not getting joined to the company domain after the deployment.

    Before capturing I am removing the machine from the domain. and using the .wim file for the deployment.

    I have gone through lot of blogs but didn’t able to get the proper info.

    I hope you will help me to fix this issue.

    Thank you in advance.

    Reply
    1. Rens Hollanders Post author

      Hi Syed,

      Sure no problem. In your bdd.log you will find the properties that are used to do the deployment with. You can read and create a filter to search for all properties with cmtrace.exe. Find for the Domain Join settings to see if they are present. Also during deployment you can find a unique per deployment unattend.xml for your computer first in X:\MININT (during WinPE) and after in C:\MININT (during Windows setup) check the unattend to see the domain join settings are there.

      perform a domain join manually to verify the account is OK, and has enough privileges to join machines to the desired OU.

      Let me know the results.

      Cheers! Rens

      Reply
  14. Nicholas Bird

    Hi Rens,

    im on mdt 8450…

    are you saying setting joindomain variable in task sequence only works if you set skipdomainmembership in customsettings.ini?

    i find that joindomain and osdcomputername variables come into effect when placed in customsettings.ini but not when placed in task sequence itself (at least to the extent that when the deploy wizard pops up the variables are not populated as desired)

    ty

    Reply
    1. Rens Hollanders Post author

      Hi Nicholas,

      Sorry for the late response, I was abroad for some time not checking my blog. If you put the variables at the beginning of your TS everything should work just fine. You can see the processing of them in bdd.log. Think you need to set SkipDomain question in CS.ini

      Cheers! Rens

      Reply
  15. Ryan

    Hi Rens,

    I was hoping to follow your recommendations and put the domain join at the end of the task sequence, however I realized the domain join needs to stay in its default location because subsequent tasks require access to a network share within the domain. The problem with the domain join in the default location is that after the domain join and reboot, it applies group policies which break MDT automation, specifically the logon notice which has been well documented in other Google results. I’ve temporarily removed the group policy setting for the logon notice, however, now MDT just sits at the logon prompt. It no longer logs in automatically as the local administrator as it did after the initial reboot If I manually log in as the local administrator or domain administrator, then MDT will pick up where it left off and complete properly. I can’t figure out how to get MDT to logon automatically after joining the domain. Any advice is much appreciated. Thanks.

    Reply
    1. Rens Hollanders Post author

      Ryan,

      What happens when you let the machines come in a OU with block inheritance on them? Cause that would be the ‘normal’ thing to do.
      Other options is to do it later manually instead of using the MDT automated task of joining the domain, but then you cannot access resources on the network that require domain level authentication.

      Cheers! Rens

      Reply
  16. HItesh Mistry

    Hi Rens,
    I am new to MDT & WDS.
    Currently I have setup WDS & MDT(Win 2012r2) on 1 server and obtaing DHCP from dedicated server.
    When i try to deploy a win 7 Image it ask for Admin credentials, but this information is already in custom.ini & Bootstrap.

    Settings]
    Priority=Default
    Properties=MyCustomProperty

    [Default]
    OSInstall=Y
    SkipBDDWelcome=YES
    UserID=xxx
    UserDomain=xxxxx
    UserPassword=xxxx
    SkipCapture=YES
    SkipProductKey=YES
    SkipComputerBackup=YES
    SkipBitLocker=YES
    KeyboardLocale=0809:00000809
    UserLocale=en-GB
    UILanguage=en-GB
    SkipTimeZone=YES
    TimeZoneName=GMT Standard Time
    EventService=http://MDT:9800
    WSUSServer=http://xxxxx

    bootstrap:

    [Settings]
    Priority=Default

    [Default]
    DeployRoot=\\MDT\DeploymentShare$
    UserID=xxxx
    UserDomain=xxxxx
    UserPassword=xxxx
    KeyboardLocale=en-GB
    SkipBDDWelcome=YES

    Also I would like to image pc from another location, so that they can pull the image from central location.
    Any help appreciated.

    Reply
  17. William

    Hello,
    Nice articles you write!
    I’m stuck on following issue: i have created an auto domain logon script for a specific user for certain installations. After those sysprep should initialize. Being on the domain, this will not be possible, so I need to unjoin from the domain. Powershell script Remove-Computer not working strangely. Do you have experience with this or can you advise with clear example?*
    Regards,
    W.

    Reply
  18. Mario Veras

    I actually found a much easier and better method to deal with the problem of domain policies interfering with the final stages of MDT deployments. Basically, all we need to do is suppress the scripted reboot that happens right after MDT joins the domain. This allows for MDT to fly through the rest of the task sequence and perform software installs and any other tasks you’ve created after joining the domain without reboots, therefore, preventing any group policies from the domain to interfere since you haven’t rebooted yet. Then, when the task sequence finishes, you can automatically reboot the machine by adding FinishAction=RESTART to your CustomSettings.ini.

    All you have to do is edit the ZTIDomainJoin.wsf script by “commenting out” the two lines that end with “true”. Just type an apostrophe in front of each of the lines as illustrated below:

    oEnvironment.Item(“LTISuspend”) = “” 

    ‘oEnvironment.Item(“SMSTSRetryRequested”) = “true”
    ‘oEnvironment.Item(“SMSTSRebootRequested”) = “true”

    iRetVal = SUCCESS

    This method is much cleaner because it does not require messing with Unattend.xml or altering the task sequence order or removing MDT’s built-in method to join the domain or using any 3rd party vbs scripts to join the domain.

    Reply

Leave a Reply to Frank Cancel reply

Your email address will not be published.