Offline Domain Join with MDT
Windows 7 and Windows Server 2008 R2 come with a new feature called “Offline Domain Join”. With this, you get the possibility to join a computer or member server to the domain, even if that computer/server currently isn’t connected to the domain. Why would I need that, you might ask. Well, think about remote workers or remote technicians, that might only have a VPN connection to your network. Or you have (or are) an external company (OEM, etc.), preparing the new computers at a remote location and you want to have them read to go, without anyone locally doing the domain join afterwards or some script that runs automatically after the first restart.
For this, Windows 7 and Windows Server 2008 R2 come with a small tool called “DJoin.exe”. It must be called with elevated privileges. DJoin allows you to either provision a new computer account and store this information in a textfile (or a Base 64 encoded blob), or use this textfile to prepare the current computer to join the domain using the specified textfile on next reboot (e.g. after it has been delivered).
Provision a new computer
To provision a new computer account, you can specify the Domain to join, the name of the new computer account and optionally the OU where the computer account shall be created.
Lets create a Demo computer:
djoin.exe /PROVISION /DOMAIN mklab.com /MACHINE ODJDemo01 /SAVEFILE ODJDemo01.txt
If you don’t have DC with Server 2008 R2 available, you need to specify the parameter “/DOWNLEVEL”. However after DJoin.exe has finished successfully, we will have a small text file, that contains the Offline domain join information, that are necessary to join a computer with this name to the domain. If you look at the file, you will see some Base 64 encoded information. As this is pretty sensitive information, you should keep this file protected.
Offline Domain Join – manually
Now we can use this text file and the DJoin.exe on another computer, to join it to the domain.
djoin.exe /REQUESTODJ /LOADFILE C:\ODJDemo01.txt /WINDOWSPATH C:\Windows
On next reboot, the computer will be joined to the domain. So you could run this as last step of your preparation, before the computer is being sent to its target location. And if it boots there, its already a member of the domain.
Offline Domain Join – automatically using DJoin.exe
So far, nothing really fancy. OK, the offline domain join itself is pretty cool, but still requires some manual steps. And as a frequent reader of this blog, you most probably want to have this automated.
Let’s first automate the domain join via the text file that’s being created. Automating the creation of the text files is pretty easy. All you need is a list of computers names, and then just parse this list with e.g. PowerShell and call djoin.exe for each entry as show above. Then we need a small script, that is called from our Task Sequence and executes DJoin.exe appropriately. Find the script on CodePlex. It expects the file to be named with the computer name and will find it at any “default” location, e.g. in the Tools or Servicing folder. After next reboot (typically after the Task Sequence has completed) the computer will be a domain member.
Offline Domain Join – Automatically using Unattend.xml
That works, but still requires some manual work. However, there is a second way to do this, which doesn’t require the text file itself. As actually all we need is the Base 64 encoded Blob. How could we get this blob without the file? Well, one way could be to store this blob in a custom property in the database. Now this database just needs to be available from everyone, that does the deployment. Or imagine you have a publicly available web service (with proper authentication and authorization ) that takes a computer name and spits out the required blob. Then this web service could be called from the OEM during the preparation of the computer and we have all the information we need to join this computer to the domain.
Now that blob needs to be added to the Unattend.xml file. MDT is already updating the Unattend.xml file with all your settings. So one would think it shouldn’t be to hard to get this done. Sadly, it’s not working out of the box as MDT doesn’t know about how to add this information. We would need to update the original ZTIConfigure.xml file with the necessary mapping information. But I really hate to change the original files as I would have to redo it on every update, it could interfere with other scripts, etc. Luckily, I just published a script, that is, beside other helpful tasks, also able to update xml files (see ZTICustomConfiguration.wsf – a script to solve common tasks in MDT Deployments for more information and samples). We just need to download it from CodePlex and drop it in the MDT scripts folder.
We update the ZTICustomConfiguration.xml file with a section that will update the Unattend.xml file as required for our offline domain join. It will only be processed, if we are in the PREINSTALL Phase and if the OfflineDomainJoinBlob has a value.
<configurationset id="ODJ"> <operations> <!-- Updates the unattend.xml file for an offline domain join--> <file source="%OSDAnswerFilePath%" operation="update" type="xml"> <rules> <include condition="All"> <rule property="PHASE" operation="equals" value="PREINSTALL" /> <rule property="OfflineDomainJoinBlob" operator="notempty" /> </include>> </rules> <node operation="delete"> <xpath><![CDATA[//settings[@pass="specialize"]/component[@name="Microsoft-Windows-UnattendedJoin"]/Identification]]></xpath> </node> <node operation="create"> <xpath><![CDATA[//settings[@pass="specialize"]/component[@name="Microsoft-Windows-UnattendedJoin"]]]></xpath> <node position="child"> <Identification> <Provisioning> <AccountData>%OfflineDomainJoinBlob%</AccountData> </Provisioning> </Identification> </node> </node> </file> </operations> </configurationset>
Now we need to update our CustomSettings.ini. We create a new custom property called OfflineDomainJoinBlob (Used in the xml seen above). And also configure it to reach out to our web service that returns this blob and store the value in this property. But this could also be a database call or a script that reads the text file and extracts the blob etc. As always, there isn’t only one way of doing things.
[Settings] Priority=Init,GetODJBlob,Default Properties=ConfigurationSet(*),OfflineDomainJoinBlob [Init] ConfigurationSet001=ODJ [Default] [GetODJBlob] WebService=http://YourWebServer/DeploymentWebService/AD.asmx/GetOfflineDomainJoinBlob Parameters=OSDComputerName,MachineObjectOU OSDComputerName=ComputerName MachineObjectOU=OUPath OfflineDomainJoinBlob=string
Then we add a new step to our Task Sequence, just right after the “Configure” step, that calls our ZTICustomConfiguration.wsf script.
What will happen during the deployment is the following.
- At the very beginning, MDT will run the Gather and evaluate our customsettings.ini. It will create the custom properties we have specified, it will set the values we have specified and it will also call the web service and store the blob in the property OfflineDomainJoinBlob
- ZTICustomConfiguration.wsf will be called just after the Configure step has already updated the Unattend.xml file. If the OfflineDomainJobBlob property has a value assigned, it will remove all information about an online domain join and replace it with the offline domain join information.
- After the first reboot, Windows setup will evaluate the Unattend.xml file and by this automagically join the domain that isn’t available yet.
As always, all scripts and files can be found on CodePlex (Download here). But you don’t get everything for free this time. The updated web service that is used during this sample will be published, after the next 20 reviews of the MDT Customizations project on CodePlex. Interested to see how long that takes.