In my post on automating virtual machines I showed the basics for getting around and managing aspects of Windows Azure VMs. In this post I want to cover a few of the more complex scenarios such as connectivity between VMs, deploying into a virtual network and finally deploying a virtual machine automatically domain joined into an Active Directory Domain.
Connecting Virtual Machines
So far we have seen details on provisioning a single virtual machine. What happens if your application requires more than one VM? How to connect them? There are two options for connecting virtual machines. The first is to add multiple virtual machines to the same cloud service and the second is to provision each VM into the same virtual network. When machines are added to the same cloud service and are not within a virtual network they receive the benefits of being on the same network and receive built in name resolution with each other through Windows Azure provided DNS.

So how do you add two virtual machines to the same cloud service? When you create the first virtual machine using New-AzureVM or New-AzureQuickVM you are required to specify the -Location or -AffinityGroup parameter. When you specify either parameter it tells the cmdlets that you wish to create the cloud service at that time because the data center location can only be set on initial creation. To tell the cmdlets to create the VM in an existing cloud service you just omit the -Location/-AffinityGroup parameter.
Create a VM and a New Cloud Service (specify -Location/-AffinityGroup)
New-AzureVMConfig -ImageName $img -Name $vmn -InstanceSize Small | Add-AzureProvisioningConfig -Windows -Password $PWD | New-AzureVM -ServiceName $svc -Location $loc |
Create a VM and Adds to an Existing Cloud Service by (omit -Location/-AffinityGroup)
New-AzureVMConfig -ImageName $img -Name $vmn -InstanceSize Small | Add-AzureProvisioningConfig -Windows -Password $PWD | New-AzureVM -ServiceName $svc |
Connecting Virtual Machines with Windows Azure Virtual Networks
The second way of provisioning connected virtual machines is by using a Windows Azure Virtual Network. With a Windows Azure Virtual Network the network can span cloud services. This enables scenarios such as virtual machines (or web and worker roles) in different cloud services to be fully connected in the cloud.
How do you provision VMs into a VNET with PowerShell?
Just like the -Location parameter a VNET can only be specified when creating the first VM in a cloud service (note that the subnet for each VM can be set per VM on provisioning). Additionally, VNETs require that the cloud service be deployed into the same affinity group as the VNET was created in. The New-AzureVM cmdlet requires -AffinityGroup instead of -Location when deploying to a VNET.
Joining a Virtual Network at Provision Time
New-AzureVMConfig -ImageName $img -Name $vmn -InstanceSize Small | Add-AzureProvisioningConfig -Windows -Password $PWD | Set-AzureSubnet 'subnet' | New-AzureVM -ServiceName $svc -AffinityGroup 'myag' -VNetName 'VNET' |
Specifying DNS
One of the significant differences between deploying a virtual machine outside of a VNET and one within is inside of a VNET there is no Windows Azure Provided DNS for VM to VM name resolution. To provide for this you are allowed to specify DNS servers inside of the Virtual Network configuration. When deploying with PowerShell you also have the ability to specify DNS settings when you create the first VM. This is a very flexible approach because it allows you the ability to specify DNS at deployment time without the need to modify the underlying virtual network configuration.
Specifying DNS Server on Provisioning
In this example I am creating a DNS object that references a DNS server (10.1.1.4) and I specify it with New-AzureVM. All VMs created in this cloud service will inherit this DNS setting on boot.
$dns = New-AzureDns -Name 'onprem-dns' -IPAddress '10.1.1.4' New-AzureVMConfig -ImageName $img -Name $vmn -InstanceSize Small | Add-AzureProvisioningConfig -Windows -Password $PWD | Set-AzureSubnet 'subnet' | New-AzureVM -ServiceName $svc -AffinityGroup 'myag' -VNetName 'VNET' -DnsSettings $dns |
Deploying a Virtual Machine into an Active Directory Domain
With Windows Azure Virtual Machines it is entirely possible to have a full Active Directory environment in the cloud. AD can either be hosted on-premises with connectivity provided by a site-to-site VPN tunnel using Windows Azure Virtual Networks OR you can host an AD domain directly in the cloud.
Once AD connectivity is in place you can use the PowerShell cmdlets to automatically join a Windows Virtual Machine directly to an Active Directory domain at provision time. For AD domain join to work you must specify the DNS server IP address for your Active Directory domain.
In this example New-AzureDNS is used to specify the DNS for the VM to point to an AD DNS Server in the cloud (10.2.0.4) which itself has been configured to point to an on-premise AD server (192.168.1.6) in a previous deployment. Setting DNS at this level is also useful because any future VMs added to this cloud service will inherit the DNS setting.
$subnet = 'APPSubnet' $ou = 'OU=AzureVMs,DC=fabrikam,DC=com' $dom = 'fabrikam' $domjoin = 'fabrikam.com' $domuser = 'administrator' $domVM = New-AzureVMConfig -Name 'advm1' -InstanceSize Small -ImageName $image | Add-AzureProvisioningConfig -WindowsDomain -JoinDomain $domjoin -Domain $dom -DomainPassword $pass -Password $pass -DomainUserName $domuser -MachineObjectOU $ou | Set-AzureSubnet -SubnetNames $subnet $dns = New-AzureDns -Name 'clouddc-ad' -IPAddress '10.2.0.4' New-AzureVM -ServiceName 'app-cloudservice' -AffinityGroup 'ADAG' -VNetName 'HybridVNET' -DnsSettings $dns -VMs $domVM |

If you would like to try some of this out on your own I highly suggest the Windows Azure Training Kit as a starting point. There are many hands on labs including deploying Active Directory and connecting multiple virtual machines.
This example doesn’t work for me. “Create a VM and Adds to an Existing Cloud Service by (omit -Location/-AffinityGroup)” The New-AzureVM portion returns CurrentStorageAccount is not accessible. Get-AzureStorageAccount returns two accounts with a collection of information although different elements are blank (1st – StorageAccountDescription, Location, GeoSecondaryLocation, StatusOfPrimary; 2nd – AffinityGroup, GeoSecondaryLocation, StatusOfPrimary, StatusOfSecondary). The first account I created and can see in the Preview Portal GUI, the second storage account was deleted via that GUI yesterday.
Any thoughts or advice?
Hi Dan,
It’s a bit tricky but since each subscription can have multiple storage accounts we wanted to leave open the possibility of switching between them in the same script.
What that means is you have to tell PS up front which storage account you want to use with the current subscription.
The error above usually means you either don’t have a storage account associated with the subscription or the storage account that is associated isn’t part of the same subscription.
To analyze run:
Get-AzureSubscription -Current
This should show you the currently selected subscription and current storage account. Likely the current storage account is wrong.
To change:
Set-AzureSubscription -SubscriptionName subName -CurrentStorageAccount storageacct
Make sure that you only specify the storage account name (not the blob url).
Hope that helps!
Michael
Hello Mike,
Your analysis was spot on and your direction got the results. Thanks for the quick, on target reply!
Dan
Hi Mike,
I’m getting the below error message, help me to fix it
New-AzureVMConfig : Cannot validate argument on parameter ‘ImageName’. The argument is null or empty. Supply an argumen
t that is not null or empty and then try the command again.
At line:1 char:73
+ $domVM = New-AzureVMConfig -Name ‘EA-EX1′ -InstanceSize small -ImageName <<<< $image | Add-AzureProvisioningConfig -
WindowsDomain -JoinDomain $domjoin -Domain $dom -DomainPassword $pass -Password $pass -DomainUserName $domuser |Set-Azu
reSubnet -SubnetNames $subnet
+ CategoryInfo : InvalidData: (:) [New-AzureVMConfig], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.WindowsAzure.Management.ServiceManagement.Iaa
S.NewAzureVMConfigCommand
Hi Rajkumar,
Hmm.. the only time I’ve ever seen this error is when the $image variable you are passing isn’t populated. Can you verify?
Hi Michael,
first of all thx for the great post!
I’m currently trying to set up a VM from an image using Powershell and I seem to have a similar problem to Dan’s issue regarding the -CurrentStorageAccount.
Here is what I did:
1. Download PublishSettings stuff
2. Import-AzurePublishSettingsFile …dadada… (works fine)
3. Get-AzureService (works fine)
4. Get-AzureSubscription -SubscriptionName “MySubscription” OR Get-AzureSubscription -Current (SubscriptionId + Certificate is populated, but CurrentStorageAccount is blank!)
5. Set-AzureSubscription -SubscriptionName “MySubscription” -CurrentStorageAccount “MyStorageAccount”
6. Get-AzureSubscription -SubscriptionName “MySubscription” OR Get-AzureSubscription -Current (-> Now the CurrentStorageAccount is set correctly, but the IsDefault value is set to false and SubscriptionId + Certificate is blank!)
7. Get-AzureService (now obviously throws “You MUST specify a certificate” Error and I guess New-AzureVM will do the same)
This is the first time I’m working with powershell, so I’m not sure wether I missed something.
Thanks in advance!
Regards Adrian
Hi Adrian,
The Set-AzureSubscription cmdlet just configures the settings. To select which subscription to use you should call Select-AzureSubscription.
Probably more confusing then it needs to be
Hi Michael,
I’m also stuck at a similar step – whilst trying to create my VM, powershell throws these errors:
New-AzureVM: You MUST specify a certificate. Call Set-Azure Subscription and Select-AzureSubscription first.
and
New-AzureVM: Value cannot be null.
Any help would be appreciated,
Nick
Hi Nicholas,
I’ve only seen this when the certificate is not specified. Call Get-AzureSubscription and it should show you whether the cert is configured or not.
You can use Set-AzureSubscription to resolve.
I can’t get passed Step 3 – I have generated the file and imported the subscription, but I keep getting a you MUST have a certificate error. When I do a get-AzureSubscription -current command my certificate info is blank??
SubscriptionName : MCITPLOCAL
SubscriptionId :
Certificate :
ServiceEndpoint : https://management.core.windows.net/
SqlAzureServiceEndpoint :
CurrentStorageAccount : mcitplocaleast
IsDefault : False
It’s likely that the publishsettings file you imported had multiple subscriptions.
Try running:
Get-AzureSubscription
Which will list all available.
Once you see the one you want to use use:
Select-AzureSubscription ‘subscriptionname’
To set it to the correct context.
You can also use:
Set-AzureSubscription -DefaultSubscription ‘subscriptionname’
This will tell the cmdlets to use that subscription by default the next time you start a PowerShell session.
How can you enter multiple IP’s when using New-AzureDns? Or do I simply create $dns1 and $dns2 with New-AzureDns and then when creating the VM I pass both to the -DnsSettings. Any help would be appreciated
Hi Greg,
-DnsSettings can take multiple dns entries.
-DnsSettings $dns1,$dns2 etc..
Is there a way to apply DNS settings when adding a VM to an existing cloud service? I have a pair of DC’s setup in Azure and I have a cloud service with a bunch of compute VM’s for an application. If I want to add more VM’s to the compute cloud service I get the following error:
WARNING: VNetName, DnsSettings, DeploymentLabel or DeploymentName Name can only be specified on new deployments. The code I’m using is:
New-AzureVMConfig -Name $Agent -ImageName $nodeimage -InstanceSize $size -MediaLocation $vmStorageLocation |
Add-AzureProvisioningConfig -WindowsDomain -Password $dompwd -Domain $domain -DomainUserName $domuser -DomainPassword $dompwd -MachineObjectOU $advmou -JoinDomain $joindom |
Add-AzureDataDisk -CreateNew -DiskSizeInGB 50 -DiskLabel ‘temp00′ -LUN 0 |
Add-AzureDataDisk -CreateNew -DiskSizeInGB 50 -DiskLabel ‘temp01′ -LUN 1 |
Set-AzureSubnet $subnetName |
New-AzureVM -ServiceName $serviceName -VNetName $vnetname -DnsSettings $dns1,$dns2
There are no DNS servers setup on the VNET since the DC’s were in Azure. The machine is built but without the proper DNS setting the VM doesn’t join the domain. Any pointers on this would be appreciated.