Upgrading Windows Azure Cloud Services to Server 2012 and .NET 4.5

In this post I’ll walk through the options for upgrading an existing Cloud Service using OS Family (1 or 2) to use Windows Server 2012 (OS Family 3) and .NET 4.5.

Traditionally, to upgrade a Cloud Service all that is required is to click the update button in the Windows Azure portal after uploading your updated package or publishing with Visual Studio. However, when changing OS Families from (1 or 2) to 3 you will receive the error saying “Upgrade from OS family 1 to OS family 3 is not allowed”. This is a temporary restriction on the update policy that we are working to remove in an upcoming release.

In the mean time there are two workarounds to updating your existing Windows Azure Cloud Service to run with .NET 4.5 and OS family 3 (Server 2012):

  • VIP Swap (recommended approach)
  • Delete and Re-deploy

Both have different pros/cons that are outlined in the table below. Detailed walkthroughs of both the options are provided below:

  PROS CONS
VIP Swap Fast and simple. Usual VIP swap restrictions apply.
Delete/Re-deploy Can make any change to the updated application. VIP swap restrictions do not apply. Loss of availability while the application is deleted and then redeployed. Potential change in the public IP address after the   redeployment.

Configuring Your Project for Upgrade

Step 1: Open the solution in Visual Studio.

In the example below the solution is named Sdk1dot7 and there are two projects. The first is an MVC Web Role project (MvcWebRole1) and the second is the Windows Azure Cloud Service project (Sdk1dot7).

csu1

Step 2: Upgrade the Project

Right click on the Cloud Service project  (Sdk1dot7) and select properties. Note in the picture below, the properties page shows that this project was built the June 2012 SP1 Windows Azure Tools version. Click the “Upgrade” button. After the upgrade, if you check this properties sheet again, it should show that the current Windows Azure Tools
version is October 2012.

csu2

Step 3: Open ServiceConfiguration.Cloud.cscfg: csu3

Change OSFamily from (1 or 2) to 3.

csu4

New Value: osFamily=”3″

Step 4: Modify the Web Role to use .NET 4.5

Open the properties sheet of the WebRole project by right-clicking the WebRole project and clicking on “Properties”.

csu5

In the “Application” tab look for the “Target framework” dropdown. It should show .NET 4.0.

csu6

Open the dropdown and select .NET 4.5. You’ll get a “Target Framework Change” dialog box, click “Yes” to proceed. The Target Framework should now read .NET 4.5.

Rebuild by hitting ‘F6’. You might get some build errors due to namespace clashes between some new libraries that have been introduced in .NET 4.5. These are easy enough to fix. If you cannot, feel free to add the comment and I’ll respond.

Deploying using VIP Swap

You can deploy from within Visual Studio or from the Windows Azure Portal. In this post, I’ll show the steps to deploy through the portal.

Step 1: Generate the .cspkg and .cscfg files for upload.

Right click on your Cloud Service project (Sdk1Dot7) and select Package:

csu6.5

After the packaging is complete, a file explorer window will open with the newly created .cspkg and .cscfg files for your Cloud Service.

Step 2: Uploading the Files to the Staging Slot using the Windows Azure Portal

Open the Windows Azure portal at https://manage.windowsazure.com and select your cloud service. Click on the “Staging” tab (circled in red in the accompanying picture below).

Once on the staging tab, click on the “Update” button on the bottom panel (circled in green in the accompanying picture below).

csu7

From there a dialog will open requesting the newly created files packaged from Visual Studio.

Select “From Local” button for both and upload  the files that were generated during packaging. Remember to check the “Update even if one or more roles contain single instance” if you have a single instance role. These options are circled in red in the picture below. Click on the check marked circle to proceed.

csu8

Step 3: Test the new deployment

At this point you will have your application running on OS family 3 and using .NET 4.5 in the staging slot and your original application using OS family 1/2 and .NET 4.0 in the production slot. Browse to the application by clicking the Site URL on the dashboard under the staging slot.

Step 4: Perform the VIP Swap to Production

On either the production or the staging tab, click on the “swap” button located in the bottom panel next to the update button (circled in green in the accompanying picture).

csu9

After this operation completes, you will have your application running on OS family 3 and using .NET 4.5 in place of the original application.

Deleting Your Deployment

The second option is to delete your deployment. This is not going to be the recommended approach for a production application because you will have downtime and there is a probability of losing the current IP address assigned to your VIP. This option is really only useful for dev/test where you do not want to go through the VIP swap life cycle or you are making changes to the cloud service that are restricted during an in-place upgrade using VIP swaps.

To delete your deployment open the Windows Azure portal at https://manage.windowsazure.com and select your cloud service. Click the “STOP” button in the bottom panel (circled in green in the accompanying picture). Click “yes” on the dialog box that pops up.

csu10

Once the service is deleted you can simply republish from Visual Studio or package and upload using Visual Studio + the management portal.

Migrate a Virtual Machine to Windows Azure with PowerShell

In my previous post I show how you can use the Add-AzureVHD cmdlet to upload a VHD. I wanted to take it a bit further and show how you can use this new cmdlet in conjunction with the other PowerShell cmdlets to migrate and provision an entire virtual machine.

The script below uploads two VHDs; one for the Operating System Disk and one for an additional data disk. Once the VHDs are uploaded it then creates the disk entities using the Add-AzureDisk cmdlet and then proceeds to construct the virtual machine using the newly uploaded VHDs.

# Retrieve with Get-AzureSubscription 
$subscriptionName = '[MY SUBSCRIPTION]'  

# Retreive with Get-AzureStorageAccount 
$storageAccountName = '[MY STORAGE ACCOUNT]'   

# Specify the storage account location to store the newly created VHDs 
Set-AzureSubscription -SubscriptionName $subscriptionName -CurrentStorageAccount $storageAccountName 
 
# Select the correct subscription (allows multiple subscription support) 
Select-AzureSubscription -SubscriptionName $subscriptionName 

# Retreive with Get-AzureLocation 
$location = 'West US' 

# ExtraSmall, Small, Medium, Large, ExtraLarge
$instanceSize = 'Medium' 

# Has to be a unique name. Verify with Test-AzureService
$serviceName = '[UNIQUE SERVICE NAME]' 

# Server Name
$vmname1 = '[MY VM NAME]'

# Source VHDs
$sourceosvhd = 'C:\MyVHDs\AppServer1OSDisk.vhd'
$sourcedatavhd = 'C:\MyVHDs\AppServer1DataDisk.vhd'

# Target Upload Location 
$destosvhd = 'http://' + $storageAccountName + '.blob.core.windows.net/uploads/AppServer1OSDisk.vhd'
$destdatavhd = 'http://' + $storageAccountName + '.blob.core.windows.net/uploads/AppServer1DataDisk.vhd'

Add-AzureVhd -LocalFilePath $sourceosvhd -Destination $destosvhd 
Add-AzureVhd -LocalFilePath $sourcedatavhd -Destination $destdatavhd

Add-AzureDisk -OS Windows -MediaLocation $destosvhd -DiskName 'AppServer1OSDisk'
Add-AzureDisk -MediaLocation $destdatavhd -DiskName 'AppServer1DataDisk'

$migratedVM = New-AzureVMConfig -Name $vmname1 -DiskName 'AppServer1OSDisk' -InstanceSize 'Medium' |
					Add-AzureDataDisk -Import -DiskName 'AppServer1DataDisk' -LUN 0 |
					Add-AzureEndpoint -Name 'Remote Desktop' -LocalPort 3389 -Protocol tcp 
					
New-AzureVM -ServiceName $serviceName -Location $location -VMs $migratedVM 					

New Windows Azure PowerShell Update – December 2012

The Windows Azure PowerShell team has just put out an update. Currently, downloadable from: GitHub.

The first one I want to call out because it is close to my IaaS focused heart is Add-AzureVhd.

If you have had the pleasure of uploading VHDs for IaaS before using CSUpload you know the old tool was pretty cumbersome.

Now uploading VHDs for onboarding virtual machines is simple(r).

In it’s simplest form you simply specify the local path to the VHD and the destination storage account URL:

Select-AzureSubscription 'mysubscription' 
Add-AzureVhd -LocalFilePath 'D:\VMStorage\SP2013VM1.vhd' -Destination 'http://mystorageaccount.blob.core.windows.net/uploads/SP2013VM1.vhd'

Once the upload has completed you can add the VHD to the disk repository by using the following command:

Add-AzureDisk -DiskName 'SP2013VM1OS' -MediaLocation 'http://mystorageaccount.blob.core.windows.net/uploads/SP2013VM1.vhd' -OS Windows

If you wanted to upload only a data disk just omit -OS Windows.
This cmdlet also supports uploading differencing disks to patch VHDs in storage as well. You can specify -BaseImageUriToPatch as the target VHD to apply the differencing disk too.

Once the disk is loaded to boot the virtual machine from the disk simply specify the disk name when configuring the VM.

uploaddisk

If you prefer to provision from PowerShell:

New-AzureVMConfig -DiskName 'SP2013VM1OS' -InstanceSize Medium -Name 'SP2013VM1' | 
	Set-AzureSubnet -SubnetNames 'AppSubnet' | 
	New-AzureVM -ServiceName 'sp2013svc1' -VNETName 'HybridVNET' -AffinityGroup 'WestUSAG'

One potential regression I do want to call out in the IaaS space is a change to Get-AzureVMImage

The below code formerly worked and now no longer returns a value..

# Previous functionality 
(Get-AzureVMImage)[1].ImageName # Returns a value
Get-AzureVMImage | Select ImageName # Returns value

If your scripts did something similar you will need to use

Get-AzureVMIMage | ft imagename 

Store the specific image in a variable for later use.

Another key set of additions to the Windows Azure PowerShell Cmdlets:

ServiceBus
We finally have the ability to directly manage ServiceBus Namespaces from the command line. From a dev-ops perspective this one is HUGE.

  • New-AzureSBNamespace – Create a new Windows Azure ServiceBus namespace
  • Get-AzureSBLocation – Get the Windows Azure regions that may be used to create new Windows Azure
  • Get-AzureSBNamespace – Get information about existing Windows Azure ServiceBus namespaces
  • Remove-AzureSBNamespace – Delete a WindowsAzure ServiceBus namespace and all associated objects

Complete list of the cmdlets in the December release:
(Note the Windows Azure SQL Database cmdlets made it back into the official release in November)

Add-AzureCacheWorkerRole
Add-AzureCertificate
Add-AzureDataDisk
Add-AzureDisk
Add-AzureDjangoWebRole
Add-AzureEndpoint
Add-AzureNodeWebRole
Add-AzureNodeWorkerRole
Add-AzurePHPWebRole
Add-AzurePHPWorkerRole
Add-AzureProvisioningConfig
Add-AzureVhd
Add-AzureVMImage
Disable-AzureServiceProjectRemoteDesktop
Enable-AzureMemcacheRole
Enable-AzureServiceProjectRemoteDesktop
Export-AzureVM
Get-AzureAffinityGroup
Get-AzureCertificate
Get-AzureDataDisk
Get-AzureDeployment
Get-AzureDisk
Get-AzureDns
Get-AzureEndpoint
Get-AzureLocation
Get-AzureOSDisk
Get-AzureOSVersion
Get-AzurePublishSettingsFile
Get-AzureRemoteDesktopFile
Get-AzureRole
Get-AzureSBLocation
Get-AzureSBNamespace
Get-AzureService
Get-AzureServiceProjectRoleRuntime
Get-AzureSqlDatabase
Get-AzureSqlDatabaseServer
Get-AzureSqlDatabaseServerFirewallRule
Get-AzureStorageAccount
Get-AzureStorageKey
Get-AzureSubnet
Get-AzureSubscription
Get-AzureVM
Get-AzureVMImage
Get-AzureVNetConfig
Get-AzureVNetConnection
Get-AzureVNetGateway
Get-AzureVNetGatewayKey
Get-AzureVNetSite
Get-AzureWebsite
Get-AzureWebsiteDeployment
Get-AzureWebsiteLocation
Import-AzurePublishSettingsFile
Import-AzureVM
Move-AzureDeployment
New-AzureAffinityGroup
New-AzureCertificateSetting
New-AzureDeployment
New-AzureDns
New-AzureQuickVM
New-AzureSBNamespace
New-AzureService
New-AzureServiceProject
New-AzureSqlDatabase
New-AzureSqlDatabaseServer
New-AzureSqlDatabaseServerContext
New-AzureSqlDatabaseServerFirewallRule
New-AzureSSHKey
New-AzureStorageAccount
New-AzureStorageKey
New-AzureVM
New-AzureVMConfig
New-AzureVNetGateway
New-AzureWebsite
Publish-AzureServiceProject
Remove-AzureAffinityGroup
Remove-AzureCertificate
Remove-AzureDataDisk
Remove-AzureDeployment
Remove-AzureDisk
Remove-AzureEndpoint
Remove-AzureSBNamespace
Remove-AzureService
Remove-AzureSqlDatabase
Remove-AzureSqlDatabaseServer
Remove-AzureSqlDatabaseServerFirewallRule
Remove-AzureStorageAccount
Remove-AzureSubscription
Remove-AzureVM
Remove-AzureVMImage
Remove-AzureVNetConfig
Remove-AzureVNetGateway
Remove-AzureWebsite
Reset-AzureRoleInstance
Restart-AzureVM
Restart-AzureWebsite
Restore-AzureWebsiteDeployment
Save-AzureVMImage
Save-AzureWebsiteLog
Select-AzureSubscription
Set-AzureAffinityGroup
Set-AzureDataDisk
Set-AzureDeployment
Set-AzureEndpoint
Set-AzureOSDisk
Set-AzureRole
Set-AzureService
Set-AzureServiceProject
Set-AzureServiceProjectRole
Set-AzureSqlDatabase
Set-AzureSqlDatabaseServer
Set-AzureSqlDatabaseServerFirewallRule
Set-AzureStorageAccount
Set-AzureSubnet
Set-AzureSubscription
Set-AzureVMSize
Set-AzureVNetConfig
Set-AzureVNetGateway
Set-AzureWalkUpgradeDomain
Set-AzureWebsite
Show-AzurePortal
Show-AzureWebsite
Start-AzureEmulator
Start-AzureService
Start-AzureVM
Start-AzureWebsite
Stop-AzureEmulator
Stop-AzureService
Stop-AzureVM
Stop-AzureWebsite
Test-AzureName
Update-AzureDisk
Update-AzureVM
Update-AzureVMImage

To download the latest bits:
Latest PowerShell Bits

To file an issue:
File a bug

Windows Azure IaaS Webcast Series Part Two: Virtual Machine Networking Basics

This is part two of the Windows Azure IaaS Webcast Series. This webcast discusses connecting virtual machines together in a cloud service for direct network connectivity and also shows the basics of configuring load balanced endpoints.

iaas-part-2

If you missed it click here for: Part One Getting Started with Windows Azure Virtual Machines

Windows Azure IaaS Webcast Series Part One – Getting Started with Virtual Machines

I’ve started a series of webcasts focused on Windows Azure Infrastructure as a Service. This series is targeted at new users to IaaS and starts from the basics with creating virtual machines. I plan on building many of these webcasts to cover the getting started scenarios to more advanced topics.

If you have any scenario requests shoot me an email at: mwasham@microsoft.com or Tweet me at MWashamMS!

iaas-part-1

Bootstrapping a Virtual Machine with Windows Azure

In my Advanced IaaS Talk at Build I showed a demo where you can configure a PowerShell script that can download a zip file with multiple actions (unzip or execute) that gives you similar functionality to a Windows Azure startup task for web and worker roles.

This is a very simple example but it does show some of the capabilities you can do.

The bootstrap.ps1 file below is the main script that is responsible for downloading the bootstrap.zip file from your storage account. You should create a directory called c:\BootStrap and place the script inside and reference it from the startup task on your virtual machine.

In this demonstration I am pulling from a public storage container. If you want to contain anything secure in your bootstrap.zip you should modify the url below to use a shared access signature..

bootstrap.ps1

cls

$rootpath = 'C:\BootStrap\'
$manifest = 'C:\BootStrap\Working\manifest.xml'
$workingdir = 'C:\BootStrap\Working\'
$downloaddir = 'C:\BootStrap\Working\config1.zip'
$packagesource = 'http://YOURSTORAGEACCOUNT.blob.core.windows.net/bootstrap/config1.zip'

function GetPayload()
{
    $retries = 5
	while($retries -gt 0)
	{
		CheckFolder $workingdir
	    try {
		    $wc = New-Object System.Net.WebClient
		    $wc.DownloadFile($packagesource, $downloaddir)
			break
	     } 
	     catch [System.Net.WebException] {
		    # $_ is set to the ErrorRecord of the exception
	        if ($_.Exception.InnerException) {
	     	   $_.Exception.InnerException.Message | Out-File c:\BootStrap\error.txt -Append
	        } else {
	           $_.Exception.Message | Out-File c:\BootStrap\error.txt -Append
	        }
			Start-Sleep -Seconds 15
			$retries = $retries - 1
	     }
	 }
     UnzipFileTo $downloaddir $workingdir
}

function BootStrapVM()
{
  if((Test-Path HKLM:\Software\VMBootStrap) -eq $true)
  {
     Write-Host "Already Ran"
	 return
  }

  [xml] $manifest = Get-Content $manifest
  $counter = 0
  $manifest.StartupManifest.Items.Item | foreach { 
	$action = $_.action 
	$path = $_."#text"
	$target = $_.target 
	$sourcefullpath = $workingdir + $path
	
	switch($action)
	{
	   "execute" {
		  Write-Host "Executing command: " $sourcefullpath
		  ExecuteCommand $sourcefullpath
	   }
	   "unzip" {
		  $sourcefullpath = $workingdir + $path
		  Write-Host "Unzipping " $sourcefullpath " to " $target 
	      UnzipFileTo $sourcefullpath $target
	   }
	   
	}
	 
  }
  New-Item -Path HKLM:\Software -Name VMBootStrap –Force | Out-Null
  Set-Item -Path HKLM:\Software\VMBootStrap -Value "ran" | Out-Null
}

function ExecuteCommand($commandpath)
{
	& $commandpath
}

function UnzipFileTo($sourcepath, $destinationpath)
{
	CheckFolder $destinationpath
	$shell_app = new-object -com shell.application
	$zip_file = $shell_app.namespace($sourcepath)
	$destination = $shell_app.namespace($destinationpath)
	$destination.Copyhere($zip_file.items(), 16)
}

function CheckFolder($path)
{
	if((Test-Path $path) -eq $false)
	{
   		New-Item -ItemType directory -Path $path -Force | Out-Null
	}
}
GetPayload
BootStrapVM

Here are two sample configs I put together:

config1.zip Enables Remote PowerShell

http://mwweststorage.blob.core.windows.net/bootstrapblog/config1.zip

config2.zip Installs IIS, WebPI, MySQL and WordPress

http://mwweststorage.blob.core.windows.net/bootstrapblog/config2.zip

The config1.zip file contains a manifest.xml file and all of the entities you need to upload.

Example of the manifest.xml section of the config2.zip

 <StartupManifest>
   <Items>
     <Item action="execute">InstallRoles\ConfigureRoles.ps1</Item>
     <Item action="unzip" target="c:\webpi\">WebPI\WebpiCmd.zip</Item>
     <Item action="execute">InstallPackages\EnableWebPI.cmd</Item>
   </Items>
 </StartupManifest>

All that is needed to configure the script to run when your VM boots is to configure a startup task using group policy.

Run: mmc
File -> Add/Remove Snapin
Select -> Group Policy Object Editor (Local Computer)
Expand -> Computer Configuration -> Windows Settings -> Scripts Startup/Shutdown

Once the script is configured you will need to change the execution policy on the virtual machine before you run sysprep and capture on your image otherwise the script will not execute on the next boot.

 Set-ExecutionPolicy RemoteSigned

Finally, if you do enable to the remote PowerShell task here is the command line you can use to connect.

Enter-PSSession -ComputerName {hostname}.cloudapp.net -Authentication Basic -Credential Administrator -UseSSL -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck)