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!