Azure ARM: VM Domain Join to Active Directory Domain with "JoinDomain" Extension

It is a pretty common scenario to provision a Virtual Machine (VM) in Azure and join it to an existing Active Directory (AD) Domain, either extended from on-premises via hybrid connections, or natively deployed in the cloud installing Domain Controllers (DCs) into Azure VMs. Using legacy Azure Service Management API (ASM), a nice PowerShell cmdlet called “Add-AzureProvisioningConfig” is available, with “ -JoinDomain” switch to automatically join the VM to an AD domain as in example below:

Add-AzureProvisioningConfig

https://msdn.microsoft.com/en-us/library/azure/dn495299.aspx

Unfortunately, there is no more evidence of domain join functionality in the newest Azure Resource Manager (ARM) API, then how to gain back that nice feature previously available in Azure ASM? There are essentially two ways, both based on a new type of ARM “Extension” called “JsonADDomainExtension”:

  • Using Azure ARM Templates (“declarative mode”).
  • Using Azure ARM PowerShell Cmdlet (“imperative mode”).

The first approach is very simple; you can find a template sample for automatic VM joining to an AD domain at the link below in GitHub:

201-vm-domain-join

https://github.com/Azure/azure-quickstart-templates/blob/master/201-vm-domain-join/azuredeploy.json

As you can see, this new extension type can take all the necessary parameters to join a VM to an existing AD domain, and then finally reboot the VM once the join operation is complete. If you try to search using Bing about this extension, you will not find (at least at the time of writing this post) any public reference nor documentation. Now, what happen if you don’t or want to use an ARM template and instead you have/want to use “imperative” PowerShell? What I have done below is reverse-engineering the template mentioned above and test a very simple script. First of all, you need to prepare two JSON strings as in the example below:

 

The first one contains all the necessary parameters/options for the domain join operation, please note that there is no documentation on the possible values for “Options”, value (3) is recommended in the GitHub template mentioned above. The second one contains protected info that the extension mechanism will encrypt transparently to guarantee security of passwords. After that, simply execute the PowerShell cmdlet below:

Execution of “Set-AzureRmVMExtension” cmdlet will require some time; you can check the status using the “Get-AzureRmVMExtension” cmdlet as in the example below (output sample included):

From the Azure Portal, you can see almost the same level of details going into the “Extension” tab of your Virtual Machine:

 

That’s all I wanted to share with you, hope you will find this content useful and interesting, feel free to post your comments and feedbacks here. Remember that you can also follow me on Twitter ( @igorpag). Best Regards.

 

 

 

SampleScript.ps1.txt

Comments

  • Anonymous
    January 24, 2016
    Awesome! thank you

  • Anonymous
    January 28, 2016
    Very Useful. Thanks.

  • Anonymous
    February 07, 2016
    Hi, thank you for your excellent description of this subject. I am having trouble joining using the ARM template on certain VHD files I have made. Some work, some don't. Is there a setting on the image that needs to be set right for this to work?

  • Anonymous
    February 07, 2016
    The comment has been removed

  • Anonymous
    March 22, 2016
    Worked like a charm. I ran the VM extensions after I created the VM, where Add-AzureProvisioningConfig is run prior to creating the VM.

  • Anonymous
    June 27, 2016
    Hi,We are deployig VMs using JSON which is working fine. In the existing JSON, I have added the extension to add the VM to the Domain, while deploying the VM, I am getting an error for adding it to the Domain, it say not getting the "'The template variable 'apiVersion' is not found". Please suggest.

  • Anonymous
    September 06, 2016
    Hi Igor,Nice article, thanks. Although when I try to use 201 domain join template, it fails with a joindomain extension conflict error, have you run into this issue at all.?

    • Anonymous
      September 07, 2016
      Conflict error on using the ARM template? Sorry no, never heard about that.Regards.
  • Anonymous
    September 14, 2016
    I am getting below error using Github template code { "apiVersion": "2015-06-15", "type": "Microsoft.Compute/virtualMachines/extensions", "name": "[concat(parameters('vmName'),'/joindomain')]", "location": "[resourceGroup().location]", "dependsOn": [ "[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]" ], "properties": { "publisher": "Microsoft.Compute", "type": "JsonADDomainExtension", "typeHandlerVersion": "1.3", "autoUpgradeMinorVersion": true, "settings": { "Name": "[parameters('domainToJoin')]", "OUPath": "[parameters('ouPath')]", "User": "[concat(parameters('domainToJoin'), '', parameters('domainUsername'))]", "Restart": "true", "Options": "[parameters('domainJoinOptions')]" }, "protectedsettings": { "Password": "[parameters('domainPassword')]"New-AzureRmResourceGroupDeployment : 11:20:11 AM - Handler 'Microsoft.Compute.JsonADDomainExtension' has reported failure for VM Extension 'joindomain' with terminal error code '1009' and error message: 'Enable failed 11:20:11 - [ERROR] for plugin (name: Microsoft.Compute.JsonADDomainExtension, version 1.3) with exception Command C:\Packages\Plugins\Microsoft.Compute.JsonADDomainExtension\1.3\enable.cmd of Microsoft.Compute.JsonADDomainExtension has 11:20:11 - [ERROR] not exited on time! Killing it...'

    • Anonymous
      December 21, 2016
      Hello I just found the reason for my error on the ARM template deployment, You may want to look your specific case under: %windir%\debug\netsetup.logIn my case it was failing because of incorrect referenced username in the template.wrong definittion on the template I had:"User": "parameters('domainUsername'))"It has missing the enclosing [ ], and the log says:12/20/2016 22:45:20:804 HostName: testVM12/20/2016 22:45:20:804 NetbiosName: testVM12/20/2016 22:45:20:804 Domain: example.com12/20/2016 22:45:20:804 MachineAccountOU: OU=Servers,DC=example,DC=com12/20/2016 22:45:20:804 Account: parameters('domainUsername')) ******** notice the parameter was not passed correctly12/20/2016 22:45:20:804 Options: 0x3 Regards
  • Anonymous
    September 16, 2016
    Sorry for this question as it is a reflection on my lack of powershell knowledge and not a problem with your script. I actually used it perfectly and LOVE it! I want to add it to my own script and am trying to use variables for the domain join info. for example: rather than having the domain name hard coded in, I have if statements to determine the domain to use. here is an example:IF ($SubName -eq "ProdSubcription") {$DomainName = 'Companyname.com' }IF ($DomainName -eq "Companyname.com") { $DomainUser = 'Administrator' }So then i want to have the script you wrote look like this:$String1 "Name": "$DomainName" "User" : "DomainUser"Problem is when it runs it doesn't see the variable, rather thinks the domain is called $DomainName.... any ideas?

    • Anonymous
      December 09, 2016
      @Mike Bergin, If you're replacing information in the script example in this post, you need to change the quotes from single to double. So it would start $string1 = "{ ... Single quotes are literal strings, double quotes allow for variable replacement. HTH
  • Anonymous
    November 15, 2016
    Hey Igor,Great script. It works.

  • Anonymous
    December 23, 2016
    It works , but getting this error "Handler 'Microsoft.Compute.JsonADDomainExtension' has reported failure for VM Extension 'joindomain' with terminal error code '1009' and error message: 'Enable failed for pluginmpute.JsonADDomainExtension' has reported failure for VM Extension 'joindomain' with terminal error code '1009' and error message: 'Enable failed for plugin (name: Microsoft.Compute.JsonADDomainExtension, version 1.3) with exception Command C:\Packages\Plugins\Microsoft.Compute.JsonADDomainExtension\1.3\enable.cmd of Microsoft.Compute.JsonADDomainExtension has not exited on time! Killing it...'"is there any settings for timeout ?

    • Anonymous
      April 13, 2017
      Dyanesh December 23, 2016 at 5:56 pm It works , but getting this error“Handler ‘Microsoft.Compute.JsonADDomainExtension’ has reported failure for VM Extension ‘joindomain’ with terminal error code ‘1009’ and error message: ‘Enable failed for pluginmpute.JsonADDomainExtension’ has reported failure for VM Extension ‘joindomain’ with terminal error code ‘1009’ and error message: ‘Enable failed for plugin (name: Microsoft.Compute.JsonADDomainExtension, version 1.3) with exception Command C:\Packages\Plugins\Microsoft.Compute.JsonADDomainExtension\1.3\enable.cmd of Microsoft.Compute.JsonADDomainExtension has not exited on time! Killing it…'”is there any settings for timeout ?
    • Anonymous
      April 13, 2017
      Hi,with terminal error code ‘1009’ and error message: ‘Enable failed for plugin (name: Microsoft.Compute.JsonADDomainExtension, version 1.3) with exception Command C:\Packages\Plugins\Microsoft.Compute.JsonADDomainExtension\1.3\enable.cmd of Microsoft.Compute.JsonADDomainExtension has not exited on time! Killing it…regards:durga
  • Anonymous
    February 22, 2017
    I have to ask. Does this now support joining Azure Active Directory?

  • Anonymous
    April 13, 2017
    Great option But when using this with managed disk as an image VM's I got the following error. If I use a storage account it worked.New-AzureRmVM : Long running operation failed with status 'Failed'.ErrorCode: PropertyChangeNotAllowedErrorMessage: Changing property 'sourceUri' is not allowed.

  • Anonymous
    August 22, 2017
    Siga as instruções e veja dinheiro entrar!