Author Archives: mwasham

Setting Static IP addresses in a Microsoft Azure Virtual Network with PowerShell

I have finally had a chance to update the Windows Microsoft Azure PowerShell Guide.

The page is about the new functionality of assigning a static IP address to a virtual machine deployed in a Virtual Network.

Setting Static IP Address on Microsoft Azure Virtual Machine

Copy a Windows Azure Virtual Machine Between Subscriptions

While working on some recent training content focused on development and test with Windows Azure Rick Rainey and I thought a great scenario would be to have a script that can copy a single Windows Azure Virtual Machine from a source subscription to a destination subscription. This script will also copy a virtual machine between data center locations. There are tons of scenarios where this can be useful for dev/test so I will not enumerate them all here :)

Using the Script

This script uses the Windows Azure PowerShell cmdlets so they must be installed prior to use. Also, both the source and destination subscription must be configured for PowerShell access prior to use. See the following for information on getting started with the Windows Azure PowerShell Cmdlets.

  # Copy a virtual machine to a different subscription (no VNET)
  .\vmcopy.ps1 -SourceSubscription "source subscription" ` 
             -DestinationSubscription "destination subscription" ` 
             -VirtualMachineName "existingvmname" ` 
             -SourceServiceName "sourcecloudservice" ` 
             -DestinationServiceName "destinationcloudservice" ` 
             -DestinationStorageAccount "destinationstorageaccount" ` 
             -Location "West US" 
  # Copy a virtual machine to a different subscription and specify an existing virtual network and subnet. 
  .\vmcopy.ps1 -SourceSubscription "source subscription" ` 
               -DestinationSubscription "destination subscription" ` 
               -VirtualMachineName "existingvmname" ` 
               -SourceServiceName "sourcecloudservice" ` 
               -DestinationServiceName "destinationcloudservice" ` 
               -DestinationStorageAccount "destinationstorageaccount" ` 
               -VNETName "DestinationVNET" ` 
               -SubnetName "DestinationSubnet"

The script can be downloaded from within the TechNet Script Center: Virtual Machine Copy Script.

If you find any issues with the script or would just like to make it better we have it posted in GitHub as well: GitHub – Virtual Machine Copy Script and are interested in pull requests for improvements.

Of course, if you would like deeper training on Windows Azure to learn how to write scripts like this yourself we would be happy to help :)

New Windows Azure IaaS Training Courses Available

With the new year upon us we figured it would be a great time to announce new courses! We have recently added two new Windows Azure Infrastructure as a Service based courses that are immediately available for a dedicated onsite or remote class room style delivery.

Each course is two days in length, complete with hands on labs and a thorough introduction to Windows Azure Infrastructure Services (Virtual Machines and Virtual Networks). They are designed as “Jump Start” courses; meaning that they can quickly get students up to speed and proficient with the technology in a very short time period.

Windows Azure Training

Questions about the courses? Give us a call at: 866-833-3878 or email at

Windows Azure – Disk Cleanup with Virtual Machines

In the latest Windows Azure Portal and PowerShell updates Microsoft has added some great functionality to manage disk cleanup with virtual machines.

Prior to these updates managing the cleanup of virtual machine disks was fairly painful. You either had to delete each disk one by one from the portal or use PowerShell code with some complex filtering and polling mechanism to remove them.

Deleting an Individual Virtual Machine and Disks from the Portal

In the portal when you select an individual virtual machine and on the bottom of the screen select Delete you are given two new options.

  • Keep the attached disks (doesn’t delete any disks)
  • Delete the attached disks (deletes all attached disks OS and Data)

delete vm windows azure portal

Deleting an Individual Virtual Machine and Disks from PowerShell

The equivelant functionality for the “Delete the attached disks” option from PowerShell is to append the -DeleteVHD parameter onto a call to Remove-AzureVM.

  Remove-AzureVM -ServiceName $serviceName -Name $vmName -DeleteVHD

Deleting all Virtual Machines and Disks in a Cloud Service from the Portal

If you need to remove all of the virtual machines and underlying disks in a specific cloud service you are covered too.
In the portal simply click CLOUD SERVICES on the left menu and find the cloud service hosting your virtual machines.

In the portal select a cloud service that contains virtual machines and on the bottom of the screen select Delete you are given three options.

  • Delete the cloud service and its deployments (deletes cloud service, all of the virtual machines (in the cloud service) and all disks attached to the virtual machines)
  • Delete all virtual machines (deletes all of the virtual machines (in the cloud service) but retains the disks)
  • Delete all virtual machines and attached disks (deletes all of the virtual machines in the cloud service and all of the disks but does not delete the cloud service)

portal delete cloud service and disks

To accomplish each of the tasks from PowerShell is straightforward.

Delete the cloud service and its deployments – equivalent PowerShell Code

Remove-AzureService -ServiceName $serviceName -DeleteAll

Delete all virtual machines (but not the cloud service or disks)

Remove-AzureDeployment -ServiceName $serviceName -Slot Production

Delete all virtual machines and attached disks (but not the cloud service)

Remove-AzureDeployment -ServiceName $serviceName -Slot Production -DeleteVHD

PowerShell for the rest
Finally, if you need to clean up disks that are no longer attached to virtual machines the PowerShell cmdlets come to the rescue.

Get-AzureDisk | where { $_.AttachedTo -eq $null } | select diskname, medialink

To delete an individual disk.

Remove-AzureDisk "disk name" -DeleteVHD

If you want to delete all of the disks that are not attached (be careful of this one – ensure you know what you are deleting before executing!).

Get-AzureDisk | where { $_.AttachedTo -eq $null } | Remove-AzureDisk -DeleteVHD

The ease of use of Windows Azure is getting better every day. What used to be a complex task (deleting disks after VM deletion) is now simplified without taking away the power that is available to the command line user. The Windows Azure team(s) are doing an amazingly good job of tackling tasks that were once difficult and making them much more manageable.

Bootstrapping a PowerShell DSC Pull Server and Client

Script Sample

This post describes a set of PowerShell scripts that can automatically provision a PowerShell DSC Pull Server and Client using Windows Azure Virtual Machines.

The scripts can be downloaded from here: Bootstrap PowerShell DSC in Windows Azure.
If you find bugs feel free to fork, fix and submit a pull request.

Before continuing

If you are brand new to Windows PowerShell DSC I recommend a slight detour from this post to watch the TechEd 2013 Introductory Session. Once you watch the TechEd session you should then read this blog post on how to configure a DSC Pull Server: Push and Pull Configuration Modes.

Ok, I feel better. You now should not only know what a DSC pull server is but you will likely appreciate the script more because it takes all of the complexity of putting together a DSC Pull Server and Client and wraps it up in two simple scripts. Not that I am saying you shouldn’t know how to do this on your own but if you need to quickly spin up an environment for a demo, testing or whatever it is nice not to have to reconstruct an environment from scratch each time.


The scripts have a dependency on the Windows Azure PowerShell Cmdlets. So read this article to configure them if you haven’t already.

Creating a Pull Server

$subscription = "opsgilitytraining"
$serviceName = "mypullsvc"
$vmNamePull = "pullsrv"
$vmSize = "Small" 
$Location = "West US"
.\create-pull-srv.ps1 -SubscriptionName $subscription `
   -ServiceName $serviceName -Name $vmNamePull -Size $vmSize `
    -Location $location

What the script does:

  • Provisions a Server 2012 R2 VM in the “mypullsvc” cloud service in the West US data center. The VM name is “pullsrv”.
  • Creates a self-signed SSL certificate that is used to connect to the pull server and for encrypting stored passwords and automatically deploys it to the new virtual machine.
  • Uploads and executes the DSC Pull Server resource provider written by the PowerShell team.
  • Uploads a file that contains a helper function called SetConfiguration. This helper executes your DSC configuration file, generates a deterministic GUID based on the configuration name (so you don’t have to have a table of GUIDs handy) and creates the .mof files + checksums. Basically, all of the nasty work to create a DSC configuration in a pull server environment.
  • Once the server is provisioned login to the Pull Server via RDP.

    # if you don't want to leave your PowerShell session
    Get-AzureRemoteDesktopFile -ServiceName $serviceName -Name $vmNamePull -Launch

    Open the example configuration file C:\DSCScript\WebServer.ps1 in PowerShell_ISE and Hit F5. This will create your first bare bones configuration named WebServer on the pull server.

    Creating a Pull Client

    Note: The scripts have been designed to only allow deploying the client into the same cloud service as the pull server

    $vmNameClient = "pullclient"
    $configName = "WebServer"
    .\create-pull-client.ps1 -SubscriptionName $subscription `
       -ServiceName $serviceName -Name $vmNameClient -Size $vmSize `
       -CertificatePath .\PSDSCPullServerCert.pfx -PullServer $vmNamePull `
       -ConfigurationName $configName

    What the script does:

    • Provisions a Server 2012 R2 VM in the “mypullsvc” cloud service in the West US data center. The VM name is “pullclient”.
    • Deploys the previously created certificate PSDSCPullServerCert.pfx and also adds this cert to the LocalMachine\Root (trusted root authority) so it can be used with SSL.
    • Configures the client to point to the pull server using the DSC configuration name specified in -Configuration. The pull server has an example WebServer configuration that simply installs IIS that can be specified here.

    Testing the configuration

    Once the server is provisioned login to the Pull Client via RDP.

    # if you don't want to leave your PowerShell session
    Get-AzureRemoteDesktopFile -ServiceName $serviceName -Name $vmNameClient -Launch

    After patiently waiting 30+ minutes the configuration should be downloaded to your client VM. To validate this launch PowerShell and run:


    If all goes well you should see the following:
    PowerShell DSC

    Forcing DSC Configuration
    As of now there is no DSC cmdlet to force the client to pull a configuration. However, DSC is setup using scheduled tasks so you can force the task to run which will have your client check to see if it is up to date and if not apply the configuration.

    Get-ScheduledTask "Consistency" | Start-ScheduledTask


    There you have it. Two simple scripts that can quickly get you up and running with PowerShell DSC.
    If you are interested in learning more about PowerShell DSC or Windows Azure in general for yourself or your organization we provide on-site or open enrollment Windows Azure and PowerShell Training.

Windows Azure Training

Introducing Opsgility – my new venture

Over the past few months a good friend of mine Rick Rainey and myself have discussed starting a business together. We both saw a huge need for solid technical training for organizations looking at Windows Azure as their cloud provider of choice. There were three primary reasons that convinced us to start a new business:

  • The first reason is we think Windows Azure is going to be a smashing success for Microsoft. I’ve talked to enough Microsoft customers to see which way the wind is blowing and with my experience on the Windows Azure engineering team I know how hard they work and how fast they can innovate. It is only going to get better!

  • The second reason is Windows Azure is evolving very fast and keeping up with the changes to create always up to date content requires a full time commitment to training. We think this is a very valuable service to customers and also think we are just the people to do it.

  • The third reason is no one else is doing it. If you are an organization that needs deep focused training for your IT Staff or Developers there are not many (if any) options out there. This is a tricky reason.. It could be the reason there is a lack of Windows Azure trainers is because there isn’t a market for it. We do not believe that for a second. We believe that we are on the bleeding edge of a huge opportunity!

It just happens that we both have deep expertise with Windows Azure and PowerShell and have been working closely with and on the platform for years. We both have a passion for training and public speaking so it seems like a no brainer to create our new company, Opsgility.

Opsgility, is a training company focused on Windows Azure and DevOps practices. We provide deep, immersive and hands-on training for Technology Leaders, IT Professionals and Developers. We deliver open enrollment training in areas all over the United States and we will likely start international open enrollment deliveries very soon. Additionally, we will provide onsite private training at your organization in the United States or abroad (tropical locations are a plus!).

If you are interested in Windows Azure or building DevOps into your organization skillsets and would like to learn more about our services please visit our website: or give us a call: 1-866-833-3878!

Click here to read Opsgility’s CTO and Co-founder Rick Rainey’s Announcement.

P.S. If you are a Windows Azure or PowerShell Expert and would like to help us teach the world about Windows Azure and DevOps shoot us an email:

Michael Washam
CEO and Co-Founder Opsgility

Updating SQL Server AlwaysOn IP in Windows Azure

When deploying SQL Server AlwaysOn Availability Groups into Windows Azure with the listener enabled the configuration can break if the public IP address of the cloud service the SQL VMs are deployed into changes.

Cloud Service IP

The IP address of the cloud service hosting your SQL VMs can change if you shut down all the SQL Nodes at the same time using the Portal or PowerShell (and not using the -StayProvisioned flag in Stop-AzureVM). If this happens you will no longer be able to connect to the SQL Server through the listener until it is updated with the new IP of the cloud service when the VMs are restarted. This is a very common scenario with Dev/Test and proof of concepts because you may spin up the SQL servers but need to shut them down when not in use.

To make this easier from a DevOps perspective I have written a PowerShell script and published it to the TechNet Script Center that will update the listener IP address to the current IP Address of the cloud service.

Using the Script

The script does use the Windows Azure PowerShell cmdlets for automation so ensure they are setup and configured first.

Install and configure the Windows Azure PowerShell Cmdlets

Next you will need to enable CredSSP authentication since the script automates the other SQL nodes from the primary.

Enable CredSSP on your client machine for delegation before executing the script.

enable-wsmancredssp -role client -delegatecomputer “*”

This command will fail if your client machine is connected to any networks defined as “Public network” in “Network and Sharing Center.” of if PowerShell remoting has not previously been enabled with Enable-PSRemoting.

Run GPEdit.msc You must also enable delegating of fresh credentials using group policy editor on your client machine. Computer Configuration -> Administrative Templates -> System -> Credentials Delegation and then change the state of “Allow Delegating Fresh Credentials with NTLM-only server authentication” to “Enabled.” Its default state will say, “Not configured.”

Enable CredSSP on the primary SQL Server Node

enable-wsmancredssp -role client -delegatecomputer "*"

Install the WinRM certificate for the primary SQL Node

Download the script from the TechNet Script center:

Install WinRM Certificate for Windows Azure VMs

Example that installs the WinRM certificate (this allows secure remote PowerShell to the SQL Server VM)

$subName = "my subscription"
$cloudService = "MySQLAOCloudService"
$vmName = "SQLAO-01"
.\InstallWinRMCertAzureVM.ps1 -SubscriptionName $subName -ServiceName $cloudService -Name $vmName

Update the SQL Always On Listener IP

Download the SQL AlwaysOn IP Update script from the TechNet script center:

Update SQL Server Always On Listener IP Address in Windows Azure

Example of using the script to update a SQL AlwaysOn Availability Group.
The UpdateSQLAlwaysOnVIP.ps1 script will get the current IP address of the cloud service. Log in to the first SQL Node (SQLAO-01), update the IP cluster resource IP address and restart the SQL Nodes.

$avgroup = "SQLAG"
$nodes = "SQLAO-01", "SQLAO-02", "SQLAO-03"
.\UpdateSQLAlwaysOnVIP.ps1 -SubscriptionName $subName -ServiceName $cloudService -AvailabilityGroupName $avgroup -Nodes $nodes

SQL Always On References

Calling the Windows Azure Management API from PowerShell

Most of the time using the Windows Azure PowerShell cmdlets will accomplish whatever task you need to automate. However, there are a few cases where directly calling the API directly is a necessity.

In this post I will walk through using the .NET HttpClient object to authenticate and call the Service Management API along with the real world example of creating a Dynamic Routing gateway (because it is not supported in the WA PowerShell cmdlets).

To authenticate to Windows Azure you need the Subscription ID and a management certificate. If you are using the Windows Azure PowerShell cmdlets you can use the built in subscription management cmdlets to pull this information.

 $sub = Get-AzureSubscription "my subscription" 
 $certificate = $sub.Certificate
 $subscriptionID = $sub.SubscriptionId

For API work my preference is to use the HttpClient class from .NET. So the next step is to create an instance of it and set it up to use the management certificate for authentication.

$handler = New-Object System.Net.Http.WebRequestHandler
# Add the management cert to the client certificates collection 
$httpClient = New-Object System.Net.Http.HttpClient($handler)
# Set the service management API version 
$httpClient.DefaultRequestHeaders.Add("x-ms-version", "2013-08-01")
# WA API only uses XML 
$mediaType = New-Object System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/xml")

Now that the HttpClient object is setup to use the management certificate you need to generate a request.

The simplest request is a GET request because any parameters are just passed in the query string.

# The URI to the API you want to call 
# List Services API:
$listServicesUri = "$subscriptionID/services/hostedservices"
# Call the API 
$listServicesTask = $httpClient.GetAsync($listServicesUri)
if($listServicesTask.Result.IsSuccessStatusCode -eq "True")
    # Get the results from the API as XML 
    [xml] $result = $listServicesTask.Result.Content.ReadAsStringAsync().Result
    foreach($svc in $result.HostedServices.HostedService)
        Write-Host $svc.ServiceName " "  $svc.HostedServiceProperties.Location 

However, if you need to do something more complex like creating a resource you can do that as well.

For example, the New-AzureVNETGateway cmdlet will create a new gateway for your virtual network but it was written prior to the introduction of Dynamic Routing gateways (and they have not been updated since…).
If you need to create a new virtual network with a dynamically routed gateway in an automated fashion calling the API is your only option.

$vnetName = "YOURVNETNAME"
# Create Gateway URI
$createGatewayUri = "$subscriptionID/services/networking/$vnetName/gateway"
# This is the POST payload that describes the gateway resource 
# Note the lower case g in <gatewayType - the documentation on MSDN is wrong here
$postBody = @"
<?xml version="1.0" encoding="utf-8"?>
<CreateGatewayParameters xmlns="">
Write-Host "Creating Gateway for VNET" -ForegroundColor Green
$content = New-Object System.Net.Http.StringContent($postBody, [System.Text.Encoding]::UTF8, "text/xml")        
# Add the POST payload to the call    
$postGatewayTask = $httpClient.PostAsync($createGatewayUri, $content)
# Check status for success and do cool things

So there you have it.. When the WA PowerShell cmdlets are behind the times you can quickly unblock with some direct API intervention.

Try out Server 2012 R2 RTM in Windows Azure

It was announced today that MSDN/TechNet subscribers can now download Server 2012 R2 and Windows 8.1 RTM.. Fantastic news if you have access to MSDN or TechNet :)

As of 9/9/2013 Server 2012 R2 RTM is not available as an image in Windows Azure. You can either wait for them to add it OR if you have access to the RTM bits you can add it yourself.

Step 1: Login to MSDN or TechNet and download the ISO

Step 2: Download the Convert-WindowsImage.ps1 PowerShell script to convert the ISO from MSDN/TechNet into a bootable VHD.

Step 3: Mount the ISO to your machine (double click it in Win8)

Step 4: Run the following to create the VHD:

 .\Convert-WindowsImage.ps1 -SourcePath "E:\sources\install.wim" -Edition ServerStandard -VHDPath D:\Server2012R2.VHD

Step 5: Use the Windows Azure PowerShell Cmdlets to Upload the VHD

Add-AzureVHD -Destination "https://<yourstorage>" -LocalFilePath "D:\Server2012R2.VHD" -NumberOfUploaderThreads 5

Step 6: Register as an image.

Add-AzureVMImage -ImageName "Server2012R2" -OS Windows  -MediaLocation "https://<yourstorage>"

Now, back in the portal or from PowerShell you can provision a new Server 2012 R2 VM from your very own custom image. My bet is the Windows Azure team will have an RTM Image of Server 2012 R2 in the Image Gallery and avoid the need for these steps but until then you can try out 2012 R2 in the cloud :)

Connecting Clouds – Creating a site-to-site Network with Amazon Web Services and Windows Azure

Connecting Windows Azure to Amazon AWS

In this post I will show how you can use a Windows Azure Virtual Network (VNET) to create a site to site IPsec tunnel to connect to a Virtual Private Cloud (VPC) hosted in Amazon Web Services (AWS). Using this setup you can literally have workloads in each cloud with full VM to VM connectivity over a secure IPsec tunnel. This scenario could easily be used for failover, backup or even migration between providers. The software VPN solution I chose for testing is Open Swan.

Creating a VPC in Amazon AWS

Starting on the Amazon side create a virtual private cloud (VPC) which is the equivalent to a virtual network in Windows Azure.

VPC Creation Wizard – Single Public Subnet with Internet Gateway


I’m choosing the address space for the Amazon VPC network.


Provision an EC2 instance that will be used to host Open Swan and be the Amazon side of the tunnel.

Launch Ubuntu 13.04 into the VPC Subnet


Specify the subnet of the VPC previously deployed and I would advise bumping up the instance size to Small from Micro.


Once the instance is created switch to the EC2 view and allocate a new Elastic IP. This will be the public IP address you will connect to the VM using SSH and the IP address your Windows Azure Virtual Network will connect to.

Click Yes Allocate on the new Elastic IP dialog.


Select the instance from the drop down and click Yes Associate.


Creating the Windows Azure Virtual Network

Before configuring the Open Swan service I need to create the other side of the network in Windows Azure. To establish the IPsec tunnel Open Swan needs the gateway IP address and authentication key which both from the Windows Azure Virtual Network.

Create a Windows Azure Virtual Network


Specify Data Center Location and VNET/Affinity Group Name


Check site-to-site VPN


Define the onsite network properties which in this case is the Amazon VPC Address Space and Elastic IP of the Open Swan Server


Define the Windows Azure Address Space. Ensure you add the Gateway Subnet.


Creating the Windows Azure Virtual Network Gateway

Once the Virtual Network is created open it and click create gateway -> and select static routing.


Once the gateway is created you can get the gateway IP address and the authentication key and configure Open Swan on the Amazon side.
You will need the gateway IP and the key on the Amazon side.


Configuring Open Swan in Amazon Web Services

Connect to the Open Swan VM

Switch to the instances view, select your instance and on the Actions menu click Connect.

Select Connect with a standalone SSH client.


Copy the SSH command (or use Putty using the instructions on the screen) to connect via SSH. I’m using the Windows SSH client that comes with GitBash for the record :)


Once connected install and configure Open Swan for the VPN solution on the Amazon side.

Installing Open Swan

  sudo apt-get install openswan

Select NO for installing a certificate since we will be using key based authentication.


The next steps require you to use a text editor to modify some configuration files. If you are rusty on using Linux editors like vi here is a handy cheat sheet: VI Cheat Sheet

Edit the ipsec.conf file

   cd /etc
   sudo vi ipsec.conf

Once open, enter edit mode by pressing: *i (in that order)

Replace the existing configuration with the following:

config setup
include /etc/ipsec.d/*.conf

Exit and save the file by pressing: : x (in that order)

Change to the ipsec.d directory and create a new file named amznazure.conf.

  cd ipsec.d
  sudo vi amznazure.conf

Contents of amznazure.conf

conn amznazure

Notes about the above configuration:

  • left= is the local IP address of the Open Swan Server
  • leftsubnet= is the local address space of the servers in the VPC
  • right= is the IP Address of the Windows Azure VNET Gateway (replace with your own)
  • rightsubnet= is the address space of the Windows Azure Virtual Network

Once you have specified the configuration you need to specify the authentication key.

  cd /etc  
  sudo vi ipec.secrets

Add a line to the file in the following format (do not add the [] brackets): [WINDOWS AZURE GATEWAY IP] : PSK "[WINDOWS AZURE GATEWAY KEY]"

Next, enable enable IP forwarding to the Open Swan VM:

sudo vi /etc/sysctl.conf

Then uncomment this line:


Apply the changed network setting.

sudo sysctl -p /etc/sysctl.conf

Next, disable source / destination checking on the Open Swan server.



Modify Security Groups to Allow Traffic from Windows Azure

In the Amazon management console select Security Groups and -> amzn-azure-group.

Add two custom UDP inbound rules – one for 500 and one for 4500 using the Windows Azure GW IP with /32 as the CIDR.


 sudo service ipsec restart

Windows Azure Virtual Network Connected to Amazon AWS Virtual Private Cloud


Configuring Routing

The reason the software VPN solution needs to be on the Amazon AWS side is because the AWS networking stack supports configuring routing tables where Windows Azure does not (yet I assume).

In the Amazon management console switch back to the VPC view and select route tables.

Select the route table associated with your VPC and add a new route to the (Windows Azure Network) and that routes traffic through the instance ID of the Open Swan Server.

Updating Route Information


Creating Instances to Test Connectivity

Create an instance in AWS on the VPC Subnet.


Launch an instance in Windows Azure on the Virtual Network created.


One both instances are up you will need to enable the ICMP rule on each VM to test out connectivity using PING.

Pinging an Azure VM from an Amazon VM over the IPsec Tunnel


Pinging an Amazon VM from an Azure VM over the IPsec Tunnel


That is it!

I can now deploy applications into Amazon AWS and Windows Azure and communicate between the two on a secure IPsec tunnel over the Internet.