Automation–Automating Hybrid Clouds with Windows Azure and PowerShell (Part 2): Public Cloud Environment Provisioning PowerShell Examples

Hello Again!

Time for Part 2 of the Automating Hybrid Clouds with Windows Azure and PowerShell blog series (find Part 1: Intro & TOC here).  And yes, this post actually has PowerShell Examples! But first, the list of what examples will be provided…


Public Cloud Environment Provisioning PowerShell Examples

As covered in the intro post of the blog series, the following is the list of high level concept commands that will be covered in this post:

High Level Concept Commands

  1. Establish Windows Azure Subscription Connection
  2. Create Windows Azure Affinity Group
  3. Create Windows Azure Cloud Service
  4. Create Windows Azure Storage Account
  5. Create Windows Azure Storage Container
  6. Upload “On-Prem” VHD to Windows Azure Storage Container
  7. Copy Windows Azure Blob
  8. Create Windows Azure VM Image
  9. Create Windows Azure VM

Pre-Requisites

Here is the short list of pre-requisites for this example solution:

  1. Windows Server
  2. A VHD file that meets the requirements to be uploaded to Windows Azure
    Also see: Converting Hyper-V .vhdx to .vhd file formats for use in Windows Azure
  3. Windows Azure PowerShell Module
    Direct Download Link: https://go.microsoft.com/?linkid=9811175&clcid=0x409

Establish Windows Azure Subscription Connection

Automation often requires “trust”, especially between two endpoints in any given process/scenario solution. This example is no exception. The connection between the “On-Prem” Windows Server and Windows Azure need to share a “trust”. For Windows Azure (and for this example), one of the most common ways to accomplish this is through “the certificate method” (outlined in this Windows Azure tutorial: How to install and configure Windows Azure PowerShell).

Basically, it leverages the following:

  • The Get-AzurePublishSettingsFile cmdlet opens a web page on the Windows Azure Management Portal, from which you can download the subscription information. The information is contained in a .publishsettings file.
  • The Import-AzurePublishSettingsFile imports the .publishsettings file for use by the module. This file includes a management certificate that has security credentials.

Example Script (with some instructional comments)

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 #0.0. Perform Prerequisite Setup Steps #0.1. Download latest Windows Azure PowerShell Module: https://go.microsoft.com/?linkid=9811175&clcid=0x409 #0.2. Execute: Get-AzurePublishSettingsFile; Save .publishsettings file locally Get-AzurePublishSettingsFile #0.3. Execute: Import-AzurePublishSettingsFile; reference local .publishsettings file $AzurePublishSettingsFile = "C:\Your_Local_Path\Your Windows Azure Subscription Name-MM-DD-YYYY-credentials.publishsettings" Import-AzurePublishSettingsFile -PublishSettingsFile $AzurePublishSettingsFile #0.4. Execute: Set-AzureSubscription and Select-AzureSubscription (and then, to verify Execute: Get-AzureSubscription) $AzureSubscriptionName = "Windows Azure MSDN - Visual Studio Ultimate" Set-AzureSubscription -SubscriptionName $AzureSubscriptionName Select-AzureSubscription -SubscriptionName $AzureSubscriptionName Get-AzureSubscription

Note I recommend running these commands individually (not all at once) by the groups above.

Execution Results

As part of this process, you will notice a new Management Certificate in the Windows Azure Portal:

image

If everything was successful, the Get-AzureSubscription results should look similar to this:

image


Connection Established – Moving On…

Now that we have established a good connection to Windows Azure, we can take care of the rest of the automated steps to build out the environment.

Reminder Obviously, there are other methods and concepts to be automated for Windows Azure - these are just the ones I chose for the examples in this blog series.

Setting up the Environment with a “Project Name”

There is one variable that impacts the entire script and resulting environment. This needs to be set first, and will be used throughout:

  • $ProjectName: This is the over-arching variable that will be used (in part or whole) throughout the example. Many other variables are set based on this value.
001 $ProjectName = "BCBDemo"

Note If you run this example all the way through as a test, you will see how pervasive this variable’s value actually is. Even if you just look through the “Execution Results” from each step it is apparent. This is for example purposes only. I wanted to simplify the scripts and number of variable inputs.


Create Windows Azure Affinity Group

First step for these examples is to create a Windows Azure Affinity Group within Windows Azure for the environment being built. There is one variable that you will want to consider updating to fit your environmental needs/requirements:

  • $AGLocation: The Location the Affinity Group for this Environment/Project is associated with.
001 002 003 004 005 006 007 008 009 010 011 012 $AGName = $ProjectName $AGLocation = "West US" $AGLocationDesc = "Affinity group for $ProjectName VMs" $AGLabel = "$AGLocation $ProjectName" $AzureAffinityGroup = Get-AzureAffinityGroup -Name $ProjectName -ErrorAction SilentlyContinue if(!$AzureAffinityGroup) { $AzureAffinityGroup = New-AzureAffinityGroup -Location $AGLocation -Name $ProjectName -Description $AGLocationDesc -Label $AGLabel } $AzureAffinityGroup

Note All variable values were chosen for this example only, and can be changed to fit your project needs.

Execution Results

image

image


Create Windows Azure Cloud Service

Next up, is to create a Windows Azure Cloud Service within Windows Azure for the environment being built. There are no new unique variables that require value updates.

001 002 003 004 005 006 007 008 009 010 $CloudServiceDesc = "Service for $ProjectName VMs" $CloudServiceLabel = "$ProjectName VMs" $AzureService = Get-AzureService -ServiceName $ProjectName -ErrorAction SilentlyContinue if(!$AzureService) { $AzureService = New-AzureService -AffinityGroup $AGName -ServiceName $ProjectName -Description $CloudServiceDesc -Label $CloudServiceLabel } Return $AzureService

Note This portion of the script depends on the previous two.

Execution Results

image

image


Create Windows Azure Storage Account

Next, is to create a Windows Azure Storage Account within Windows Azure for the environment being built. There are no new unique variables that require value updates.

001 002 003 004 005 006 007 008 009 010 011 $StorageAccountName = $ProjectName.ToLower() $StorageAccountDesc = "Storage account for $ProjectName VMs" $StorageAccountLabel = "$ProjectName Storage" $AzureStorageAccount = Get-AzureStorageAccount -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue if(!$AzureStorageAccount) { $AzureStorageAccount = New-AzureStorageAccount -AffinityGroup $AGName -StorageAccountName $StorageAccountName -Description $StorageAccountDesc -Label $StorageAccountLabel } $AzureStorageAccount

Note This portion of the script depends on the previous three.

Execution Results

image

image

 


Create Windows Azure Storage Container(s)

Next, is to create Two Windows Azure Storage Containers within Windows Azure for the environment being built. There are no new unique variables that require value updates.

Reason for Two Storage Containers

  • Storage Container #1: Generic VHD Storage Container – “On-Prem” VHD will be uploaded to this container
  • Storage Container #2: Project Specific Storage Container – Uploaded VHD will be copied here (this is the VHD that will be leveraged for the rest of the example)

Note Creation of two Storage Containers in this example was to ensure I always had a “known good” copy of the uploaded VHD/Blob.

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 #Ensure Storage Account is fully created - Sleep for 60 seconds Start-Sleep -Seconds 60 #Update the Azure Subscription Connection with the Storage Account #This makes it easier to connect to the storage account, without requiring the creation and usage of Storage Context $AzureStorageAccountName = $ProjectName.ToLower() Set-AzureSubscription -SubscriptionName $AzureSubscriptionName -CurrentStorageAccount $AzureStorageAccountName #Create Generic VHD Storage Container; VHD will be uploaded here $GenericStorageContainerName = "vhds" #Create Project Storage Container; VHD will be copied here $ProjectStorageContainerName = $ProjectName.ToLower() $StorageContainerNames = @($GenericStorageContainerName,$ProjectStorageContainerName) foreach ($StorageContainerName in $StorageContainerNames) { $AzureStorageContainer = Get-AzureStorageContainer -Name $StorageContainerName -ErrorAction SilentlyContinue if(!$AzureStorageContainer) { $AzureStorageContainer = New-AzureStorageContainer -Name $StorageContainerName } $AzureStorageContainer }

Note This portion of the script depends on the previous four.

Execution Results

image

image


Upload “On-Prem” VHD to Windows Azure Storage Container

Next, is to upload the “On-Prem” VHD to the Generic Windows Azure Storage Container within Windows Azure for the environment being built. This portion of PowerShell does require some customization, as it references the previously mentioned, “…VHD file that meets the requirements to be uploaded to Windows Azure”:

  • $SourceDiskName: The Name of the VHD (without .vhd extension) to be uploaded to the Generic Windows Azure Storage Container.
  • $SourceDiskPath: The Path of the VHD (without trailing "\") to be uploaded to the Generic Windows Azure Storage Container.
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 #Set Source VHD Info $SourceDiskName = "toWindowsAzure" $SourceDiskFileExt = "vhd" $SourceDiskPath = "D:\Drop\Azure\toAzure" $SourceVHDName = "{0}.{1}" -f $SourceDiskName,$SourceDiskFileExt $SourceVHDPath = "{0}\{1}" -f $SourceDiskPath,$SourceVHDName #Set Destination Blob Info $DesitnationVHDName = "{0}.{1}" -f $ProjectName,$SourceDiskFileExt $DestinationVHDPath = "https://{0}.blob.core.windows.net/{1}" -f $AzureStorageAccountName,$GenericStorageContainerName $DestinationBlobURI = "{0}/{1}" -f $DestinationVHDPath,$DesitnationVHDName $OverWrite = $false #Upload Local VHD to the Generic VHD Windows Azure Storage Container; this will take a while $AzureBlob = Get-AzureStorageBlob -Container $GenericStorageContainerName -Blob $DesitnationVHDName -ErrorAction SilentlyContinue if(!$AzureBlob -or $OverWrite) { $AzureBlob = Add-AzureVhd -LocalFilePath $SourceVHDPath -Destination $DestinationBlobURI -OverWrite:$OverWrite } $AzureBlob

Note This portion of the script depends on the previous five.

The following is an image (not that it is really needed, but for proof) , of the file and path of the VHD I am uploading in this example:

image

Execution Results

Because this step takes a while, when you run the example PowerShell above, you have the opportunity to see the ongoing status within the PowerShell console. Here is a screenshot of the process, mid-execution:

image

Note Over a fast connection, a file of this size (7.5GB) takes about 10 minutes to upload (as seen in the results below).

image

image


Copy Windows Azure Blob

Next, is to copy the uploaded VHD (now a Windows Azure Blob) from the Generic Container (vhds) to the Project Specific Container within Windows Azure for the environment being built. There are no new unique variables that require value updates.

Note Usage of two Storage Containers in this example was to ensure I always had a “known good” copy of the uploaded VHD/Blob.

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 #Set Source Blob Info for Copy $SourceBlobName = $DesitnationVHDName $SourceContainer = $GenericStorageContainerName #Set Destination Blob Info for Copy $DestinationContainer = $ProjectStorageContainerName $DestinationBlobName = "{0}_copy.{1}" -f $ProjectName,$SourceDiskFileExt $CopiedAzureBlob = Get-AzureStorageBlob -Container $DestinationContainer -Blob $DestinationBlobName -ErrorAction SilentlyContinue #Copy Uploaded Blob from Generic to Project if(!$CopiedAzureBlob) { $CopiedAzureBlob = Start-AzureStorageBlobCopy -DestContainer $DestinationContainer -SrcBlob $SourceBlobName -SrcContainer $SourceContainer -DestBlob $DestinationBlobName } Return $CopiedAzureBlob

Note This portion of the script depends on the previous six.

Execution Results

image

image


Create Windows Azure VM Image

Next, is to create an Azure VM Image from copied blob within Windows Azure for the environment being built. There are no new unique variables that require value updates as $VMImageOS likely will remain “Windows” for the VHDs uploaded.

001 002 003 004 005 006 007 008 009 010 011 012 013 014 $VMImageName = $ProjectName $VMImageBlobContainer = $DestinationContainer $VMImageBlobName = $DestinationBlobName $VMImageOS = "Windows" $AzureVMImage = Get-AzureVMImage -ImageName $VMImageName -ErrorAction SilentlyContinue if(!$AzureVMImage) { $AzureBlobMediaLocation = (Get-AzureStorageBlob -Container $VMImageBlobContainer -Blob $VMImageBlobName).ICloudBlob.Uri.AbsoluteUri $AzureVMImage = Add-AzureVMImage -ImageName $VMImageName -MediaLocation $AzureBlobMediaLocation -OS $VMImageOS } Return $AzureVMImage

Note This portion of the script depends on the previous seven.

Execution Results

image

image


Create Windows Azure VM

Next, (what we all have been waiting for!) is to create a Windows Azure VM from the Windows Azure VM Image within Windows Azure for the environment being built. This portion of PowerShell does require some customization:

  • $VMName: The Name of the VM being created – the example I show here is a simple numbering suffix. It is not a mask of any kind, but something that generates a sequencing integer could be created. If you are uploading a large number of VM to create Windows Azure VMs, you would likely be referencing VM Name (and most other things) from an external data source. Either way, it is up to you, this is just example naming.
  • $AdminUsername: The Name of the Admin User for initial login to the Windows Azure VM. This cannot be "Administrator".
  • $Password: The Password for the Admin User for initial login to the Windows Azure VM.
  • $Windows: The OS of Windows Azure VM. Again, this will likely remain “Windows” for the VHDs uploaded.
  • $VMInstanceSize: The VM Instance Size for the Windows Azure VM (options available, reference the following: Virtual Machine and Cloud Service Sizes for Windows Azure).
  • $WaitForBoot: The option to wait for the Windows Azure VM to finish "Provisioning" before releasing control back to the PowerShell console.
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 $VMName = "{0}-001" -f $ProjectName.ToLower() $ServiceName = $ProjectName $AdminUsername = "AdminUser" $VMImageName = $AzureVMImage.ImageName $Password = "Pass@word1" $Windows = $true $VMInstanceSize = "ExtraSmall" $WaitForBoot = $true $AzureVM = Get-AzureVM -Name $VMName -ServiceName $ServiceName -ErrorAction SilentlyContinue if(!$AzureVM -and $Windows) { $AzureVM = New-AzureQuickVM -AdminUsername $AdminUsername -ImageName $VMImageName -Password $Password ` -ServiceName $ServiceName -Windows:$Windows -InstanceSize $VMInstanceSize -Name $VMName -WaitForBoot:$WaitForBoot } Return $AzureVM

Note This portion of the script depends on the previous eight. Also, the method used to create the Windows Azure VM in this example was New-AzureQuickVM, there are other methods – Please see some examples below (after the "Putting it all together" section).

Execution Results

Because this step takes a while, you have the opportunity to see the ongoing status within the Windows Azure Portal. Here is a screenshot of the Windows Azure VM creation, mid-execution:

image

Note "Provisioning" durations vary.

image

image


Connecting to the Windows Azure VM

Once provisioned, it is simple to connect directly to the Windows Azure VM to test its contents.

Step 1: Select the Windows Azure VM, Click Connect

image

Step 2: When prompted, Open the RDP file that is presented

image

Step 3: When prompted, Enter the credentials you provided within the Create Windows Azure VM PowerShell Script

image

Step 4: Wait for the RDP Session to complete and connect you to the Windows Azure VM

image

Step 5: Use/Explore the Windows Azure VM

image

Note Obviously nothing was done to customize the network for this VM. Windows Azure Virtual Network was out of scope for this example. For more information, please refer to the following: Windows Azure Virtual Network Overview .


A Dashboard View of the created Windows Azure VM

image

image


Putting it all together

I realize this is more than “like 5 lines of PowerShell”. But in reality, if you had the Windows Azure environment already created, that number isn’t that far off. Either way, here are all the above PowerShell script portions, rolled up into one script example:

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 #0.0. Perform Prerequisite Setup Steps #0.1. Download latest Windows Azure PowerShell Module: https://go.microsoft.com/?linkid=9811175&clcid=0x409 #0.2. Execute: Get-AzurePublishSettingsFile; Save .publishsettings file locally Get-AzurePublishSettingsFile #0.3. Execute: Import-AzurePublishSettingsFile; reference local .publishsettings file $AzurePublishSettingsFile = "C:\Your_Local_Path\Your Windows Azure Subscription Name-MM-DD-YYYY-credentials.publishsettings" Import-AzurePublishSettingsFile -PublishSettingsFile $AzurePublishSettingsFile #0.4. Execute: Set-AzureSubscription and Select-AzureSubscription (and then, to verify Execute: Get-AzureSubscription) $AzureSubscriptionName = "Windows Azure MSDN - Visual Studio Ultimate" Set-AzureSubscription -SubscriptionName $AzureSubscriptionName Select-AzureSubscription -SubscriptionName $AzureSubscriptionName Get-AzureSubscription #1.0 Setting up the Environment with a “Project Name” $ProjectName = "BCBDemo" #2.0 Create Windows Azure Affinity Group $AGName = $ProjectName $AGLocation = "West US" $AGLocationDesc = "Affinity group for $ProjectName VMs" $AGLabel = "$AGLocation $ProjectName" $AzureAffinityGroup = Get-AzureAffinityGroup -Name $ProjectName -ErrorAction SilentlyContinue if(!$AzureAffinityGroup) { $AzureAffinityGroup = New-AzureAffinityGroup -Location $AGLocation -Name $ProjectName -Description $AGLocationDesc -Label $AGLabel } $AzureAffinityGroup #3.0 Create Windows Azure Cloud Service $CloudServiceDesc = "Service for $ProjectName VMs" $CloudServiceLabel = "$ProjectName VMs" $AzureService = Get-AzureService -ServiceName $ProjectName -ErrorAction SilentlyContinue if(!$AzureService) { $AzureService = New-AzureService -AffinityGroup $AGName -ServiceName $ProjectName -Description $CloudServiceDesc -Label $CloudServiceLabel } Return $AzureService #4.0 Create Windows Azure Storage Account $StorageAccountName = $ProjectName.ToLower() $StorageAccountDesc = "Storage account for $ProjectName VMs" $StorageAccountLabel = "$ProjectName Storage" $AzureStorageAccount = Get-AzureStorageAccount -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue if(!$AzureStorageAccount) { $AzureStorageAccount = New-AzureStorageAccount -AffinityGroup $AGName -StorageAccountName $StorageAccountName -Description $StorageAccountDesc -Label $StorageAccountLabel } $AzureStorageAccount #5.0 Create Windows Azure Storage Container(s) #Ensure Storage Account is fully created - Sleep for 60 seconds Start-Sleep -Seconds 60 #Update the Azure Subscription Connection with the Storage Account #This makes it easier to connect to the storage account, without requiring the creation and usage of Storage Context $AzureStorageAccountName = $ProjectName.ToLower() Set-AzureSubscription -SubscriptionName $AzureSubscriptionName -CurrentStorageAccount $AzureStorageAccountName #Create Generic VHD Storage Container; VHD will be uploaded here $GenericStorageContainerName = "vhds" #Create Project Storage Container; VHD will be copied here $ProjectStorageContainerName = $ProjectName.ToLower() $StorageContainerNames = @($GenericStorageContainerName,$ProjectStorageContainerName) foreach ($StorageContainerName in $StorageContainerNames) { $AzureStorageContainer = Get-AzureStorageContainer -Name $StorageContainerName -ErrorAction SilentlyContinue if(!$AzureStorageContainer) { $AzureStorageContainer = New-AzureStorageContainer -Name $StorageContainerName } $AzureStorageContainer } #6.0 Upload “On-Prem” VHD to Windows Azure Storage Container #Set Source VHD Info $SourceDiskName = "toWindowsAzure" $SourceDiskFileExt = "vhd" $SourceDiskPath = "D:\Drop\Azure\toAzure" $SourceVHDName = "{0}.{1}" -f $SourceDiskName,$SourceDiskFileExt $SourceVHDPath = "{0}\{1}" -f $SourceDiskPath,$SourceVHDName #Set Destination Blob Info $DesitnationVHDName = "{0}.{1}" -f $ProjectName,$SourceDiskFileExt $DestinationVHDPath = "https://{0}.blob.core.windows.net/{1}" -f $AzureStorageAccountName,$GenericStorageContainerName $DestinationBlobURI = "{0}/{1}" -f $DestinationVHDPath,$DesitnationVHDName $OverWrite = $false #Upload Local VHD to the Generic VHD Windows Azure Storage Container; this will take a while $AzureBlob = Get-AzureStorageBlob -Container $GenericStorageContainerName -Blob $DesitnationVHDName -ErrorAction SilentlyContinue if(!$AzureBlob -or $OverWrite) { $AzureBlob = Add-AzureVhd -LocalFilePath $SourceVHDPath -Destination $DestinationBlobURI -OverWrite:$OverWrite } $AzureBlob #7.0 Copy Windows Azure Blob #Set Source Blob Info for Copy $SourceBlobName = $DesitnationVHDName $SourceContainer = $GenericStorageContainerName #Set Destination Blob Info for Copy $DestinationContainer = $ProjectStorageContainerName $DestinationBlobName = "{0}_copy.{1}" -f $ProjectName,$SourceDiskFileExt $CopiedAzureBlob = Get-AzureStorageBlob -Container $DestinationContainer -Blob $DestinationBlobName -ErrorAction SilentlyContinue #Copy Uploaded Blob from Generic to Project if(!$CopiedAzureBlob) { $CopiedAzureBlob = Start-AzureStorageBlobCopy -DestContainer $DestinationContainer -SrcBlob $SourceBlobName -SrcContainer $SourceContainer -DestBlob $DestinationBlobName } Return $CopiedAzureBlob #8.0 Create Windows Azure VM Image $VMImageName = $ProjectName $VMImageBlobContainer = $DestinationContainer $VMImageBlobName = $DestinationBlobName $VMImageOS = "Windows" $AzureVMImage = Get-AzureVMImage -ImageName $VMImageName -ErrorAction SilentlyContinue if(!$AzureVMImage) { $AzureBlobMediaLocation = (Get-AzureStorageBlob -Container $VMImageBlobContainer -Blob $VMImageBlobName).ICloudBlob.Uri.AbsoluteUri $AzureVMImage = Add-AzureVMImage -ImageName $VMImageName -MediaLocation $AzureBlobMediaLocation -OS $VMImageOS } Return $AzureVMImage #9.0 Create Windows Azure VM $VMName = "{0}-001" -f $ProjectName.ToLower() $ServiceName = $ProjectName $AdminUsername = "AdminUser" $VMImageName = $AzureVMImage.ImageName $Password = "Pass@word1" $Windows = $true $VMInstanceSize = "ExtraSmall" $WaitForBoot = $true $AzureVM = Get-AzureVM -Name $VMName -ServiceName $ServiceName -ErrorAction SilentlyContinue if(!$AzureVM -and $Windows) { $AzureVM = New-AzureQuickVM -AdminUsername $AdminUsername -ImageName $VMImageName -Password $Password ` -ServiceName $ServiceName -Windows:$Windows -InstanceSize $VMInstanceSize -Name $VMName -WaitForBoot:$WaitForBoot } Return $AzureVM

Alternate Windows Azure VM Create Examples

Note As stated above, the method used to create the Windows Azure VM in this example was New-AzureQuickVM, there are other methods – Please see the following for a couple of those alternate methods.

001 002 003 004 005 006 007 008 009 010 #Alternate Windows Azure VM Create: Example #1 New-AzureVMConfig -DiskName $DiskName -InstanceSize $VMInstanceSize -Name $VMName | ` Add-AzureProvisioningConfig -AdminUsername $AdminUsername -Windows -Password $Password -ResetPasswordOnFirstLogon | ` New-AzureVM –ServiceName $ServiceName #Alternate Windows Azure VM Create: Example #2 $VMConfig = New-AzureVMConfig -Name $VMName -InstanceSize $VMInstanceSize -ImageName $VMImageName | ` Add-AzureProvisioningConfig -Windows -Password $Password -AdminUsername $AdminUsername New-AzureVM -ServiceName $ServiceName -VMs $VMConfig –WaitForBoot

Community Built Alternate Windows Azure VM Create Example!

I would like to take the time to share something that came from the MVP Community recently – Another Alternate Windows Azure VM Creation Example… (Thank you Christopher Keyaert!)

This example highlights the ability to create a Windows Azure VM from a Disk with a VNet and Subnet defined.

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 ######################################################## # Define Parameters ######################################################## $ProjectName = "TestProj" $SourceDiskFileExt = "vhd" $VMInstanceSize = "ExtraSmall" $VMImageOS = "Windows" $BlobName = "{0}_copy.{1}" -f $ProjectName,$SourceDiskFileExt $BlobContainer = $ProjectName.ToLower() $DiskName = "{0}-001" -f $ProjectName.ToLower() $DiskLabel = "BootDisk" $VNetSiteName = "VNetSiteName" $SubNetName = "SubnetName" $Windows = $true $ServiceName = $ProjectName $VMName = "{0}-001" -f $ProjectName.ToLower() ######################################################## # Add a new Disk to the Windows Azure Disk Repository ######################################################## $AzureBlobMediaLocation = (Get-AzureStorageBlob -Container $BlobContainer -Blob $BlobName).ICloudBlob.Uri.AbsoluteUri Add-AzureDisk -DiskName $DiskName -MediaLocation $AzureBlobMediaLocation -Label $DiskLabel -OS $VMImageOS ######################################################## # Get Windows Azure VNet and Subnet Information ######################################################## $AzureVNet = Get-AzureVNetSite | where {$_.Name -eq $VNetSiteName} $AzureSubNet = $AzureVNet.Subnets | where {$_.Name -eq $SubNetName} ######################################################## #Create Windows Azure VM from Disk with VNet and Subnet ######################################################## $AzureVM = Get-AzureVM -Name $VMName -ServiceName $ServiceName -ErrorAction SilentlyContinue if(!$AzureVM -and $Windows) { $VMConfig = New-AzureVMConfig -Name $VMName -InstanceSize $VMInstanceSize -DiskName $VMName | Set-AzureSubnet $AzureSubNet.Name New-AzureVM -ServiceName $ServiceName -VMs $VMConfig -VNetName $AzureVNet.Name –WaitForBoot } Return $AzureVM

Note This is an example that builds on the other scripts within this blog post. Be sure you have all pre-requisite steps completed before you attempt to implement this example.

Important If you attempt to create a new Windows Azure VM in an existing deployment with the above script you will likely get a warning like this:

image

Warning Text: WARNING: VNetName, DnsSettings, DeploymentLabel or DeploymentName Name can only be specified on new deployments.


Execution Results

image

image

image

Once again, a big Thanks to Christopher for expanding on what I published here and suggesting that I share it with the rest of the community!


Other Learnings

During the "Conversion" process from Orchestrator Runbooks to Windows PowerShell, I ran up against a few things that I had to figure out. Here are a two of those learnings (outside what you have seen above), for just in case:

Storage Context

Before I learned about Setting the Azure Subscription with a "Current Storage Account", I tried my hand at creating and leveraging a Storage Context. Once you have created a Storage Context, you can reference it and pass it as a variable to commands requiring some level of specificity when it comes to Windows Azure Storage. While I did not use Storage Context in the examples above, I figured I would give you some example PowerShell, if you decide that is the route you want to take:

001 002 003 004 005 #Get Azure Storage Key and Create New Azure Storage Context if(!$AzureStorageContext) { $AzureStorageKey = Get-AzureStorageKey -StorageAccountName $StorageAccountName $AzureStorageContext = New-AzureStorageContext -StorageAccountKey $AzureStorageKey.Primary -StorageAccountName $StorageAccountName }

References


Digging Deeper: Bad Request (400)

I ran into quite a few exceptions during the build out of this example solution. Needless to say, when the PowerShell screen turns red, frustration rises just a little bit (if not more than a little bit). The following command helped me dig deeper on some of the more vague errors being returned by the command failure exceptions:

001 002 003 #Read Full Error Stream from Failed [Windows Azure] Command $ErrorStream = New-Object System.IO.StreamReader($Error[0].Exception.InnerException.Response.GetResponseStream()) $ErrorStream.ReadToEnd()

Note While it will not work in all cases, and while it is very generic, I found that if this is run right after a "Bad Request (400)", the "InnerText" of the Exception helped tremendously with what was actually going on. I found this originally referenced here .

Exception Handling Improved?

To get some proof of this working, I attempted to recreate the scenario where I needed to use the above commands. In my attempt to reproduce the "Bad Request (400)", I was met with actually useful and accurate errors:

image

That’s it! If I have any more learnings, I will add them to the upcoming blog posts.


What’s next?

So, what’s next? On to increasing complexity – Part 3 of this blog series takes what we have in this post, and transports it to a new world – Windows PowerShell Workflow!


Automating Hybrid Clouds with Windows Azure and PowerShell - Blog Series - Table of Contents

I broke this “Automating Windows Azure” topic up into four posts – primarily to make it easier to reference externally (based on varied interest levels).

As promised, the following is the link to the TechNet Contribution and Download for the examples (from all parts of the blog series).


TechNet Contribution and Download

The download (Hybrid Cloud Automation Toolkit - Windows Azure and PowerShell.zip) includes the following (4) files:

  • Provision-WindowsAzureEnvironmentResources.ps1
  • Provision-WindowsAzureEnvironmentResources-Workflow.ps1
  • Deprovision-WindowsAzureEnvironmentResources.ps1
  • Provision-Deprovision-Extras.ps1

Download the Hybrid Cloud Automation Toolkit - Windows Azure and PowerShell from TechNet Gallery here:

BC-DLButtonDark


Thanks for checking out this blog series! For more information, tips/tricks, and example solutions for Automation within System Center, Windows Azure Pack, Windows Azure, etc., be sure to check out the other blog posts from Building Clouds in the Automation Track!

enJOY!