Connecting Windows Azure Virtual Machines with PowerShell

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.

14 thoughts on “Connecting Windows Azure Virtual Machines with PowerShell

  1. Dan

    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?

    Reply
    1. Michael Washam

      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

      Reply
  2. Dan

    Hello Mike,

    Your analysis was spot on and your direction got the results. Thanks for the quick, on target reply!

    Dan

    Reply
  3. Rajkumar

    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

    Reply
  4. Adrian

    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

    Reply
    1. Michael Washam

      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 :)

      Reply
      1. Nicholas

        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

        Reply
        1. Michael Washam

          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.

          Reply
    2. Rich

      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

      Reply
      1. Michael Washam

        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.

        Reply
  5. gmatusko

    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

    Reply
  6. gmatusko

    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.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>