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

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

  • Comments 7
  • Likes

Hi. :)

At this point, you know the drill…This is Part 3 of the Automating Hybrid Clouds with Windows Azure and PowerShell blog series – which is kind of the same thing as Part 2, but this time the deliverable is a set of PowerShell Workflow Examples.

For reference, here is Part 1 (Intro & TOC), and here is Part 2 (Public Cloud Environment Provisioning PowerShell Examples).

Let’s get to it.


Public Cloud Environment Provisioning PowerShell Workflow Examples

As covered in Parts 1 and 2 of this 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 (Please Reference Part 2 for details)
  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

These are the same as they were in Part 2, but again for reference, 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: http://go.microsoft.com/?linkid=9811175&clcid=0x409

Okay, there are three new pre-requisites for this post:

  1. An Established Windows Azure Subscription Connection (Please Reference Part 2 for details).
    Note     This portion of the script will be included in the overall script at the end of the post, just not covered separately here at the top.
  2. The Workflows that contain all the commands previously discussed in Part 2 of this blog series.
  3. An Understanding of the differences between PowerShell and PowerShell Workflow:
    Reference 1: Syntactic Differences Between Script Workflows and Scripts
    Reference 2: Windows PowerShell: PowerShell scripts versus PowerShell workflows
    Reference 3: When Windows PowerShell Met Workflow
    Note     Many other references available on TechNet/MSDN.

PowerShell Workflow Differences / Notes

Here is a short list of differences and notes based on my experience creating the Public Cloud Environment Provisioning Example Solution with PowerShell Workflow:

  1. Get-AzureSubscription - There is a difference between executing the Get-AzureSubscription command within the script calling Workflows and executing the Get-AzureSubscription command within the Workflows themselves. For this reason, within the final script (which contains variables, Workflows and Workflow calls), I have placed $AzureSubscriptionForWorkflow = Get-AzureSubscription at the beginning of each Workflow. While there may be better ways to handle this, I found this the best way to ensure Workflow execution contains the necessary Windows Azure Subscription information required by the Windows Azure commands being called.
  2. Return Values - The return values are not exactly what you would expect (especially if you were expecting the same results as when executed as straight PowerShell). This difference is to be expected, with the usage of Workflow. So, what you will see in these examples is verification based on if ($Variable.OperationStatus –eq "Succeeded") logic. Obviously, you can modify what is being returned by each Workflow based on your own project requirements. This is just the method I chose for these examples.
  3. PowerShell Jobs - Because we are leveraging Workflow, we can very easily take advantage of the -AsJob and Receive-Job features. You will see that I have used Jobs for the longer running portions of this example (Uploading the VHD to Windows Azure, Creating the Windows Azure VM from Windows Azure VM Image).
  4. Regions – Nothing major here, for the sake of organization, I decided to leverage #region … #endregion functionality. You will see in the overall script I have broken everything up into 5 major regions:
    image 

Other than these few things, you should be good to go!

Speaking of Regions…

I decided it would be neat (pardon the pun) to break this blog post into these 5 regions as well. Seems like a pretty organized and symmetric idea anyway… ;)


Pre-Requisite Setup

This section of the blog posts covers (references, rather) the necessary steps for an Established Windows Azure Subscription Connection.

#region 0.PrerequisiteSetup

This region is covered 100% in Part 2 of this blog series.

image

For reference, here is the link:
Automating Hybrid Clouds with Windows Azure and PowerShell (Part 2): Public Cloud Environment Provisioning PowerShell Examples

#endregion 0.PrerequisiteSetup


Region 0 Execution Results

Steps Completed in Region 0:

  • Connection to a Windows Azure Subscription Established

Pre-Requisite Workflows

This section of the blog post will cover all the PowerShell Workflow scripts required for the Public Cloud Environment Provisioning example solution.

Note     I am breaking them up into individual scripts so that you can leverage them one at a time if desired. The complete script exists at the end of this blog post.

#region 1.PrerequisiteWorkflows

001
#1.0 Establish Prerequisite Workflows

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
#1.1 Create Affinity Group
workflow Create-AzureAffinityGroup {

    param
    (
        [string]$ProjectName,
        [string]$AGLocation,
        [string]$AGLocationDesc,
        [string]$AGLabel
    )

    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureAffinityGroup = Get-AzureAffinityGroup -Name $ProjectName -ErrorAction SilentlyContinue

    if(!$AzureAffinityGroup) {
        $AzureAffinityGroup = New-AzureAffinityGroup -Location $AGLocation -Name $ProjectName -Description $AGLocationDesc -Label $AGLabel
    }

    Return $AzureAffinityGroup

}

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
#1.2 Create Cloud Service
workflow Create-AzureCloudService {

    param
    (
        [string]$ProjectName,
        [string]$AGName,
        [string]$CloudServiceDesc,
        [string]$CloudServiceLabel
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureService = Get-AzureService -ServiceName $ProjectName -ErrorAction SilentlyContinue

    if(!$AzureService) {
        $AzureService = New-AzureService -AffinityGroup $AGName -ServiceName $ProjectName -Description $CloudServiceDesc -Label $CloudServiceLabel
    }

    Return $AzureService

}

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
#1.3 Create Storage Account
workflow Create-AzureStorageAccount {

    param
    (
        [string]$StorageAccountName,
        [string]$AGName,
        [string]$StorageAccountDesc,
        [string]$StorageAccountLabel
    )

    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureStorageAccount = Get-AzureStorageAccount -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue

    if(!$AzureStorageAccount) {
        $AzureStorageAccount = New-AzureStorageAccount -AffinityGroup $AGName -StorageAccountName $StorageAccountName -Description $StorageAccountDesc -Label $StorageAccountLabel
    }

    Return $AzureStorageAccount

}

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
#1.4 Create Storage Container
workflow Create-AzureStorageContainer {

    param
    (
        [string]$StorageContainerName
    )

    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureStorageContainer = Get-AzureStorageContainer -Name $StorageContainerName -ErrorAction SilentlyContinue

    if(!$AzureStorageContainer) {
        $AzureStorageContainer = New-AzureStorageContainer -Name $StorageContainerName
    }

    Return $AzureStorageContainer

}

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
#1.5 Get Blob Info
workflow Get-AzureBlobInfo {

    param
    (
        [string]$StorageContainerName,
        [string]$VHDName
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureBlob = Get-AzureStorageBlob -Container $StorageContainerName -Blob $VHDName -ErrorAction SilentlyContinue

    Return $AzureBlob

}

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
#1.6 Upload Local VHD to Storage Container
workflow Upload-LocalVHDtoAzure {

    param
    (
        [string]$StorageContainerName,
        [string]$VHDName,
        [string]$SourceVHDPath,
        [string]$DestinationBlobURI,
        [bool]$OverWrite
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureBlob = Get-AzureStorageBlob -Container $StorageContainerName -Blob $VHDName -ErrorAction SilentlyContinue
   
    if(!$AzureBlob -or $OverWrite) {

        $AzureBlob = Add-AzureVhd -LocalFilePath $SourceVHDPath -Destination $DestinationBlobURI -OverWrite:$OverWrite
    }

    Return $AzureBlob

}

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
#1.7 Copy Blob from one Storage Container to another
workflow Copy-AzureStorageBlob {

    param
    (
        [string]$DestinationContainer,
        [string]$DestinationBlobName,
        [string]$SourceContainer,
        [string]$SourceBlobName
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureBlob = Get-AzureStorageBlob -Container $DestinationContainer -Blob $DestinationBlobName -ErrorAction SilentlyContinue
   
    if(!$AzureBlob) {

        $AzureBlob = Start-AzureStorageBlobCopy -DestContainer $DestinationContainer -SrcBlob $SourceBlobName -SrcContainer $SourceContainer -DestBlob $DestinationBlobName
    }
   
    Return $AzureBlob
}

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
#1.8 Create Azure VM Image from Copied Blob
workflow Create-AzureVMImage {

    param
    (
        [string]$VMImageName,
        [string]$VMImageBlobContainer,
        [string]$VMImageBlobName,
        [string]$VMImageOS
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $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
}

 

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
#1.9 Create Azure VM from Newly Created VM Image
workflow Create-AzureVM {

    param
    (
        [string]$VMName,
        [string]$ServiceName,
        [string]$AdminUsername,
        [string]$VMImageName,
        [string]$Password,
        [bool]$Windows,
        [string]$VMInstanceSize,
        [bool]$WaitForBoot
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $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
}

#endregion 1.PrerequisiteWorkflows


Region 1 Execution Results

Steps Completed in Region 1:

  • All PowerShell Workflow Scripts in the Example Solution Loaded and Ready for Execution

Create New Windows Azure Environment

Now the fun can begin. This is the part of the PowerShell Script where I call all the above Workflows required to create the New Windows Azure Environment – called in a particular order, with specific logic. If you have your Orchestrator hat on, you can think of the Workflows as Sub-Runbooks, and the follow script (when compiled together) is the Process Runbook. In fact, the same exact concept exists in SMA – Process Runbook and Sub-Runbooks.

Note     Once again, I am breaking up the main process script into multiple parts. This is so that it is easier to consume, and you can leverage it a piece at a time if desired. The complete script exists at the end of this blog post.

#region 2.CreateNewWindowsAzureEnvironment

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
#2.0 Setup/Configure the New Windows Azure Environment

#2.1 Reset all Workflow Defined Variables


    $AzureAffinityGroup = $null
    $AzureCloudService = $null
    $AzureStorageAccount = $null
    $GenericAzureStorageContainer = $null
    $ProjectAzureStorageContainer = $null
    $AzureBlobUploadJob = $null
    $AzureBlob = $null
    $CopiedAzureBlob = $null
    $AzureVMImage = $null
    $CreateAzureVMJob = $null

#2.2 Define Project Name Variable - This will be used throughout the example

    $ProjectName = "BCBWFDemo"

Note    Just like in Part 2 of this blog series, $ProjectName 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. Be sure to modify this value to fit your project.

001
002
003
004
005
006
007
008
#2.3 Create Affinity Group

    $AGName = $ProjectName
    $AGLocation = "West US"
    $AGLocationDesc = "Affinity group for $ProjectName VMs"
    $AGLabel = "$AGLocation $ProjectName"

    $AzureAffinityGroup = Create-AzureAffinityGroup -ProjectName $AGName -AGLocation $AGLocation -AGLocationDesc $AGLocationDesc -AGLabel $AGLabel

Note    Again, like in Part 2 of this blog series, $AGLocation is the Location the Affinity Group for this Environment/Project is associated with – be sure to modify this value to fit your project.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
if ($AzureAffinityGroup.OperationStatus -eq "Succeeded") {

#2.4 Create Cloud Service

    $CloudServiceDesc = "Service for $ProjectName VMs"
    $CloudServiceLabel = "$ProjectName VMs"

    $AzureCloudService = Create-AzureCloudService -ProjectName $ProjectName -AGName $AGName -CloudServiceDesc $CloudServiceDesc -CloudServiceLabel $CloudServiceLabel

#2.5.0 Create Storage Account

    $StorageAccountName = $ProjectName.ToLower()
    $StorageAccountDesc = "Storage account for $ProjectName VMs"
    $StorageAccountLabel = "$ProjectName Storage"

    $AzureStorageAccount = Create-AzureStorageAccount -StorageAccountName $StorageAccountName -AGName $AGName -StorageAccountDesc $StorageAccountDesc -StorageAccountLabel $StorageAccountLabel

}

Note    No changes (unless desired) to the example variable values is required in this section.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
if ($AzureStorageAccount.OperationStatus -eq "Succeeded") {

#2.5.1 Update Set-AzureSubscription with Current Storage Account; Validate

    Start-Sleep -Seconds 60
    $AzureStorageAccountName = $ProjectName.ToLower()
    Set-AzureSubscription -SubscriptionName $AzureSubscriptionName -CurrentStorageAccount $AzureStorageAccountName

#2.5.2 Create Generic VHD Storage Container; VHD will be uploaded here

    $GenericStorageContainerName = "vhds"
    $GenericAzureStorageContainer = Create-AzureStorageContainer -StorageContainerName $GenericStorageContainerName

#2.5.3 Create Project Storage Container; VHD will be copied here

    $ProjectStorageContainerName = $ProjectName.ToLower()
    $ProjectAzureStorageContainer = Create-AzureStorageContainer -StorageContainerName $ProjectStorageContainerName

}

Note    Again, no changes (unless desired) to the example variable values is required in this section.

#endregion 2.CreateNewWindowsAzureEnvironment


Region 2 Execution Results

Steps Completed in Region 2:

  • New! Windows Azure Affinity Group Created
  • New! Windows Azure Cloud Service Created
  • New! Windows Azure Storage Account Created
  • New! Windows Azure Storage Container (generic) Created
  • New! Windows Azure Storage Container (project specific) Created

The following are some screen shots I took based on the execution of Region 2 above:

New! Windows Azure Affinity Group Created

image

New! Windows Azure Cloud Service Created

image

New! Windows Azure Storage Account Created

image

New! Windows Azure Storage Container (generic) Created and

New! Windows Azure Storage Container (project specific) Created

image


Upload VHD to Windows Azure

The fun continues! Now that we have a new Windows Azure Environment, we can upload an “On-Prem” VHD.

Note     This region is pretty small and self-contained, so I have not broken it into pieces. Either way, the complete script exists at the end of this blog post.

#region 3.UploadVHDtoWindowsAzure

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
#3.0 Setup/Configure Source and Destination Settings for VHD Upload to Windows Azure

if ($AzureStorageAccount.OperationStatus -eq "Succeeded") {

#3.1 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

#3.2 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

#3.3 Upload Local VHD to Windows Azure Storage Container; this will take a while

    $AzureBlobUploadJob = Upload-LocalVHDtoAzure -StorageContainerName $GenericStorageContainerName -VHDName $DesitnationVHDName -SourceVHDPath $SourceVHDPath -DestinationBlobURI $DestinationBlobURI -OverWrite $OverWrite -AsJob
    Receive-Job -Job $AzureBlobUploadJob -AutoRemoveJob -Wait -WriteEvents -WriteJobInResults
}

Note     I am executing the Upload-LocalVHDtoAzure Workflow with the -AsJob option. This allows me to use the Receive-Job command, to track and monitor the Job’s status.

#endregion 3.UploadVHDtoWindowsAzure


Region 3 Execution Results

Steps Completed in Region 3:

  • “On-Prem” VHD Uploaded to Windows Azure

The following are two screen shots I took based on the execution of Region 3 above:

“On-Prem” VHD Uploaded to Windows Azure

In Process (Windows PowerShell Workflow)

image

Note     The output here is not as verbose as it was when directly executing the Add-AzureVhd command. I chose this for the example to keep things simple. You can certainly extend this with more script logic and output.

Results (Windows Azure Portal)

image


Copy Uploaded Windows Azure Blob from Generic to Project Container

On, and on! Now that we have the “On-Prem” VHD uploaded into the Generic Windows Azure Storage Container as a Windows Azure Blob, we can copy it over to the Project Specific Windows Azure Storage Container.

Note     Again, this region is pretty small and self-contained, so I have not broken it into pieces. Either way, the complete script exists at the end of this blog post.

#region 4.CopyUploadedAzureBlobFromGenericToProjectContainer

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
#4.0 Copy Uploaded Azure Blob from Generic Storage Container to Project Storage Container

#4.1 Get Azure Blob Info


    $AzureBlob = Get-AzureBlobInfo -StorageContainerName $GenericStorageContainerName -VHDName $DesitnationVHDName

if ($AzureBlob) {

#4.2 Set Source Blob Info for Copy

    $SourceBlobName = $DesitnationVHDName
    $SourceContainer = $GenericStorageContainerName

#4.3 Set Destination Blob Info for Copy

    $DestinationContainer = $ProjectStorageContainerName
    $DestinationBlobName = "{0}_copy.{1}" -f $ProjectName,$SourceDiskFileExt

#4.4 Copy Uploaded Blob from Generic to Project

    $CopiedAzureBlob = Copy-AzureStorageBlob -DestinationContainer $DestinationContainer -DestinationBlobName $DestinationBlobName -SourceContainer $SourceContainer -SourceBlobName $SourceBlobName

}

Note     Because some time passes during the upload, I be sure to get the Azure Blog Info as a simple check. You obviously can do a more rigorous test, but this is what I went with for the example.

#endregion 4.CopyUploadedAzureBlobFromGenericToProjectContainer


Region 4 Execution Results

Steps Completed in Region 4:

  • Uploaded VHD/Blob in Generic Container Copied to Project Specific Container

The following is a screen shot I took based on the execution of Region 4 above:

Uploaded VHD/Blob in Generic Container Copied to Project Specific Container

image


Create Windows Azure VM from Copied Azure Blob

Finally - We have arrived! Now that we have a copy of the Uploaded “On-Prem” VHD (copied from the Generic Windows Azure Storage Container to the Project Specific Windows Azure Storage Container), we can Create a new Windows Azure VM Image, and then a Windows Azure VM (again, all based on that originally Uploaded “On-Prem” VHD).

Note     Finally, while this last region is small, it does have two distinct parts. I have broken the script up by these two parts. And as you know, the complete script exists at the end of this blog post.

#region 5.CreateAzureVMFromCopiedAzureBlob

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
#5.0 Create Azure VM Image from Copied Azure Blob

if ($CopiedAzureBlob) {

#5.1 Set VM Image Info from Copied Blob Info

    $VMImageName = $ProjectName
    $VMImageBlobContainer = $DestinationContainer
    $VMImageBlobName = $DestinationBlobName
    $VMImageOS = "Windows"

#5.2 Create Azure VM Image from Copied Azure Blob

    $AzureVMImage = Create-AzureVMImage -VMImageName $VMImageName -VMImageBlobContainer $VMImageBlobContainer -VMImageBlobName $VMImageBlobName -VMImageOS $VMImageOS

}

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
if ($AzureVMImage) {

#5.3 Set VM Info

    $VMName = "{0}-001" -f $ProjectName.ToLower()
    $ServiceName = $ProjectName
    $AdminUsername = "AdminUser"
    $VMImageName = $AzureVMImage.ImageName
    $Password = "Pass@word1"
    $Windows = $true
    $VMInstanceSize = "ExtraSmall"
    $WaitForBoot = $true

#5.4 Create Azure VM from Newly Created VM Image

    $CreateAzureVMJob = Create-AzureVM -VMName $VMName -ServiceName $ServiceName -AdminUsername $AdminUsername -VMImageName $VMImageName -Password $Password -Windows $Windows -VMInstanceSize $VMInstanceSize -WaitForBoot $WaitForBoot -AsJob
    Receive-Job -Job $CreateAzureVMJob -AutoRemoveJob -Wait -WriteEvents -WriteJobInResults
}

Note     Once again, like in Part 2 of this blog series, there are a few variables that you will want to change to fit your project: $VMName, $AdminUsername, $Password, $Windows, $VMInstanceSize, $WaitForBoot. For more information about these variables, see Part 2 – Create Windows Azure VM.

Note     I am executing the Create-AzureVM Workflow with the -AsJob option. This allows me to use the Receive-Job command, to track and monitor the Job’s status.

#endregion 5.CreateAzureVMFromCopiedAzureBlob


Region 5 Execution Results

Steps Completed in Region 5:

  • New! Windows Azure VM Image Created
  • New! Windows Azure VM Created

The following are some screen shots I took based on the execution of Region 5 above:

New! Windows Azure VM Image Created

In Process (Windows PowerShell Workflow)

image

Note     The output here is not as verbose as it was when directly executing the New-AzureQuickVM command. I chose this for the example to keep things simple. You can certainly extend this with more script logic and output.

Results (Windows Azure Portal)

New! Windows Azure VM Created

image

image


Putting it all together

It’s that time again – time to extend the length of this blog post beyond what was thought possible, by adding all the PowerShell Regions above into one script. Either way, here are all the above PowerShell script portions, rolled up into one script example (a cool 402 lines of PowerShell):

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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
#region 0.PrerequisiteSetup

#0.0. Perform Prerequisite Setup Steps

#0.1. Download latest Windows Azure PowerShell Module: http://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 (to verify Execute: Get-AzureSubscription)

    $AzureSubscriptionName = "Windows Azure MSDN - Visual Studio Ultimate"
    Set-AzureSubscription -SubscriptionName $AzureSubscriptionName
    Select-AzureSubscription -SubscriptionName $AzureSubscriptionName
    Get-AzureSubscription

#endregion 0.PrerequisiteSetup

#region 1.PrerequisiteWorkflows

#1.0 Establish Prerequisite Workflows

#1.1 Create Affinity Group

workflow Create-AzureAffinityGroup {

    param
    (
        [string]$ProjectName,
        [string]$AGLocation,
        [string]$AGLocationDesc,
        [string]$AGLabel
    )

    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureAffinityGroup = Get-AzureAffinityGroup -Name $ProjectName -ErrorAction SilentlyContinue

    if(!$AzureAffinityGroup) {
        $AzureAffinityGroup = New-AzureAffinityGroup -Location $AGLocation -Name $ProjectName -Description $AGLocationDesc -Label $AGLabel
    }

    Return $AzureAffinityGroup

}

#1.2 Create Cloud Service
workflow Create-AzureCloudService {

    param
    (
        [string]$ProjectName,
        [string]$AGName,
        [string]$CloudServiceDesc,
        [string]$CloudServiceLabel
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureService = Get-AzureService -ServiceName $ProjectName -ErrorAction SilentlyContinue

    if(!$AzureService) {
        $AzureService = New-AzureService -AffinityGroup $AGName -ServiceName $ProjectName -Description $CloudServiceDesc -Label $CloudServiceLabel
    }

    Return $AzureService

}

#1.3 Create Storage Account
workflow Create-AzureStorageAccount {

    param
    (
        [string]$StorageAccountName,
        [string]$AGName,
        [string]$StorageAccountDesc,
        [string]$StorageAccountLabel
    )

    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureStorageAccount = Get-AzureStorageAccount -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue

    if(!$AzureStorageAccount) {
        $AzureStorageAccount = New-AzureStorageAccount -AffinityGroup $AGName -StorageAccountName $StorageAccountName -Description $StorageAccountDesc -Label $StorageAccountLabel
    }

    Return $AzureStorageAccount

}

#1.4 Create Storage Container
workflow Create-AzureStorageContainer {

    param
    (
        [string]$StorageContainerName
    )

    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureStorageContainer = Get-AzureStorageContainer -Name $StorageContainerName -ErrorAction SilentlyContinue

    if(!$AzureStorageContainer) {
        $AzureStorageContainer = New-AzureStorageContainer -Name $StorageContainerName
    }

    Return $AzureStorageContainer

}

#1.5 Get Blob Info
workflow Get-AzureBlobInfo {

    param
    (
        [string]$StorageContainerName,
        [string]$VHDName
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureBlob = Get-AzureStorageBlob -Container $StorageContainerName -Blob $VHDName -ErrorAction SilentlyContinue

    Return $AzureBlob

}

#1.6 Upload Local VHD to Storage Container
workflow Upload-LocalVHDtoAzure {

    param
    (
        [string]$StorageContainerName,
        [string]$VHDName,
        [string]$SourceVHDPath,
        [string]$DestinationBlobURI,
        [bool]$OverWrite
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureBlob = Get-AzureStorageBlob -Container $StorageContainerName -Blob $VHDName -ErrorAction SilentlyContinue
   
    if(!$AzureBlob -or $OverWrite) {

        $AzureBlob = Add-AzureVhd -LocalFilePath $SourceVHDPath -Destination $DestinationBlobURI -OverWrite:$OverWrite
    }

    Return $AzureBlob

}

#1.7 Copy Blob from one Storage Container to another
workflow Copy-AzureStorageBlob {

    param
    (
        [string]$DestinationContainer,
        [string]$DestinationBlobName,
        [string]$SourceContainer,
        [string]$SourceBlobName
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $AzureBlob = Get-AzureStorageBlob -Container $DestinationContainer -Blob $DestinationBlobName -ErrorAction SilentlyContinue
   
    if(!$AzureBlob) {

        $AzureBlob = Start-AzureStorageBlobCopy -DestContainer $DestinationContainer -SrcBlob $SourceBlobName -SrcContainer $SourceContainer -DestBlob $DestinationBlobName
    }
   
    Return $AzureBlob
}

#1.8 Create Azure VM Image from Copied Blob
workflow Create-AzureVMImage {

    param
    (
        [string]$VMImageName,
        [string]$VMImageBlobContainer,
        [string]$VMImageBlobName,
        [string]$VMImageOS
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $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
}

#1.9 Create Azure VM from Newly Created VM Image
workflow Create-AzureVM {

    param
    (
        [string]$VMName,
        [string]$ServiceName,
        [string]$AdminUsername,
        [string]$VMImageName,
        [string]$Password,
        [bool]$Windows,
        [string]$VMInstanceSize,
        [bool]$WaitForBoot
    )
   
    $AzureSubscriptionForWorkflow = Get-AzureSubscription

    $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
}

#endregion 1.PrerequisiteWorkflows

#region 2.CreateNewWindowsAzureEnvironment

#2.0 Setup/Configure the New Windows Azure Environment

#2.1 Reset all Workflow Defined Variables


    $AzureAffinityGroup = $null
    $AzureCloudService = $null
    $AzureStorageAccount = $null
    $GenericAzureStorageContainer = $null
    $ProjectAzureStorageContainer = $null
    $AzureBlobUploadJob = $null
    $AzureBlob = $null
    $CopiedAzureBlob = $null
    $AzureVMImage = $null
    $CreateAzureVMJob = $null

#2.2 Define Project Name Variable - This will be used throughout the example

    $ProjectName = "BCBWFDemo"

#2.3 Create Affinity Group

    $AGName = $ProjectName
    $AGLocation = "West US"
    $AGLocationDesc = "Affinity group for $ProjectName VMs"
    $AGLabel = "$AGLocation $ProjectName"

    $AzureAffinityGroup = Create-AzureAffinityGroup -ProjectName $AGName -AGLocation $AGLocation -AGLocationDesc $AGLocationDesc -AGLabel $AGLabel

if ($AzureAffinityGroup.OperationStatus -eq "Succeeded") {

#2.4 Create Cloud Service

    $CloudServiceDesc = "Service for $ProjectName VMs"
    $CloudServiceLabel = "$ProjectName VMs"

    $AzureCloudService = Create-AzureCloudService -ProjectName $ProjectName -AGName $AGName -CloudServiceDesc $CloudServiceDesc -CloudServiceLabel $CloudServiceLabel

#2.5.0 Create Storage Account

    $StorageAccountName = $ProjectName.ToLower()
    $StorageAccountDesc = "Storage account for $ProjectName VMs"
    $StorageAccountLabel = "$ProjectName Storage"

    $AzureStorageAccount = Create-AzureStorageAccount -StorageAccountName $StorageAccountName -AGName $AGName -StorageAccountDesc $StorageAccountDesc -StorageAccountLabel $StorageAccountLabel

}

if ($AzureStorageAccount.OperationStatus -eq "Succeeded") {

#2.5.1 Update Set-AzureSubscription with Current Storage Account; Validate

    Start-Sleep -Seconds 60
    $AzureStorageAccountName = $ProjectName.ToLower()
    Set-AzureSubscription -SubscriptionName $AzureSubscriptionName -CurrentStorageAccount $AzureStorageAccountName

#2.5.2 Create Generic VHD Storage Container; VHD will be uploaded here

    $GenericStorageContainerName = "vhds"
    $GenericAzureStorageContainer = Create-AzureStorageContainer -StorageContainerName $GenericStorageContainerName

#2.5.3 Create Project Storage Container; VHD will be copied here

    $ProjectStorageContainerName = $ProjectName.ToLower()
    $ProjectAzureStorageContainer = Create-AzureStorageContainer -StorageContainerName $ProjectStorageContainerName

}

#endregion 2.CreateNewWindowsAzureEnvironment

#region 3.UploadVHDtoWindowsAzure

#3.0 Setup/Configure Source and Destination Settings for VHD Upload to Windows Azure


if ($AzureStorageAccount.OperationStatus -eq "Succeeded") {

#3.1 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

#3.2 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

#3.3 Upload Local VHD to Windows Azure Storage Container; this will take a while

    $AzureBlobUploadJob = Upload-LocalVHDtoAzure -StorageContainerName $GenericStorageContainerName -VHDName $DesitnationVHDName -SourceVHDPath $SourceVHDPath -DestinationBlobURI $DestinationBlobURI -OverWrite $OverWrite -AsJob
    Receive-Job -Job $AzureBlobUploadJob -AutoRemoveJob -Wait -WriteEvents -WriteJobInResults
}

#endregion 3.UploadVHDtoWindowsAzure

#region 4.CopyUploadedAzureBlobFromGenericToProjectContainer

#4.0 Copy Uploaded Azure Blob from Generic Storage Container to Project Storage Container

#4.1 Get Azure Blob Info


    $AzureBlob = Get-AzureBlobInfo -StorageContainerName $GenericStorageContainerName -VHDName $DesitnationVHDName

if ($AzureBlob) {

#4.2 Set Source Blob Info for Copy

    $SourceBlobName = $DesitnationVHDName
    $SourceContainer = $GenericStorageContainerName

#4.3 Set Destination Blob Info for Copy

    $DestinationContainer = $ProjectStorageContainerName
    $DestinationBlobName = "{0}_copy.{1}" -f $ProjectName,$SourceDiskFileExt

#4.4 Copy Uploaded Blob from Generic to Project

    $CopiedAzureBlob = Copy-AzureStorageBlob -DestinationContainer $DestinationContainer -DestinationBlobName $DestinationBlobName -SourceContainer $SourceContainer -SourceBlobName $SourceBlobName

}

#endregion 4.CopyUploadedAzureBlobFromGenericToProjectContainer

#region 5.CreateAzureVMFromCopiedAzureBlob

#5.0 Create Azure VM Image from Copied Azure Blob


if ($CopiedAzureBlob) {

#5.1 Set VM Image Info from Copied Blob Info

    $VMImageName = $ProjectName
    $VMImageBlobContainer = $DestinationContainer
    $VMImageBlobName = $DestinationBlobName
    $VMImageOS = "Windows"

#5.2 Create Azure VM Image from Copied Azure Blob

    $AzureVMImage = Create-AzureVMImage -VMImageName $VMImageName -VMImageBlobContainer $VMImageBlobContainer -VMImageBlobName $VMImageBlobName -VMImageOS $VMImageOS

}

if ($AzureVMImage) {

#5.3 Set VM Info

    $VMName = "{0}-001" -f $ProjectName.ToLower()
    $ServiceName = $ProjectName
    $AdminUsername = "AdminUser"
    $VMImageName = $AzureVMImage.ImageName
    $Password = "Pass@word1"
    $Windows = $true
    $VMInstanceSize = "ExtraSmall"
    $WaitForBoot = $true

#5.4 Create Azure VM from Newly Created VM Image

    $CreateAzureVMJob = Create-AzureVM -VMName $VMName -ServiceName $ServiceName -AdminUsername $AdminUsername -VMImageName $VMImageName -Password $Password -Windows $Windows -VMInstanceSize $VMInstanceSize -WaitForBoot $WaitForBoot -AsJob
    Receive-Job -Job $CreateAzureVMJob -AutoRemoveJob -Wait -WriteEvents -WriteJobInResults
}

#endregion 5.CreateAzureVMFromCopiedAzureBlob

Finishing Up

I covered a bunch of “post deployment” topics in Part 2. I will not be repeating them in this part of the blog series. If you are interested, be sure to check out the following sections of Part 2:

  • Connecting to the Windows Azure VM
  • A Dashboard View of the created Windows Azure VM
  • Alternate Windows Azure VM Create Examples
  • Other Learnings

What’s next?

So, what’s next? This time, decreasing complexity! – Part 4 of this blog series lets you wipe the slate clean. It will be a pretty simple (in comparison) blog post that provides Windows PowerShell Examples to Deprovision all what you have created here (or with Part 2). You may be surprised how simple it is to “delete” everything!

Hey! What about SMA?

I know, I know. This blog post doesn’t say much about SMA. That is intentional. It is really about providing the Windows PowerShell Workflow version of the example solution, to get you thinking. How might this be leveraged? I mean, how might it be leveraged over the straight Windows PowerShell examples from Part 2? All great questions.

If there is interest, I am happy to put together another blog post where I actually leverage the above script(s) in SMA. At this point, this blog post is already entirely too long. So, until then, keep your comments and ideas coming. And feel free to leverage the Building Clouds Blog Forum (http://aka.ms/BuildingCloudsForum) for questions/comments/discussions/ideas/etc.!


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!


Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Please can you help me,

    When i for example only run the Create-AzureAffinityGroup workflow as described i get the following error "Get-AzureAffinityGroup: value cannot be null" It looks like the param variables are not used.

    When i removed the param section and change the variables in the value i want, the AffinityGroup is created.

    Kind Regards,
    Arie Heukels

  • @Arie - When calling the Create-AzureAffinityGroup workflow, as long as the following command has valid variables, the workflow execution should work:

    Create-AzureAffinityGroup -ProjectName $AGName -AGLocation $AGLocation -AGLocationDesc $AGLocationDesc -AGLabel $AGLabel

    Each of these are defined above the command:

    $ProjectName = "BCBWFDemo"
    $AGName = $ProjectName
    $AGLocation = "West US"
    $AGLocationDesc = "Affinity group for $ProjectName VMs"
    $AGLabel = "$AGLocation $ProjectName"

    The actual workflow is defined above these calls (because it has to exist before it is called). If that is what you changed, then it would work, just not in the way this example intended. Either way, you can change these variable definitions and workflow examples as you wish.

    -Charles