Create a Load Balanced Azure IAAS Virtual Machine (VM) with an RDP connection

Overview

A very common scenario in Azure Infrastructure As A Service (IAAS) is to have two or more VM’s behind an Azure external Internet-facing load balancer.  The load balancer provides high availability and network performance by distributing traffic according to a predetermined algorithm.

In this exercise we will create a load-balanced VM in Azure – using Powershell.  And we will enable RDP access to the VM by creating a NAT rule.

Details

In our scenario, we are creating one VM and the load balancer is forwarding Internet traffic to the VM by using an RDP NAT rule that maps an Azure public IP address to a private IP address.  The private IP address is on the Network Interface (NIC) card attached to the VM.

Consequently, no Load Balancing rules are created or used – only a NAT rule – to allow RDP into the VM.

Please notice that the script below creates a second data disk on the VM (because the VM is to be a Domain Controller).  You can easily remove the code for the second disk if it is not needed.

break

Login-AzureRmAccount
Get-AzureRmSubscription
Select-AzureRmSubscription -SubscriptionId <your subscription ID>

#################################################
# Create Resource Group - or use an existing one
#################################################
$loc = 'westeurope'
$rgName = 'RG-ASRConfigServer'
New-AzureRmResourceGroup -Name $rgname -Location $loc -Force

# Create a storage account
$stoName = 'storasrconsrvr4'
$stoType = 'Standard_LRS'
$naResult = Get-AzureRmStorageAccountNameAvailability $stoName

if ($naResult.NameAvailable) {
New-AzureRmStorageAccount -ResourceGroupName $rgName -Name $stoName `
                          -Location $loc -SkuName $stotype -Kind Storage
}
else { # The LoadBalancer is not used to create Load Balancing rules
# But to create NAT rules (to allow RDP from the Internet)
 Write-Host ''
 Write-Host -ForegroundColor Yellow "This storage account name: $stoName is not available"
 break
}
$storageAccount = Get-AzureRmStorageAccount -ResourceGroupName $rgName -Name $stoName

###############################
# Set up networking for the VM
###############################
# Create VNet and Subnet(s) - if needed
$beSubnetName = 'LB-SUBNET-BE'
$backendSubnet = New-AzureRmVirtualNetworkSubnetConfig -Name $beSubnetName `
                                                        -AddressPrefix '10.0.0.0/24'
$vnetName = 'vnetConfserv'
$vnet = New-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgname `
                                  -Location $loc -AddressPrefix '10.0.0.0/16' `
                                  -Subnet $backendSubnet 

#Create Public IP address 
#########################
$ipName = 'confservPublicIP'
$locName = 'West Europe'
$domainName = 'asrconfig'
$pip = New-AzureRmPublicIpAddress -Name $ipName -ResourceGroupName $rgName `
                                  -Location $locName -AllocationMethod Dynamic `
                                  -DomainNameLabel $domainName

#Create a front-end IP address pool tied to the Public IP address
#################################################################
$frontendIP = New-AzureRmLoadBalancerFrontendIpConfig -Name 'LB-FrontendIP' `
                                                      -PublicIpAddress $pip

#Create a back-end IP address pool that will be tied to the NIC
###############################################################
$backendAP = New-AzureRmLoadBalancerBackendAddressPoolConfig -Name 'LB-BackendAP'

#Create an Inbound NAT rule for Remote Desktop
##############################################
$natRuleRDP = New-AzureRmLoadBalancerInboundNatRuleConfig -Name 'natRuleRDP' `
                            -FrontendIpConfiguration $frontendIP -Protocol TCP `
                            -FrontendPort 3442 -BackendPort 3389 

#Create the external Load Balancer
##################################
$lbName = 'vmLoadBalancer'
$loadBal = New-AzureRmLoadBalancer -ResourceGroupName $rgName -Name $lbName `
                               -Location 'West Europe' -FrontendIpConfiguration $frontendIP `
                               -InboundNatRule $natRuleRDP -BackendAddressPool $backendAP

# Attach backend address pool to load balancer                                 
Add-AzureRmLoadBalancerBackendAddressPoolConfig -Name $backendAP -LoadBalancer $loadBal | `
                                                Set-AzureRmLoadBalancer
                                                     
#Create the Network Interface
#############################

$vnet1 = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
$backendSubnet1 = Get-AzureRmVirtualNetworkSubnetConfig -Name $beSubnetName -VirtualNetwork $vnet1
$nicName = 'vmNIC'
$vmNIC = New-AzureRmNetworkInterface -ResourceGroupName $rgName -Name $nicName `
                             -Location $locName -PrivateIpAddress '10.0.0.4' `
                             -Subnet $backendSubnet1 `
                             -LoadBalancerBackendAddressPool $loadBal.BackendAddressPools[0] `
                             -LoadBalancerInboundNatRule $loadBal.InboundNatRules[0]

##############################################
#Create the VM
##############################################
$vmName = 'vm-asrcsrvr'
$AvID = (New-AzureRmAvailabilitySet -ResourceGroupName $rgName `
                                    -Name 'adAvailabiltySet' -Location 'West Europe').id

#create a VM configuration
##########################
$vmObj = New-AzureRmVMConfig -VMName $vmName -VMSize 'Standard_A1' -AvailabilitySetId $AvID

$compName = 'vm-asrcsrvr'
$cred = Get-Credential -Message 'Enter name / password of VM administrator account.'
$vmObj = Set-AzureRmVMOperatingSystem -VM $vmObj -Windows -ComputerName $compName `
                                     -Credential $cred -ProvisionVMAgent `
                                     -EnableAutoUpdate

$vmObj = Set-AzureRmVMSourceImage -VM $vmObj -PublisherName MicrosoftWindowsServer `
                                 -Offer WindowsServer -Skus 2012-R2-Datacenter `
                                 -Version 'latest'

# Add the network interface (NIC) to the VM
###########################################
$vmObj = Add-AzureRmVMNetworkInterface -VM $vmObj -Id $vmNIC.Id

# ADD OS Disk and Data Disk
###########################
$blobPath = 'vhds/spfarm-ad-osdisk.vhd'
$osDiskUri = $storageAccount.PrimaryEndpoints.Blob.ToString() + $blobPath

$diskName = 'adVmOSDisk'
$vmObj = Set-AzureRmVMOSDisk -VM $vmObj -Name $diskName -VhdUri $osDiskUri `
                            -CreateOption fromImage -DiskSizeInGB 1000

# Add data disks by using the URLs of the copied data VHDs at the appropriate 
#  Logical Unit Number (Lun).
$dataDiskBlobPath = 'vhds/ADDataDisk-1.vhd'
$dataDiskUri = $storageAccount.PrimaryEndpoints.Blob.ToString() + $dataDiskBlobPath

# AD DC in Azure need the data disk storing sysvol to have NO caching
$vmObj = Add-AzureRmVMDataDisk -VM $vmObj -Name 'ADDataDisk-1' -Caching None `
                            -VhdUri $dataDiskUri -Lun 0 -DiskSizeInGB 1000 `
                            -CreateOption empty

# Create the actual VM
New-AzureRmVM -ResourceGroupName $rgName -Location $locName -VM $vmObj

######################
####Post VM Creation:
######################

# Add the network interface (NIC) to the load balancer
######################################################

$lb = Get-AzureRmLoadBalancer -Name $lbName -ResourceGroupName $rgName
$backend = Get-AzureRmLoadBalancerBackendAddressPoolConfig -Name $backendAP `
                                                           -LoadBalancer $lb
$nic = Get-AzureRmNetworkInterface -Name $nicName -ResourceGroupName $rgName
$nic.IpConfigurations[0].LoadBalancerBackendAddressPools = $backend
Set-AzureRmNetworkInterface -NetworkInterface $nic



Lessons Learned

1. If $backendSubnet is used instead of $backendSubnet1 and Error is produced: “Parameter set cannot be resolved using the specified named parameters” OR “Cannot parse the request”.

2. The Backend Address pool will contain the objects (IPs) targeted by the Load Balancer. If you want to redirect via NAT, The VM’s NIC should be part of the backend pool.  Therefore, you need to associate the Backend AddressPool with the IP address of the VM (held in the NIC).  This needs to be done after the VM is created.