Azure – Provision Azure Virtual Machine with UnManaged disks

Microsoft has introduced a new type of disk called “Managed” disk wherein Azure manages the disk and the underlying storage account overhead for you. And, Microsoft recommends you create Azure virtual machines with “managed” disks, which is straightforward.

However, you might come across scenarios where your organization/client may require creating an Azure virtual machine with “unmanaged” disks. Use the below code to create an Azure virtual machine with “unmanaged” disks.

$location = "EastUS2"
$rgname = "manjuResourceGroup"
New-AzureRmResourceGroup -Name manjuResourceGroup -Location $location

# Create a subnet configuration
$subnetConfig = New-AzureRmVirtualNetworkSubnetConfig -Name mySubnet -AddressPrefix

# Create a virtual network
$vnet = New-AzureRmVirtualNetwork -ResourceGroupName manjuResourceGroup -Location $location `
    -Name MYvNET -AddressPrefix -Subnet $subnetConfig

# Create a public IP address and specify a DNS name
$pip = New-AzureRmPublicIpAddress -ResourceGroupName manjuResourceGroup -Location $location `

    -AllocationMethod Static -IdleTimeoutInMinutes 4 -Name "mypublicdns$(Get-Random)"

# Create an inbound network security group rule for port 3389
$nsgRuleRDP = New-AzureRmNetworkSecurityRuleConfig -Name myNetworkSecurityGroupRuleRDP  -Protocol Tcp `
    -Direction Inbound -Priority 1000 -SourceAddressPrefix '' -SourcePortRange * -DestinationAddressPrefix * `
    -DestinationPortRange 3389 -Access Allow

# Create an inbound network security group rule for port 80
$nsgRuleWeb = New-AzureRmNetworkSecurityRuleConfig -Name myNetworkSecurityGroupRuleWWW  -Protocol Tcp `
    -Direction Inbound -Priority 1001 -SourceAddressPrefix '' -SourcePortRange * -DestinationAddressPrefix * `
    -DestinationPortRange 80 -Access Allow

# Create a network security group
$nsg = New-AzureRmNetworkSecurityGroup -ResourceGroupName manjuResourceGroup -Location $location `
    -Name myNetworkSecurityGroup -SecurityRules $nsgRuleRDP,$nsgRuleWeb

# Create a virtual network card and associate with public IP address and NSG
$nic = New-AzureRmNetworkInterface -Name myNic -ResourceGroupName manjuResourceGroup -Location $location `
    -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $pip.Id -NetworkSecurityGroupId $nsg.Id

# Define a credential object
$cred = Get-Credential

#VM config
$vmsize = "Standard_DS2"
$vm = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize
$pubName = ”MicrosoftWindowsServer”
$offerName = ”WindowsServer”
$skuName = ”2016-Datacenter”
$vm = Set-AzureRmVMOperatingSystem -VM $vm -Windows -ComputerName $vmName -Credential $cred
$vm = Set-AzureRmVMSourceImage -VM $vm -PublisherName $pubName -Offer $offerName -Skus $skuName -Version "latest"
$vm = Add-AzureRmVMNetworkInterface -VM $vm -Id $NIC.Id

# Create a new storage account
New-AzureRmStorageAccount -ResourceGroupName "manjuResourceGroup" -AccountName "manjustorageaccount" -Location $location -SkuName "Standard_LRS"

# Disk setup
$diskName = ”manju-disk”
$storageaccount = "manjustorageaccount"
$STA = Get-AzureRmStorageAccount -ResourceGroupName $rgName -Name $storageAccount
$OSDiskUri = $STA.PrimaryEndpoints.Blob.ToString() + "vhds/" + $diskName? + ".vhd"
$vm = Set-AzureRmVMOSDisk -VM $vm -Name $diskName -VhdUri $OSDiskUri -CreateOption fromImage

# Create the virtual machine
New-AzureRmVM -ResourceGroupName manjuResourceGroup -Location $location -VM $vm


Click here to download my PowerShell scripts for Free !!

Click here for Azure tutorial videos !!

Azure – Attach and Initialize Data disk to Azure Virtual Machine

When you create an Azure windows virtual machine, it comes a default OS drive (C:\) and a temporary drive (D:\). An azure virtual machine allows you to attach a data disk to it to expand the storage. The number of data disks that can be attached to the VM depends on the Size and Family of the VM.

You can automate the process of attaching the data disk and initializing it using two scripts:

Script 1: initializePartition.ps1

This script contains the code to initialize the RAW partition.

Script 2: attachAndInstallCSE.ps1

This script will attach the data disk to the Azure windows virtual machine. It also installs the Custom Script Extension to the virtual machine.



$disks = Get-Disk | Where partitionstyle -eq 'raw' | sort number
    $letters = 70..89 | ForEach-Object { [char]$_ }
    $count = 0
    $labels = "data1","data2"

    foreach ($disk in $disks) {
        $driveLetter = $letters[$count].ToString()
        $disk |
        Initialize-Disk -PartitionStyle MBR -PassThru |
        New-Partition -UseMaximumSize -DriveLetter $driveLetter |
        Format-Volume -FileSystem NTFS -NewFileSystemLabel $labels[$count] -Confirm:$false -Force




# Declaringvariables
$resourceGroupName = 'resourceGroupName'
$virtualMachineName = 'virtualMachineName'
$location = 'East US'
$storageType = 'Premium_LRS'
$dataDiskName = $virtualMachineName + '_datadisk1'

# Create a new managed data disk
$diskConfig = New-AzureRmDiskConfig -SkuName $storageType -Location $location -CreateOption Empty -DiskSizeGB 128
$dataDisk1 = New-AzureRmDisk -DiskName $dataDiskName -Disk $diskConfig -ResourceGroupName $resourceGroupName

# Get the virtual machine reference
$vm = Get-AzureRmVM -Name $virtualMachineName -ResourceGroupName $resourceGroupName

# Update the VM reference by adding the data disk
$vm = Add-AzureRmVMDataDisk -VM $vm -Name $dataDiskName -CreateOption Attach -ManagedDiskId $dataDisk1.Id -Lun 1

# Update the virtual machine
Update-AzureRmVM -VM $vm -ResourceGroupName $resourceGroupName

## Install the Custom Script Extension that inturn calls the initializePartition.ps1
$location = "East US 2"

# The name you want to give for the CSE
$extensionName = "extensionName"

$fileName = "initializePartition.ps1"

# Storage Account where the initializePartition.ps1 is present
$storageAccountName = "<INSERT_STORAGE_ACCOUNT_NAME>"

# Primary Access Key of Storage Account where the initializePartition.ps1 is present
$storageAccountAccessPrimaryKey = "<INSERT_STORAGE_PRIMARY_ACCESS_KEY>"

# Storage Account container where the initializePartition.ps1 is present
$storageAccountContainerName = "<INSERT_STORAGE_ACCOUNT_CONTAINER_NAME>"

Set-AzureRmVMCustomScriptExtension -ResourceGroupName $resourceGroupName -Location $location -VMName $virtualMachineName -Name $extensionName -TypeHandlerVersion "1.4" -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountAccessPrimaryKey -FileName $fileName -ContainerName $storageAccountContainerName


Click here to download my PowerShell scripts for Free !!

Click here for Azure tutorial videos !!



Azure – Understand your Azure resource utilization using Azure Metrics

Understanding resource utilization is very crucial in determining how your resources are performing. Using this data, you can them make decisions on cost optimization. From my experience, clients are very keen on having a scheduled Resource Utilization Report.

If you are working in an infrastructure team, then your report for a virtual machine may include, CPU utilization, memory, disk usage, network in/Out etc.,

You can use Azure PowerShell to download Azure Insight Metric Data.

As an example, below code shows you how to retrieve CPU Utilization data for an Azure virtual machine.


# Get the virtual machine object
$vm = get-azurermvm -ResourceGroupName "automationResourceGroup" -Name "hybridworker"

# Get the resource ID for the virtual machine
$resourceID = $vm.Id

# Retrieve Azure Insight metric definitions for virtual machines
Get-AzureRmMetricDefinition –ResourceId $resourceID -DetailedOutput


Output of the above cmdlet will fetch a lot of metrics. I have selected the “Percentage CPU”.

sourceId             : /subscriptions/aaaaaaa-bbbb-cccc-dddd-eeeeeeeee/resourceGroups/automation/providers/Microsoft.Compute/virtualMachines/hybridworker

Name                   :

                             LocalizedValue : Percentage CPU

                             Value          : Percentage CPU


Unit                   : Percent

PrimaryAggregationType : Average

Id                     : /subscriptions/aaaaaaa-bbbb-cccc-dddd-eeeeeeeee/resourceGroups/automation/providers/Microsoft.Compute/virtualMachines/hybridworker/providers/microsoft.insights/metricdefinitions/Percentage CPU


The “Value” will give you the correct Metric Name.


Below code will pull the CPU utilization of the virtual machine for the last 40 minutes.

$endTime = Get-Date
$startTime = $endTime.AddMinutes(-40)
$timeGrain = '00:01:00'
$metricName = 'Percentage CPU'
$metricData = Get-AzureRmMetric -ResourceId $resourceID -TimeGrain $timeGrain -StartTime $startTime -EndTime $endTime -MetricNames $metricName


I have shown you how to fetch one such metric for an Azure resource (Azure virtual machine in this case). Similarly, you can fetch metrics for any Azure resource by obtaining the relevant “resourceID” and fetching the appropriate Azure Metric Definition.

Click here to download my PowerShell scripts for Free !!

Click here for Azure tutorial videos !!


Azure -Forgot Azure Virtual machine password?

While troubleshooting RDP issues, one of the approaches is to connect to the Azure windows machine using its local admin credentials. What if you forgot the credentials? Use the below code to reset them using VMAccess extension and PowerShell:


$resourceGroupName = "<ENTER_RESOURCE_GROUP_NAME>"
$virtualMachineName = "<ENTER_VIRTUAL_MACHINE_NAME>"
$location = "<ENTER_VM_LOCATION>"
Set-AzureRmVMAccessExtension -ResourceGroupName $resourceGroupName -location $location -virtualMachineName $virtualMachineName -Credential (get-credential) -typeHandlerVersion "2.0" -Name VMAccessAgent


Post troubleshooting, you conclude that by resetting the RDP configuration, the RDP issue will get resolved. How do you reset the RDP configuration, when you are not able to RDP? You may cause service disruption if you decide to restart or redeploy the VM to reset the RDP configuration.

Azure allows you to reset the RDP configuration without logging into the Azure windows virtual machine.

Use the below code to reset the Remote Desktop Services Configuration:

The code resets the access extension named “myVMAccess” on the VM named “myVM” in the “myResourceGroup” resource group:

Set-AzureRmVMAccessExtension -ResourceGroupName "myResoureGroup" -VMName "myVM" -Name "myVMAccess" -Location WestUS -typeHandlerVersion "2.0" -ForceRerun


Click here to download my PowerShell scripts for Free !!

Click here for Azure tutorial videos !!

Azure – TAG Azure Virtual Machines?

In a cloud environment, the effective way to organize and manage your infrastructure is by tagging your resources. Example, if your client has multiple silos like marketing, sales etc., and your cost model is different to each silo, tagging the resources provides an effective way to measure and manage the cost for your client.

Use the below code to TAG your Azure virtual machine:

$resource_group = "resourceGroupName"
$vm_name = "virtualMachineName"
$tags = (Get-AzureRmResource -ResourceGroupName $resource_group -Name $vm_name).Tags
$tags += @{toolsinstalled="true"}
Set-AzureRmResource -ResourceGroupName $resource_group -Name $vm_name -ResourceType "Microsoft.Compute/VirtualMachines" -Tag $tags -Force


You may tag other resources (Storage Account, Virtual Network etc.,) by providing the correct values to “-ResourceType” parameter.

If you have a set of standard tags and you want to tag all virtual machines in a resource group, then use the code below as a template:



  ## Parameter declaration


  # Tag values passed as a parameter








$azure_vm_list = get-azurermvm -ResourceGroupName $resource_group

foreach($azure_vm_list_iterator in $azure_vm_list){

$tags = (Get-AzureRmResource -ResourceGroupName $resource_group -Name $azure_vm_list_iterator.name).Tags

# Creating a hash table with tag name and value

$tags += @{"RTB status"=$rtb_status_tag_value}

$tags += @{"OS Type"=$os_type_tag_value}

$tags += @{"Environment"=$environment_tag_value}

$tags += @{"Built Date"=$build_date_tag_value}

$tags += @{"Project Name"=$project_name_tag_value}

$tags += @{"Support Type"=$support_type_tag_value}

"Setting tags"| write-output

Set-AzureRmResource -ResourceGroupName $resource_group -Name $azure_vm_list_iterator.name -ResourceType "Microsoft.Compute/VirtualMachines" -Tag $tags -ApiVersion '2017-12-01' -force



Click here to download my PowerShell scripts for Free !!

Click here for Azure tutorial videos !!

PowerShell – Delete Azure blobs older than X number of days

As a cost optimization strategy, organizations decide to retain data that are certain days old and delete the old data.

The same strategy can be implemented in Azure Storage. Let’s say if our application requires data that are 60 days old, then our approach is to retain only 60 days of data. And delete any blob that is older than 60 days.

This script deletes Azure blobs that are older than X days. Here ‘X’ is the number of days that you want to retain the data. (60, as stated in my example)

Download the script

You can create an Azure Automation Runbook from this script and schedule it to run every day. So, you will not be billed for the unwanted data.

Click here to download my PowerShell scripts for Free !!

Click here for Azure tutorial videos !!



Azure – Generate report for unattached Azure disks (managed and un-managed)

When you delete a virtual machine (VM) in Azure, by default, any disks that are attached to the VM aren’t deleted. This feature helps to prevent data loss due to the unintentional deletion of VMs. After a VM is deleted, you will continue to pay for unattached disks.

Unattached MANAGED disks:

When a managed disk is attached to a VM, the ManagedBy property contains the resource ID of the VM. When a managed disk is unattached, the ManagedBy property is null. The script examines all the managed disks in an Azure subscription. When the script locates a managed disk with the ManagedBy property set to null, the script determines that the disk is unattached.

Unattached UN-MANAGED disks:

When an unmanaged disk is attached to a VM, the LeaseStatus property is set to Locked. When an unmanaged disk is unattached, the LeaseStatus property is set to Unlocked. The script examines all the unmanaged disks in all the Azure storage accounts in an Azure subscription. When the script locates an unmanaged disk with a LeaseStatus property set to Unlocked, the script determines that the disk is unattached.


Download the script here

PowerShell script to generate a report of unattached VHD disks. This script will create two files – unattached_managed_disks.csv, unattached_un_managed_disks.csv

These two files will contain details about VHD files that are not attached to an Azure virtual machine.

NOTE: You have to login into your account before running the script. “login-azurermaccount” to log in to your account.

You can use the generated CSV to better manage your Azure infrastructure. Understand why the disks are not in use and take an informed decision on whether you want to delete or re-use them. Thus helping you to identify resources that are not being utilized and to reduce cost.

Click here to download my PowerShell scripts for Free !!

Click here for Azure tutorial videos !!

PowerShell – Create local user and add them to administrator group

Creating a local user in a windows server and adding them to local administrator group seems to be a simple task. However, when you have to add many users, the manual task becomes very tedious.

The obvious solution is automation. We shall use PowerShell scripting to achieve this. Below is the script that we can use to run. This script will create local users and add them local administrator group.


# Create an array to contain user name
$user_list = @("aabb","bbcc","ccdd")

# Create an array to contain user full name
$user_fullname_list = @("aa bb", "bb cc", "cc dd")

# Iterate over the user names
for($i=0; $i -lt $user_list.Length; $i++){

# Create the users
 $Computer = [ADSI]"WinNT://$Env:COMPUTERNAME,Computer"
 $LocalAdmin = $Computer.Create("User", $user_list[$i])
 $LocalAdmin.FullName = $user_fullname_list[$i]

# Add the users to administrators group
 $group = [ADSI]"WinNT://$Env:COMPUTERNAME/Administrators,group"



Further enhancement, is to save the user_list and user_fullname_list into a text file and then read the data from the files into the script.


Click here to download my PowerShell scripts for Free !!

Visit my youtube channel for videos on Azure:


Azure – Collecting performance metrics for Azure virtual machines

Azure Monitor provides several ways to interact with metrics, including charting them in the portal, accessing them through the REST API, or querying them using PowerShell or CLI.

In this blog, we shall learn how to fetch the metrics for our Azure Virtual Machines using PowerShell. The script that I provide can be used as a utility to generate quick reports.

Below is the script:


Manjunath Rao
February 21, 2018
The script will generate performance metrics (as recorded by Azure agent) from Azure virtual machines and then populate into an excel sheet.
$ErrorActionPreference = “SilentlyContinue”
# Login to Azure Account
Login-AzureRmAccount -ErrorAction Stop
# The exception lands in [Microsoft.Azure.Commands.Common.Authentication.AadAuthenticationCanceledException]
Write-Host “User Cancelled The Authentication” -ForegroundColor Yellow
# Prompting the user to select the subscription
Get-AzureRmSubscription | Out-GridView -OutputMode Single -Title “Please select a subscription” | ForEach-Object {$selectedSubscriptionID = $PSItem.SubscriptionId}
Write-Host “You have selected the subscription: $selectedSubscriptionID. Proceeding with fetching the inventory. `n” -ForegroundColor green
# Setting the selected subscription
Select-AzureRmSubscription -SubscriptionId $selectedSubscriptionID
# Get the list of resource groups
$resourcegroup_list = (get-azurermresourcegroup).resourcegroupname
# Create an Excel COM Object
$excel = New-Object -ComObject excel.application
Write-Host “Something went wrong in creating excel. Make sure you have MSOffice installed to access MSExcel. Please try running the script again. `n” -ForegroundColor Yellow
# Create a Workbook
$workbook = $excel.Workbooks.Add()
# Creating a directory overrides if any directory exists with the same name
Write-Host “Creating a directory: C:\AzurePerformanceMetrics. This operation will override if you have a directory with the same name. `n” -ForegroundColor Yellow
New-Item C:\AzurePerformanceMetrics -Type Directory -Force
Write-Host “Creating the Performance Metrics worksheet…” -ForegroundColor Green
# Adding worksheet
# Creating the “Virtual Machine” worksheet and naming it
$VirtualMachineWorksheet = $workbook.Worksheets.Item(1)
$VirtualMachineWorksheet.Name = ‘Virtual Machine perf metrics’
# Headers for the worksheet
$VirtualMachineWorksheet.Cells.Item(1,1) = ‘Resource Group Name’
$VirtualMachineWorksheet.Cells.Item(1,2) = ‘VM Name’
$VirtualMachineWorksheet.Cells.Item(1,3) = ‘Location’
$VirtualMachineWorksheet.Cells.Item(1,4) = ‘Percentage CPU’
$VirtualMachineWorksheet.Cells.Item(1,5) = ‘Units’
$VirtualMachineWorksheet.Cells.Item(1,6) = ‘Network IN’
$VirtualMachineWorksheet.Cells.Item(1,7) = ‘Units’
$VirtualMachineWorksheet.Cells.Item(1,8) = ‘Network Out’
$VirtualMachineWorksheet.Cells.Item(1,9) = ‘Units’
$VirtualMachineWorksheet.Cells.Item(1,10) = ‘Disk Read Bytes’
$VirtualMachineWorksheet.Cells.Item(1,11) = ‘Units’
$VirtualMachineWorksheet.Cells.Item(1,12) = ‘Disk Write Bytes’
$VirtualMachineWorksheet.Cells.Item(1,13) = ‘Units’
$VirtualMachineWorksheet.Cells.Item(1,14) = ‘Disk Read Operations/Sec’
$VirtualMachineWorksheet.Cells.Item(1,15) = ‘Units’
$VirtualMachineWorksheet.Cells.Item(1,16) = ‘Disk Write Operations/Sec’
$VirtualMachineWorksheet.Cells.Item(1,17) = ‘Units’
# Cell Counter
$row_counter = 3
$column_counter = 1
foreach($resourcegroup_list_iterator in $resourcegroup_list){
#write-output “RG: ” $resourcegroup_list_iterator
$vm_list = get-azurermvm -ResourceGroupName $resourcegroup_list_iterator
foreach($vm_list_iterator in $vm_list){
write-host “Fetching performance metrics for the virtual machine: ” $vm_list_iterator.Name -ForegroundColor cyan
$percentage_cpu_data = get-azurermmetric -ResourceId $vm_list_iterator.id -TimeGrain 00:01:00 -MetricName “Percentage CPU” # Percentage
$network_in_data = get-azurermmetric -ResourceId $vm_list_iterator.id -TimeGrain 00:01:00 -MetricName “Network IN” # Bytes
$network_out_data = get-azurermmetric -ResourceId $vm_list_iterator.id -TimeGrain 00:01:00 -MetricName “Network Out” # Bytes
$disk_read_bytes_data = get-azurermmetric -ResourceId $vm_list_iterator.id -TimeGrain 00:01:00 -MetricName “Disk Read Bytes” # Bytes Per Second
$disk_write_bytes_data = get-azurermmetric -ResourceId $vm_list_iterator.id -TimeGrain 00:01:00 -MetricName “Disk Write Bytes” # Bytes Per Second
$disk_read_operations_data = get-azurermmetric -ResourceId $vm_list_iterator.id -TimeGrain 00:01:00 -MetricName “Disk Read Operations/Sec” # Count Per Second
$disk_write_operations_data = get-azurermmetric -ResourceId $vm_list_iterator.id -TimeGrain 00:01:00 -MetricName “Disk Write Operations/Sec” # Count Per Second
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $vm_list_iterator.ResourceGroupName.ToString()
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $vm_list_iterator.Name.ToString()
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $vm_list_iterator.Location.ToString()
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $percentage_cpu_data.Data[-2].Average
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = “Percentage”
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $network_in_data.Data[-2].Total
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = “Bytes”
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $network_out_data.Data[-2].Total
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = “Bytes”
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $disk_read_bytes_data.Data[-2].Average
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = “Bytes Per Second”
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $disk_write_bytes_data.Data[-2].Average
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = “Bytes Per Second”
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $disk_read_operations_data.Data[-2].Average
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = “Count Per Second”
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = $disk_write_operations_data.Data[-2].Average
$VirtualMachineWorksheet.Cells.Item($row_counter,$column_counter++) = “Count Per Second”
$row_counter = $row_counter + 1
$column_counter = 1
Write-Output ” ”
# Checking if the Inventory.xlsx already exists
if(Test-Path C:\AzurePerformanceMetrics\Performance_metrics.xlsx){
Write-Host “C:\AzurePerformanceMetrics\Performance_metrics.xlsx already exitst. Deleting the current file and creating a new one. `n” -ForegroundColor Yellow
Remove-Item C:\AzurePerformanceMetrics\Performance_metrics.xlsx
# Saving the workbook/excel file
}else {
# Saving the workbook/excel file


Click here to download my PowerShell scripts for Free !!