June 23, 2024

SamTech 365

PowerPlatform, Power Apps, Power Automate, PVA, SharePoint, C#, .Net, SQL, Azure News, Tips ….etc

Provision Azure VMs with PowerShell

There are different ways to provision a VM in Microsoft Azure. The simplest approach is to use a very user-friendly and intuitive portal.

However, for some scenarios, you might want to automate the VMs creations.

This can be done either using the Azure CLI, Azure PowerShell or ARM templates.

Why would I use PowerShell to create VMs ?

The answer is very simple. If you want to automate the creation or have a certain grip and governance over how VMs are created you can script the provisioning process and reuse it as required.

Also, you might want to have consistency between your dev, test, uat & prod environment, or you want to delegate the complex VMs creation task to a junior team member, you can prepare the scripts and just let them run them.

What you need to know before creating your VM

The VM can have dozens of parameters and its creation can go from simple quick provisioning to a more complex and custom one.

In this article, we will just look at a simple and quick way of provisioning your VM.

If you want to dig into more details, you can check all the options and parameters of the New-AzVM (https://docs.microsoft.com/en-us/powershell/module/az.compute/new-azvm?view=azps-5.2.0).


The minimum you need to create a new VM is:

  • What resource group you want to put your VM in?
  • User name and password of the local admin account (assuming you will be provisioning Windows VMs).
  • Which OS image you want to use for the VM creation?
  • Any ports you want to open by default (e.g. 3389 for RDP connection)

The script

# Connect to your Azure Account

# Prepare the variables
$username = 'myadmin'
$password = ConvertTo-SecureString 'My$uP3R$Tr0NGPa$$w0r5' -AsPlainText -Force
$WindowsCredentials = New-Object System.Management.Automation.PSCredential($username, $password)

# The Magic
New-AzVM `
        -ResourceGroupName "Demos" `
        -Name "MyDemoVM1" `
        -Image "Win2019Datacenter" `
        -Credential $WindowsCredentials `
        -OpenPorts 3389

# Retreive the IP adress of the newly created VM   
Get-AzPublicIpAddress -ResourceGroupName "Demos" -Name "MyDemoVM1"

Once you run this script, you should see an output with a ProvisionningState : Succeeded and the public IP address.

You can double-check in your portal, your VM is ready to use.


Remove a VM

Now, if you need to delete an existing VM, you will have to remember to remove the different parts of the VMs.

Unfortunately, there is no simple command to take the different steps, as a result, you will have to manually remember to get rid of all components (VM, network interfaces, disks …etc.).

Here is the PowerShell script for that.

#Retreive the VM
$MyVM = Get-AzVM -Name MyDemoVM1 -ResourceGroupName Demos

#And all its resources
$azResourceParams = @{
 'ResourceName' = "MyDemoVM1"
 'ResourceType' = 'Microsoft.Compute/virtualMachines'
     'ResourceGroupName' = "Demos"
 $vmResource = Get-AzResource @azResourceParams

 #Get the VM Id
 $vmId = $vmResource.Properties.VmId

 #Get The Diagnostic Container Name
 $diagContainerName = ('bootdiagnostics-{0}-{1}' -f $MyVM.Name.ToLower().Substring(0, $i), $vmId)
 $diagSaRg = (Get-AzStorageAccount | where { $_.StorageAccountName -eq $diagSa }).ResourceGroupName

 #Start the recycling
 $saParams = @{
    'ResourceGroupName' = $diagSaRg
    'Name' = $diagSa
# Get-AzStorageAccount @saParams | Get-AzStorageContainer | where { $_.Name-eq $diagContainerName } | Remove-AzStorageContainer -Force

#Delete the actual VM
$null = $MyVM | Remove-AzVM -Force

#Delete the Network interfaces and resources
foreach($nicUri in $MyVM.NetworkProfile.NetworkInterfaces.Id) {
    $nic = Get-AzNetworkInterface -ResourceGroupName $MyVM.ResourceGroupName -Name $nicUri.Split('/')[-1]
    Remove-AzNetworkInterface -Name $nic.Name -ResourceGroupName $MyVM.ResourceGroupName -Force

    foreach($ipConfig in $nic.IpConfigurations) {
        if($ipConfig.PublicIpAddress -ne $null) {
            Remove-AzPublicIpAddress -ResourceGroupName $MyVM.ResourceGroupName -Name $ipConfig.PublicIpAddress.Id.Split('/')[-1] -Force

#Remove the VM Disk
$osDiskUri = $MyVM.StorageProfile.OSDisk.Vhd.Uri
$osDiskContainerName = $osDiskUri.Split('/')[-2]
$osDiskStorageAcct = Get-AzStorageAccount | where { $_.StorageAccountName -eq $osDiskUri.Split('/')[2].Split('.')[0] }
$osDiskStorageAcct | Remove-AzStorageBlob -Container $osDiskContainerName -Blob $osDiskUri.Split('/')[-1]

#Remove the VM Disk Status Blob
$osDiskStorageAcct | Get-AzStorageBlob -Container $osDiskContainerName -Blob "$($MyVM.Name)*.status" | Remove-AzStorageBlob

#In Case you have attached any data disks, remove them too
if ($MyVM.DataDiskNames.Count -gt 0) {
    foreach ($uri in $MyVM.StorageProfile.DataDisks.Vhd.Uri) {
        $dataDiskStorageAcct = Get-AzStorageAccount -Name $uri.Split('/')[2].Split('.')[0]
        $dataDiskStorageAcct | Remove-AzStorageBlob -Container $uri.Split('/')[-2] -Blob $uri.Split('/')[-1]