Microsoft 365


Active Directory


Windows Server


Microsoft Teams Day is back!


Microsoft Azure

Deploy an Azure VM to an Existing Domain using an ARM Template

Russell Smith



In today’s Ask the Admin, I’ll show you how to deploy a Windows Server 2012 R2 VM in Azure and join it to an existing Active Directory (AD) domain.

This tutorial uses Azure Resource Manager (ARM) to deploy a virtual machine and join it to a domain. If you need a primer on ARM and how to work with templates, or want to deploy a new AD domain in Azure, take a look at “Provision a domain using a Microsoft Azure Resource Manager template” on the Petri IT Knowledgebase.

Get the template URI

As in the previous article, I’m going to use a readymade template, 201-vm-domain-join, from the quick-start gallery on GitHub. First we need to get the template URI:

  • Open the 201-vm-domain-join template in a browser.
  • Click azuredeploy.json in the list of files.
  • Click Raw above the template code on the right.
Azure JSON ARM template (Image Credit: Russell Smith)

Azure JSON ARM template (Image Credit: Russell Smith)

  • Once the browser is displaying the raw template code, copy the URL from the browser address bar. This is the URI for the template required by the New-AzureRmResourceGroupDeployment cmdlet.

Deploy a VM using an ARM template

Before you can start working with the PowerShell ARM cmdlets, you’ll need to make sure that you’ve got Microsoft Azure PowerShell 1.0 or later installed on your system. For more information, see “Install Azure PowerShell 1.0 Preview” on Petri.

  • Open Windows PowerShell ISE.

The 201-vm-domain-join template creates a new VM in the same Resource Group (RG) as the domain controllers. Some additional variables are also required, including the name of the virtual network (VNET), subnet, AD domain administrator username and password, and a local administrator username and password for the new VM. To keep it simple, I’ll specify the same VNET and subnet that host my domain controller in Azure.

Template parameters in the Azure Resource Manager Template Visualizer (Image Credit: Russell Smith)

Template parameters in the Azure Resource Manager Template Visualizer (Image Credit: Russell Smith)

The code below logs in to Azure ARM and selects the first available subscription associated with the given Microsoft Account. The account credentials must be entered manually when prompted. The Resource Group name is then set ($rgName), and Azure region ($location). I’ve included some error checking to throw an error if the RG doesn’t exist and if the DNS name specified for the new VM is already in use.


$subs = Get-AzureRmSubscription 
Select-AzureRmSubscription -TenantId $subs[0].TenantId -SubscriptionId $subs[0].SubscriptionId

$rgName ='contosodcs'
$location = 'North Europe'
$domainPassword = 'passW0rd!'
$vmPassword = 'passW0rd!'
$vmName = 'srv1'

# Check availability of DNS name

If ((Test-AzureRmDnsAvailability -DomainQualifiedName $vmName -Location $location) -eq $false) {
        Write-Host 'The DNS label prefix for the VM is already in use' -foregroundcolor yellow -backgroundcolor red
        throw 'An error occurred'

# Create New Resource Group
# Checks to see if RG exists
# -ErrorAction Stop added to Get-AzureRmResourceGroup cmdlet to treat errors as terminating

try {
    Get-AzureRmResourceGroup -Name $rgName -Location $location -ErrorAction Stop
} catch {
    Write-Host "Resource Group doesn't exist" -foregroundcolor yellow -backgroundcolor red
    throw 'An error occurred'
Once the prerequisites have been met, all that’s left to do is assign values to the rest of the variables required by the template. To determine the parameters required, open the template in a browser using the link in the steps above, click Visualize to open the Azure Resource Manager Template Visualizer, and then click Edit Parameter Definitions in the menu on the left. In the Parameter Editor, you’ll see a list of parameters and their default values.

In the code below, I’ve defined the parameters in a hash table, and then splat them to the New-AzureRmResourceGroupDeployment cmdlet, which deploys the resources defined in the template to the specified Resource Group. Values for some of the parameters, such as existingVNETName and existingSubnetName, are taken from the existing domain deployment.

$newVMParams = @{
    'ResourceGroupName' = $rgName
    'TemplateURI' = ''
    'existingVNETName' = 'adVNET'
    'existingSubnetName' = 'adSubnet'
    'dnsLabelPrefix' = $vmName
    'vmSize' = 'Standard_A2'
    'domainToJoin' = ''
    'domainUsername' = 'adadmin'
    'domainPassword' = convertto-securestring $domainPassword -asplaintext -force
    'ouPath' = ''
    'domainJoinOptions' = 3
    'vmAdminUsername' = 'azureuser'
    'vmAdminPassword' = convertto-securestring $vmPassword -asplaintext -force
New-AzureRmResourceGroupDeployment @newVMParams

The New-AzureRmResourceGroupDeployment can take a long time to deploy the resources defined in the template, so while it may appear to have hanged, if there’s a problem with the deployment, you’ll receive an error message fairly quickly. No output usually indicates the deployment is running successfully. You can check to see if the VM is being deploying by checking its status in the Azure management portal.

The New-AzureRmResourceGroupDeployment PowerShell cmdlet output (Image Credit: Russell Smith)

The New-AzureRmResourceGroupDeployment PowerShell cmdlet output (Image Credit: Russell Smith)

For convenience once the deployment is complete, I output the URL to connect to the VM via Remote Desktop.

# Display the RDP connection string

$rdpVM = Get-AzureRmVM -ResourceGroupName $rgName -Name $vmName

$rdpString = $vmName + '.' + $rdpVM.Location + ''
Write-Host 'Connect to the VM using the URL below:' -foregroundcolor yellow -backgroundcolor red 
Write-Host $rdpString

In this Ask the Admin, I showed you how to deploy a VM and join in to an existing Active Directory domain running in Azure, using an ARM template from the quick-start gallery.


Article saved!

Access saved content from your profile page. View Saved