In this post, I will walk you through the process of creating a custom report with PowerShell for current usage of an Azure resource. That way, you will be able to compare how many of your resources are in use and how much capacity is left.

Defining Azure resources

Even though you've set your Azure resource limits to high values, it might still be critical to create consumption reports regularly. This is especially true for organizations that frequently create large numbers of resources in a dynamic way.

First, I'd like to list my current resources in a particular subscription:

Get-AzureRmResource | select name

This command shows us all resources in a subscription. However, this does not give us a complete report of all resource types and usage details.

Displaying all resources in a particular subscription

Displaying all resources in a particular subscription

In case we need to see how many virtual machines (VMs) are already in use, we can execute this command:

Total number of Azure Resource Manager (Azure RM) VMs

Total number of Azure Resource Manager (Azure RM) VMs

However, this command does not give us the maximum number of allowed VMs. You can view the limit for each resource available in Azure. But this is a huge list showing each resource with details for limits and quotas. The Azure PowerShell Module version 4.1.0 (or later) has the ability to list all resources with corresponding limit values.

Resource usage reports

Three cmdlets allow us to get a usage report for a particular Azure location. This point is important because each Azure location has its own separate limits, which may differ from one location to another. This is why we need to specify a value for the -Location parameter.

Get-AzureRmVMUsage -Location $location
Current usage of Azure RM VMs in a specific Azure location

Current usage of Azure RM VMs in a specific Azure location

Get-AzureRmStorageUsage | select name,currentvalue,limit

Current usage of Azure RM storage accounts, location independent

Get-AzureRmNetworkUsage -Location $location | select resourcetype,currentvalue,limit
Current usage of Azure RM network resources in a specific Azure location

Current usage of Azure RM network resources in a specific Azure location

Combining reports

Now we should combine all three of the cmdlets above using custom formatting. We need to make sure the output for each cmdlet has the same column structure so we can have a single table showing all results in it. To achieve this, we'll get them aligned in a single view by giving columns identical names.

The column names are Name, CurrentValue, and Limit:

$vms=Get-AzureRmVMUsage -Location $location | select @{label="Name";expression={$}},currentvalue,limit
$storages=Get-AzureRmStorageUsage | select name,currentvalue,limit
$networks=Get-AzureRmNetworkUsage -Location $location | select @{label="Name";expression={$_.resourcetype}},currentvalue,limit

Now we are able to see all the results in a single table:

Combination of VM, storage, and network resource usage reports

With the help of the Out-Gridview cmdlet, we can display the output in an interactive table:

$result | Out-gridview

Grid view of the consumption report

By doing this, we've created a complete table listing all details we need in terms of resource limits and consumptions.

Reporting usage limits

Let's take this one step further by adding a usage check feature. For instance, you may want to get notified in case you start running out of VMs before you hit the limit. Even though Azure limits are not that restricted, we can make sure we have a sufficient amount of resources to use before it's too late. It makes sense to send a notification when 80 percent of a certain resource has been consumed. The script below checks the values and sends you a daily report with resource details using the Send-MailMessage cmdlet.

The code below will do the trick. Note: I've set the limit to 4% to be able to test it. You can change it to any value you like.

$vms=Get-AzureRmVMUsage -Location $location | select @{label="Name";expression={$}},currentvalue,limit,@{label="PercentageUsed";expression={[math]::Round(($_.currentvalue/$_.limit)*100,1)}}
$storages=Get-AzureRmStorageUsage | select name,currentvalue,limit,@{label="PercentageUsed";expression={[math]::Round(($_.currentvalue/$_.limit)*100,1)}}
$networks=Get-AzureRmNetworkUsage -Location $location | select @{label="Name";expression={$_.resourcetype}},currentvalue,limit,@{label="PercentageUsed";expression={[math]::Round(($_.currentvalue/$_.limit)*100,1)}}
foreach($resource in $result){
	if($resource.percentageused -gt 4){

$body=$warning | convertto-html
The resources that are about to hit their warning levels

if($warning.count -gt 0){
	Send-MailMessage -BodyAsHtml -body $bodyhtml -Subject "Azure Resource Consumption Report" -SmtpServer -UseSsl -From -to -Credential (get-credential) -Port 587

The script sends you a consumption report showing the resources that are hitting their limits.

Subscribe to 4sysops newsletter!

An automatic Azure resource consumption report in your mailbox

An automatic Azure resource consumption report in your mailbox

  1. Avatar


    This script is fantastic, but I have problem in my scenario. I want to capture the Number of NSG Rules within the NSG. The command

    Get-AzureRmNetworkUsage -Location $location | select resourcetype,currentvalue,limit

    Result: I am NOT getting the actual currentvalue on the number of rules instead I get zero. But in portal I have 146 rules.

    Any help…


    K. Hasan

    • Avatar Author

      Hi Hasan,

      Please use the following command to get the number of rules defined within a Network Security group

      ((Get-AzureRmNetworkSecurityGroup -Name “NSGName” -ResourceGroupName “ResourceGroupName”).securityrules).count

      To be more specific, you can also narrow down the result specifying the direction (Inbound or Outbound)

      for Inbound Rules

      ((Get-AzureRmNetworkSecurityGroup -Name “NSGName” -ResourceGroupName “ResourceGroupName”).securityrules | where{$_.direction -eq “Inbound”}).count

      for Outbound Rules

      ((Get-AzureRmNetworkSecurityGroup -Name “NSGName” -ResourceGroupName “ResourceGroupName”).securityrules | where{$_.direction -eq “Outbound”}).count



  2. Avatar

    It works. Thanks

  3. Avatar
    Niklas 6 years ago


    Great article.

    One question, with syntax for Get-AzureRmStorageUsage it is not possible to set location/region. Accordin to MS docs it states ” The Get-AzureRmStorageUsage cmdlet gets the resource usage for Azure Storage for the current subscription.” However I’ve noticed that this is not true, and the current value doesn’t match the actuall value of storage accounts across several regions, and since the limitation for storage account is per region, this would have been great.

    Do you have any idea, how to secure that you get present with the correct value per region for storage accounts?


  4. Avatar
    Niklas 6 years ago

    + fun fact

    I’ve also noticed that CurrentValue you get from running Get-AzureRmStorageUsage does not match that actuall items I see if i go to Storage Account blade in the Azure portal.

  5. Avatar
    SparrowOncloud 5 years ago

    Hi, I want to see idle time of all azure resources running ( preferably by day/hour ) How can i achieve this?

Leave a reply

Your email address will not be published. Required fields are marked *


© 4sysops 2006 - 2023


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account