Replicating a test / lab environment hosted on Microsoft Azure with Azure PowerShell
In my last post, I covered how to stand up a small test / lab environment in Azure using Azure Power Shell. If you have not seen that post, you can access it by clicking here.
In this post I want to cover another script I’ve created that automates the replication of a lab environment to a separate isolated new lab environment. The replica will have its own affinity group, own virtual network, and its own dedicated storage account.
The client who I built the initial set of these scripts for desired to offer clients a trial of their enterprise software in a hosted Azure lab environment. So, this script is designed to take what we call the “gold lab” and clone it to a new lab that would be handed over to a client for testing purposes.
Just like the previous script required, this script also requires that you go and manually create the virtual network in Azure first. The pre-deployment notes in the script should explain this in sufficient detail. Next, you need to choose the variables that the script will use to run with by editing the script.
- $labName is the name you wish to use for the destination (new) lab. As with the first script, this name will either become the name of the components, or be prepended to them.
- $azureLocation is the Azure region where the destination (new) lab will be deployed. I’ve not yet tested replication to a new region. So, for my purposes this region has been the same region that the original “gold” lab was in.
- $instanceSize is the instance size you wish for your destination (new) machines to be assigned when they are provisioned.
- $sourceStorageAccount is the source storage account where the source “gold lab” vhds live. If you used my previous script to create your gold lab, this will be the $labName you used in that script.
- $souceVM1Disk and $sourceVM2Disk are the source VHDs that you want to copy. Unfortunately, at this time you will need to manually enter these. I’d like in improve this in the future. You can get these by browsing your source storage container.
- $sourceContainer is the source container where the VHDs live. $destinationContainer is the destination container where the new VHDs will live. Normally this will be set to “vhds” but I wanted to offer these as variables so that if you like to have your VHDs in another container, you could still easily use this script.
Once you have those variables set, your source VMs are powered off and you have manually created the destination virtual network, you should be ready to roll.
Oh, before you run the script… Please remember that I am in no way responsible for what this script might do. I believe it to be useful, and generally safe. You should make sure you are 100% comfortable with what this script is doing before you begin. Ok – now that the lawyers can sleep again tonight, here we go. When you run the script you should see output something like this.
You now have a duplicate of your initial gold lab running in an isolated environment on Azure. In my case, this includes a Active Directory (AD) Domain Controller (DC) as well as some other software that generally does not respond well to being cloned. However, because the script is making an exact copy of the disks and spinning the new VMs up in a new identically configured isolated lab (where it can not communicate with the source lab) things work fine for testing purposes. Keeping the internal IP address assignments identical is key to making this work. In my case, I’m going back in and editing my virtual network after creation to make sure that DHCP is pointed at the IP reserved for my AD DC. This is obviously required for AD to behave. This may or may not be required in your situation.
I hope this is helpful to you. I am sure this script could be improved. However, I also hope it is in good enough shape to be helpful to some of you. If you see ways it could be made better, please let me know. Keep an eye on my blog for my lab destruction script that I’ll be posting soon. Until then, be sure to turn off / remove things you don’t want Azure to bill you for.
[code language=”powershell”]
#region Notes
# Lab Cloner – V2 Built on 2/7/2015
# Built by David Winslow – wdw.org
#
# Azure PowerShell General Notes / Commands
# [Console]::CursorSize = 25 (Makes the cursor blink so you don’t go insane.)
# Add-AzureAccount (Connects Azure PowerShell up to your Azure account)
#
# Pre-Deployment Notes:
# Run Add-AzureAccount (Connects Azure PowerShell up to your Azure account) before running this script.
# The destination network for the clone must be built manually in Azure portal before running this script.
# The network name must match $labName below.
# Address space: 10.20.0.0 /16
# Subnet-1 10.20.15.0 /24
# Subnet name must be Subnet-1)
# You need to choose values for the variables below.
#endregion
#region Pre-Deployment Variables
$labName = "lab104"
# This name will be user entirely for, or prepended to most components.
# Must be all lower case letters and numbers only.
# Must be Azure globally unique.
# Must not exceed 11 characters in length.
$azurelocation = "East US 2"
# This is the location that resources will be created in.
$instanceSize = "Standard_D2"
# This determines what size instances you create for the destination VMs launch.
$sourceStorageAccount = "lab102"
# This sets the source storage account.
$sourceVM1Disk = "lab102vm1-lab102vm1-2015-2-13-10-55-45-799-0.vhd"
# This sets the 1st source disk.
$sourceVM2Disk = "lab102vm2-lab102vm2-2015-2-13-10-53-38-795-0.vhd"
# This sets the 2nd source disk.
$sourceContainer = "vhds"
# This is the container the source disks are in.
$destinationStorageAccount = $labName
# This sets the destination storage account to the $labName
$destinationContainer = "vhds"
# This is the container the destination disks will be placed in.
#endregion
#region Write Pre-Deployment Variables to screen
Write-Output "============================"
Write-Output "Cloning Lab."
Write-Output "============================"
Write-Output " "
Write-Output "Source storage account set to:" $sourceStorageAccount
Write-Output " "
Write-Output "Souce VM Disk 1 set to:" $sourceVM1Disk
Write-Output " "
Write-Output "Souce VM Disk 2 set to:" $sourceVM2Disk
Write-Output " "
Write-Output "Souce container set to:" $sourceContainer
Write-Output " "
Write-Output "Destination storage account $labName will be created."
Write-Output " "
Write-Output "Destination container $destinationContainer will be created."
Write-Output " "
Write-Output "Destination instance size set to:" $instanceSize
Write-Output " "
Write-Output "Destination lab name set to:" $labName
Write-Output " "
Write-Output "Destination Azure lab location set to:" $azurelocation
Write-Output " "
#endregion
#region Assigning Azure Subscription
Write-Output " "
Write-Output "=================================="
Write-Output "Assigning Azure Subscription"
Write-Output "=================================="
Select-AzureSubscription "Pay-As-You-Go"
#endregion
#region Provisioning Affinity Group
Write-Output " "
Write-Output "=================================="
Write-Output "Provisioning Affinity Group"
Write-Output "=================================="
New-AzureAffinityGroup -Name $labName -Location $azureLocation
#endregion
#region Provisioning Destination Storage Account
Write-Output " "
Write-Output "=================================="
Write-Output "Provisioning Destination Storage Account"
Write-Output "=================================="
New-AzureStorageAccount $labName -AffinityGroup $labName
#endregion
#region VHD Blob Copy
Write-Output " "
Write-Output "============================"
Write-Output "Starting VHD Blob Copy"
Write-Output "============================"
# Get Source Keys
$sourceStorageAccountKey = (Get-AzureStorageKey -StorageAccountName $sourceStorageAccount).Primary
$destinationStorageAccountKey = (Get-AzureStorageKey -StorageAccountName $destinationStorageAccount).Primary
$sourceContext = New-AzureStorageContext –StorageAccountName $sourceStorageAccount -StorageAccountKey $sourceStorageAccountKey
$destinationContext = New-AzureStorageContext –StorageAccountName $destinationStorageAccount -StorageAccountKey $destinationStorageAccountKey
#create the destination container
New-AzureStorageContainer -Name $destinationContainer -Context $destinationContext
# VM1Disk
$blobCopy = Start-AzureStorageBlobCopy -DestContainer $destinationContainer `
-DestContext $destinationContext `
-SrcBlob $sourceVM1Disk `
-Context $sourceContext `
-SrcContainer $sourceContainer
# VM2Disk
$blobCopy = Start-AzureStorageBlobCopy -DestContainer $destinationContainer `
-DestContext $destinationContext `
-SrcBlob $sourceVM2Disk `
-Context $sourceContext `
-SrcContainer $sourceContainer
#endregion
#region Disk Additions
Write-Output " "
Write-Output "============================"
Write-Output "Starting Disk Additions"
Write-Output "============================"
# Add disks from the just cloned blobs
$VM1disk = $labName + "VM1.vhd"
$VM2disk = $labName + "VM2.vhd"
$VM1diskLocation = "https://" + $labName + ".blob.core.windows.net/vhds/" + $sourceVM1Disk
$VM2diskLocation = "https://" + $labName + ".blob.core.windows.net/vhds/" + $sourceVM2Disk
Write-Output $VM1disk
Write-Output $VM2disk
Write-Output $VM1diskLocation
Write-Output $VM2diskLocation
Add-AzureDisk -DiskName $VM1disk -OS Windows -MediaLocation $VM1diskLocation -Verbose
Add-AzureDisk -DiskName $VM2disk -OS Windows -MediaLocation $VM2diskLocation -Verbose
#endregion
#region Assigning Azure Subscription
Write-Output " "
Write-Output "=================================="
Write-Output "Assigning Destination Azure Subscription and Storage Account"
Write-Output "=================================="
Set-AzureSubscription -SubscriptionName "Pay-As-You-Go" -CurrentStorageAccount $labName
#endregion
#region Provisioning Reserved IP Addresses
Write-Output " "
Write-Output "=================================="
Write-Output "Provisioning Reserved IP Addresses"
Write-Output "=================================="
$VM1IP = $labName + "VM1IP"
$VM2IP = $labName + "VM2IP"
New-AzureReservedIP -ReservedIPName $VM1IP -Label $VM1IP -Location $azurelocation
New-AzureReservedIP -ReservedIPName $VM2IP -Label $VM2IP -Location $azurelocation
#endregion
#region Starting VM Creation
Write-Output " "
Write-Output "============================"
Write-Output "Starting VM Creation"
Write-Output "============================"
$VM1 = $labName + "VM1"
$VM2 = $labName + "VM2"
New-AzureVMConfig -Name $VM1 -InstanceSize $instanceSize -DiskName $VM1disk | Set-AzureSubnet ‘Subnet-1’ | Set-AzureStaticVNetIP -IPAddress 10.20.15.5 | Add-AzureEndpoint -Name "RemoteDesktop" -Protocol "tcp" -PublicPort 33899 -LocalPort 3389 | Add-AzureEndpoint -Name "PowerShell" -Protocol "tcp" -PublicPort 60208 -LocalPort 5986 | New-AzureVM -ServiceName $VM1 -AffinityGroup $labName -ReservedIPName $VM1IP -VNetName $labName
New-AzureVMConfig -Name $VM2 -InstanceSize $instanceSize -DiskName $VM2disk | Set-AzureSubnet ‘Subnet-1’ | Set-AzureStaticVNetIP -IPAddress 10.20.15.6 | Add-AzureEndpoint -Name "RemoteDesktop" -Protocol "tcp" -PublicPort 33900 -LocalPort 3389 | Add-AzureEndpoint -Name "PowerShell" -Protocol "tcp" -PublicPort 60209 -LocalPort 5986 | New-AzureVM -ServiceName $VM2 -AffinityGroup $labName -ReservedIPName $VM2IP -VNetName $labName
#endregion
[/code]