Configuring an Azure VM From a Sysprepped Source Image using ARM PowerShell.

While working on an Azure IaaS deployment, I was required to configure an Azure VM using a generalized image in a different resourcegroup.In this post, I want to document my experience using Azure Resource Manager Powershell cmdlets to achieve the related tasks.

The Sysprep tool in the C:\Windows\System32 directory of the windows Azure virtual machine shuts down the vm after the process.

Use the Set-AzureRmVM -Name APPVM0 -Generalized cmdlet with the Generalized parameter to mark the virtual machine as generalized.

The Generalized source image was captured using the Save-AzureRmVMImage cmdlet. Following the cmdlet run, the image was saved to an auto created “system” container/folder in the Storage account.In the following section, the set of ARM (Azure Resource Manager) PowerShell scripts perform the operations on the source Storage account that create the objects and variables required to copy the source vhd blob between containers in storage accounts residing in different Azure Resource Groups.

#Creating an Azure Virtual Machine from a Captured Image .
#Charles Chukwudozie

#Login to the ARM Portal.

#Retrieve and save the source ResourceGroupName in a variable.
$srcresourcegroupname = (Get-AzureRmResourceGroup -Name rgJsonTest -Location centralus).ResourceGroupName

#Get a list of the Resource group resources and note the storage account name.
Get-AzureRmResource  |?{$_.ResourceGroupName -eq "$srcresourcegroupname"} | ft Name

#Get the storage account name and save it in a variable.
$srcstorageaccountname = (Get-AzureRmStorageAccount -ResourceGroupName $srcresourcegroupname -Name rgjsonstorage).StorageAccountName

#Get the storage account access key pair, extract one of the keys and save it to a variable.
$srckeys = Get-AzureRmStorageAccountKey -ResourceGroupName $srcresourcegroupname -Name $srcstorageaccountname
$srckey = $srckeys.Value[0]

#Create a storage context for authorization to the storage account and it's containers/folders.
$srccontext = New-AzureStorageContext -StorageAccountName $srcstorageaccountname -StorageAccountKey $srckey

#Retrieve the current containers in the storage account and select the system container.
Get-AzureStorageContainer -Context $srccontext

#Retrieve the captured source vhd blob container absoluteuri from the system container and assign it to a variable.System container was autocreated during the Save-AzureRmVMImage task.
$absoluteuri = (((Get-AzureStorageContainer -Context $srccontext -Name system).CloudBlobContainer).Uri).AbsoluteUri

#Retrieve the captured source blobs' path from the name property in the system(captured image location) container. Assign it to a variable.
$srcblobspath = (Get-AzureStorageBlob -Container system -Context $srccontext).Name

#Retrieve the vhd blob path from the array.
$srcvhdblobpath = $srcblobspath[0]

#Use the Split() method with the forward slash as seperator,number of element count argument and array position to isolate the source vhd blob only.
$srcvhdblob = $srcvhdblobpath.Split('/',4)[3]

#Concatenate the $absoluteuri and $srcblob variables to build the $srcvhduri variable.
$srcvhduri = $absoluteuri + "/" + $srcvhdblobpath

In the next section, the PowerShell scripts create the destination Azure Resource Groups and performs the operations required to initiate the source vhd blob copy between the source and destination Azure storage accounts in different Resource resource groups.

#Create destination ResourceGroup.

#Save the ResourceGroupName to a variable.
New-AzureRmResourceGroup -Name rgNewImageVMs -Location centralus
$destresourcegroupname = (Get-AzureRmResourceGroup -Name rgNewImageVMs).ResourceGroupName

#Create destination storage account and save the storage account name to a variable. Retrieve the storage account key and create acontext for authorization.
New-AzureRmStorageAccount -ResourceGroupName $destresourcegroupname -Name capimgstorageaccount -SkuName Standard_LRS -Location centralus -Kind Storage
$deststorageacctname = (Get-AzureRmStorageAccount -ResourceGroupName $destresourcegroupname -Name capimgstorageaccount).StorageAccountName
$destkey = (Get-AzureRmStorageAccountKey -ResourceGroupName $destresourcegroupname -Name $deststorageacctname).Value[0]
$destcontext = New-AzureStorageContext -StorageAccountName $deststorageacctname -StorageAccountKey $destkey

#Create a storage container as a copy target for the source image from above.
New-AzureStorageContainer -Name vhds -Permission Blob -Context $destcontext
$destcontainer = (Get-AzureStorageContainer -Name vhds -Context $destcontext).Name

#Initiate the copy of the source image to the destination storage account.
Start-AzureStorageBlobCopy -AbsoluteUri $srcvhduri -DestContainer $destcontainer -DestBlob $srcvhdblob -Context $srccontext -DestContext $destcontext
Get-AzureStorageBlobCopyState -Blob $srcvhdblob -Container $destcontainer -Context $destcontext 

In the third and final section of the script, the Azure VM configuration object is created using the copied source image.

#Create an Azure VM from the captured sysprepped image.

#Set the parameters and variables required to configure the new Azure VMConfig.
$credential = Get-Credential -UserName "localuser"  -Message "Type the username and password of the VM local administrator account."
$timezone = "Central Standard Time"

#Create a storage container for the new VM os disk location.
New-AzureStorageContainer -Name osdisks -Permission Blob -Context $destcontext

#Get the new os disk container name and save to a variable.
$vmcontainer = (Get-AzureStorageContainer -Name osdisks -Context $destcontext).Name

#Get the absolute uri of the source image and save the object to a variable.
$srcimgpreuri = (((Get-AzureStorageContainer -Context $destcontext -Name $destcontainer).CloudBlobContainer).Uri).AbsoluteUri

#Get the source image vhd blob path and save to a variable.
$srcimgblob = (Get-AzureStorageBlob -Container $destcontainer -Context $destcontext).Name

#Concatenate the source image uri and source vhd blob variables to build the source image uri variable.
$srcimageuri = $srcimgpreuri + "/" + $srcimgblob

#Get the new VM OS disk absolute uri.
$osuri = (((Get-AzureStorageContainer -Name osdisks -Context $destcontext).CloudBlobContainer).Uri).AbsoluteUri

#Concatenate the new VM OS disk absolute uri and it's corresponding vhd to build the new VM vhduri variable.
$vhduri = $osuri + "/" + "os.vhd"

#Create an Azure Public IP Address for the new VM.
$vmpip = New-AzureRmPublicIpAddress -Name vmpip -ResourceGroupName $destresourcegroupname -Location centralus -AllocationMethod Dynamic

#Create an Azure Subnet for the VM
New-AzureRmVirtualNetworkSubnetConfig -Name Subnet1 -AddressPrefix ""

#Create an Azure VNet for the VM.
New-AzureRmVirtualNetwork -Name VNET1 -ResourceGroupName $destresourcegroupname -Location centralus -AddressPrefix "" -Subnet $vmsubnetconfig
#Save the new vNet and subnet objects in variables for later use.
$vNet1 = Get-AzureRmVirtualNetwork -Name vNET1 -ResourceGroupName $destresourcegroupname
$subnet1 = Get-AzureRmVirtualNetworkSubnetConfig -Name Subnet1 -VirtualNetwork $vNet1

#Create the new VM network interface.
New-AzureRmNetworkInterface -Name vmNic1 -ResourceGroupName $destresourcegroupname -Location centralus -SubnetId $subnet1.Id -PublicIpAddressId $vmpip.Id
$vmNic1 = Get-AzureRmNetworkInterface -Name vmNic1 -ResourceGroupName $destresourcegroupname

#Create the new VM config object
$sysprepvm = New-AzureRmVMConfig -VMName "sysprepvm" -VMSize "Standard_A1_v2"
$sysprepvm = Set-AzureRmVMOSDisk -VM $sysprepvm -Name "os.vhd" -SourceImageUri $srcimageuri -VhdUri $vhduri -Windows -CreateOption FromImage
$sysprepvm = Set-AzureRmVMOperatingSystem -VM $sysprepvm -Windows -ComputerName $sysprepvm.Name -Credential $credential -EnableAutoUpdate -ProvisionVMAgent -TimeZone $timezone
$sysprepvm = Add-AzureRmVMNetworkInterface -VM $sysprepvm -Id $vmNic1.Id

#Instantiate the VM Object.
New-AzureRmVM -ResourceGroupName $destresourcegroupname -Location centralus -VM $sysprepvm

The following screen shot shows the final result of the Azure VM creation script.


This entry was posted in Azure, Azure Resource Manager, Azure Windows PowerShell and tagged , , , , , , , , . Bookmark the permalink.

2 Responses to Configuring an Azure VM From a Sysprepped Source Image using ARM PowerShell.

  1. anusha says:

    I’ve created a VNET in one Resource Group, Storage in One Resource Group, and Now I’m trying to create a VM in another resource group with the existing resources. Can you please provide a powershell script for the above inputs.

  2. Pingback: Add-Azurermvmnetworkinterface Arm Portal - LoginWave

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s