Upload VHD to Azure

At my job, I am the person responsible for our Azure implementation. We have 5 production subscriptions, with 13 ARM virtual networks. We maintain our IaaS OS images on-premises, so that means I need to upload them monthly after patching them. Since the image needs to be in the same storage account as the destination server, that means I need to upload our images quite often. Automation of this process is coming soon, but for now, a quick script to make it less painful.

First, we have the parameters for the script:

Param (
    [string]$ImagePath,
    [string]$subscriptionId,
    [string]$ResourceGroupName,
    [string]$DestUrl
)

The parameters are pretty self-explanitory. $ImagePath is the local path to the vhd file (including file name). $subscriptionID is the subscription ID in Azure. $ResourceGroupName is name of the resource group of the destination storage account. $DestUrl is the url of the destination storage account.

Personally, I specify all of the parameters when I run the script, but I write my scripts friendly enough for the not so command-line savvy users. If any parameter is missing, the script will graphically prompt you for the input. For the image path, I turned to a post from “Hey, Scripting Guy!” Blog that I read a while ago. There, I found a function to produce a file-picker:

Function Get-VhdPath($initialDirectory)
{   
 [System.Reflection.Assembly]::LoadWithPartialName(System.windows.forms) | Out-Null

 $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
 $OpenFileDialog.initialDirectory = $initialDirectory
 $OpenFileDialog.filter = Virtual Hard Disk (*.vhd)| *.vhd
 $OpenFileDialog.ShowDialog() | Out-Null
 $OpenFileDialog.filename
} #end function Get-VhdPath

Other than that, I used Out-GridView to allow the user to select the value of the parameter, then initiate the upload to the storage account. The destination path that is hard coded in the script is a carry over from when you would convert an existing azure machine to an image. You can change this to whatever blob container your keep your images in.

if (!($DestUrl)){$DestUrl = "http://" + (Get-AzureRMStorageAccount | Out-GridView -Title "Select an Azure Storage Account..." -PassThru).StorageAccountName + ".blob.core.windows.net/system/Microsoft.Compute/Images/templates/" + $targetVHDName}

You can download the complete script from my GitHub here, or just copy it from below:

<#
    SYNOPSIS
        A script to upload a custom OS Image vhd file to Azure
    DESCRIPTION
        This script will upload the specified vhd file to Azure to the
        specified URL or to the default image blob url. 
    PARAMETER ImagePath
        The path of a custom OS image vhd file.
    PARAMETER subscriptionID
        ID of the destination Azure Subscription
    PARAMETER ResourceGroupName
        Name of the destination ResourceGroup
    PARAMETER DestUrl
        Url of the image destination
    EXAMPLE
        .\Upload-AzureVHD.ps1 -subscriptionId '3c7b4ca9-8975-4f91-a986-23123f495c8a'
        Description
        -----------
        This will invoke the Upload-AzureVHD.ps1 script with a specified subscriptionID.
        User will be prompted for the other variables.
        
        .\Upload-AzureVHD.ps1
        Description
        -----------
        User will be prompted for all variables.
    NOTES
        ScriptName  :   Upload-AzureVHD.ps1
        Created By  :   PSH Ninja
        Date Coded  :   11/11/2016
        Last Rev    :   3/27/2017
        
#>
Param (
    [string]$ImagePath,
    [string]$subscriptionId,
    [string]$ResourceGroupName,
    [string]$DestUrl

)

Process {

Function Get-VhdPath($initialDirectory)
{   
 [System.Reflection.Assembly]::LoadWithPartialName(System.windows.forms) | Out-Null

 $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
 $OpenFileDialog.initialDirectory = $initialDirectory
 $OpenFileDialog.filter = Virtual Hard Disk (*.vhd)| *.vhd
 $OpenFileDialog.ShowDialog() | Out-Null
 $OpenFileDialog.filename
} #end function Get-VhdPath


# Sign-in with Azure account credentials
Login-AzureRmAccount -ErrorAction Stop

# Select Azure Subscription
if(!($subscriptionID)){$subscriptionId = (Get-AzureRmSubscription | Out-GridView -Title "Select an Azure Subscription ..." -PassThru).SubscriptionId}
Select-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction Stop

# Select Azure Resource Group 
if (!($ResourceGroupName)){$ResourceGroupName = (Get-AzureRmResourceGroup | Out-GridView -Title "Select an Azure Resource Group ..." -PassThru).ResourceGroupName}

if (!($ImagePath)) {$ImagePath = Get-VhdPath -initialDirectory C:}
$targetVHDName = Split-Path $ImagePath -leaf

# Select Azure Storage account
if (!($DestUrl)){$DestUrl = "http://" + (Get-AzureRMStorageAccount | Out-GridView -Title "Select an Azure Storage Account..." -PassThru).StorageAccountName + ".blob.core.windows.net/system/Microsoft.Compute/Images/templates/" + $targetVHDName}

# Upload Azure vhd
Add-AzureRmVhd -ResourceGroupName $ResourceGroupName -Destination $DestUrl -LocalFilePath $ImagePath
}

Please let me know in the comments if this script helped you out!

Share Comments
comments powered by Disqus