---
title: "Build an Azure Detailed Usage Report with PowerShell"
description: "Create a PowerShell script to build an Azure detailed daily usage report using common Azure cmdlets."
canonical: "https://adamtheautomator.com/azure-detailed-usage-report/"
---

# Build an Azure Detailed Usage Report with PowerShell

> Create a PowerShell script to build an Azure detailed daily usage report using common Azure cmdlets.

Source: https://adamtheautomator.com/azure-detailed-usage-report/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![Build an Azure Detailed Usage Report with PowerShell](https://adamtheautomator.com/wp-content/uploads/2019/10/analysis-1841158_1920.jpg)

# Build an Azure Detailed Usage Report with PowerShell

[![](https://secure.gravatar.com/avatar/9a14f10ff1b1ec7d790d34f5b559e4d3de2d31b172e6ef266dfd8b479174d97b?s=192&d=mm&r=g)June Castillote](https://adamtheautomator.com/author/june/)1 October 20198 min. read

Categories: [Cloud](/category/cloud/)

Tags:[Microsoft Azure](/tag/microsoft-azure/)[PowerShell](/tag/powershell/)

Table of Contents

*   [Downloading Reports via the Azure Account Center](#downloading-reports-via-the-azure-account-center)
*   [Prerequisites](#prerequisites)
*   [How to Get Resource Usage Data](#how-to-get-resource-usage-data)
*   [Dealing with Paging in Get-UsageAggregates](#dealing-with-paging-in-get-usageaggregates)
*   [Building an Azure Resource Usage Reporting Function](#building-an-azure-resource-usage-reporting-function)
*   [Building the Parameters](#building-the-parameters)
*   [Querying Resource Usage](#querying-resource-usage)
*   [The Completed Script (Copy/Pastable)](#the-completed-script-copy-pastable-)
*   [Querying Resource Usage with Our Function](#querying-resource-usage-with-our-function)
*   [Filtering the Report](#filtering-the-report)
*   [Ideas for Extending the Report](#ideas-for-extending-the-report)
*   [Summary](#summary)
*   [Further Reading](#further-reading)

One of the most important aspects of running workloads in Azure is keeping track of expenses. How you do that is through tracking resource usage with an Azure detailed usage report. In this article, you’ll learn how to create a PowerShell script to easily query Azure resource usage and charges across all of your Azure resources by date.

Resources in Azure are constantly running up your bill in many different ways. Although you can see resource usage via a web portal, it’s limited. But by using a couple of PowerShell cmdlets, you can build a handy report to give you a bird’s eye view of what kind of usage (thus expenses) your Azure resources are up to.

_This article was created from a TechSnips YouTube video. If you’re a more visual learner, feel free to check out the video. Otherwise, read on!_

## Downloading Reports via the Azure Account Center

You can download many different usage reports from the [Azure Account Center](https://login.microsoftonline.com/common/oauth2/authorize?client_id=15689b28-1333-4213-bb64-38407dde8a5e&response_mode=form_post&response_type=code+id_token&scope=openid+profile&state=OpenIdConnect.AuthenticationProperties%3dATnm7-lHNf9NM6oHCDqWExRkUU1Vin5eOxlTMW0d1BapASn44l8pcOIGrnuoUWqWWT75uumpW5hNSlfOncUvQmYbETIDeJxy6Z-850fTGXhGZQDlElkeo03PwqDfqzH3g2PgmvNZ1P7KWQ7UiShFAA&nonce=637666878285904071.MzNmYjQ0YzItOWM4OC00NTU5LTg5NzQtYjRiNTFjYmM4YzMwZjVmNjBiNjctODdiYS00OWEzLWE3YjYtNjM3OWY1NTIyMDYw&redirect_uri=https%3a%2f%2faccount.azure.com%2flogin&max_age=86400&post_logout_redirect_uri=https%3a%2f%2faccount.azure.com&msafed=1&lw=1&fl=easi2). The Azure Account Center is a web portal that allows you to view your billing cycle history, download invoices, and see the overview of your Azure subscription.

Although you can download Azure usage reports via the Azure Account Center, there is no flexibility in choosing a date range. You can’t limit usage to a date range because the dates are fixed to coincide with your billing cycle.

You can see below an example of a billing period and links to download usage reports.

![Azure Account Center usage reports](/wp-content/uploads/2019/09/azure-account-center.png)

Azure Account Center usage reports

Inside of these usage reports contains a lot of other information that you might not need.

Perhaps you need usage reports for the last 60 days. To get this information using the Azure Account Center, you’d have to download usage reports for at least three billing cycles to cover all your required dates.

After the reports are downloaded, you’d then have to remove the excess data. You’d then have to figure out a way to consolidate that data somehow. No thanks! That’s too much overhead.

Using PowerShell, you can build a reusable script, function or module to pull Azure resource usage reports. These, in turn, can be run manually with a few lines of commands, or as a scheduled task to automate the execution.

## **Prerequisites**

This is a walkthrough article. To follow along, you’ll need to have a few things in place.

*   Windows 10 or later.
*   [Windows Powershell v5.1](https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/install/installing-windows-powershell?view=powershell-7.1#upgrading-existing-windows-powershell)
*   A script editor, like [_Notepad++_](https://notepad-plus-plus.org/downloads/) or an Integrated Scripting Environment (ISE) like [_Windows PowerShell ISE_](https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/ise/introducing-the-windows-powershell-ise?view=powershell-5.1) and [_Visual Studio Code_](https://code.visualstudio.com/download).
*   An Azure subscription.
*   [Azure PowerShell module](https://docs.microsoft.com/en-us/powershell/azure/?view=azps-6.4.0). The latest version as of this post is 2.6.0. This module must be installed in your machine. If you don’t have it yet, you can install it [using PowerShellGet](https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-6.4.0)
*   An established connection to Azure using the _[Connect-AzAccount](https://adamtheautomator.com/connect-azaccount/)_ cmdlet

## **How to Get Resource Usage Data**

Before creating the script, let us first discuss the basics using the [`Get-UsageAggregates`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts?view=powershell-7.1&viewFallbackFrom=powershell-6?view=azps-6.4.0) cmdlet. This is a cmdlet that allows you to pull Azure resource usage by date range, metrics like hourly or daily and more. The `Get-UsageAggregates` cmdlet is the main cmdlet that pulls off most of the magic you’ll be learning in this article.

To demonstrate the `Get-UsageAggregates` cmdlet, let’s say you need to find Azure resource usage from April 1st, 2019 to September 12th, 2019. The same technique can be used for any date range. Below you will see a snippet to find usage data based on those dates.

```powershell
$params = @{
    ReportedStartTime = '04-01-19'
    ReportedEndTime = '09-12-19'
    AggregationGranularity = 'Hourly'
    ShowDetails = $true
}
$usageData = Get-UsageAggregates @params
```

<table><tbody><tr><td><strong>Parameter</strong></td><td><strong>Value</strong></td><td><strong>Usage Explanation</strong></td></tr><tr><td>ReportStartTime</td><td>04-01-19</td><td>This is the oldest date you want to retrieve.<p></p><p>(Month Day Year)</p></td></tr><tr><td>ReportEndTime</td><td>09-12-19</td><td>This is the latest date you want to retrieve.<p></p><p>(Month Day Year)</p></td></tr><tr><td>AggregationGranularity</td><td>Hourly</td><td>The granularity of data to return. Valid values are “Daily” and “Hourly”</td></tr><tr><td>ShowDetails</td><td>$True</td><td>Indicates whether the instance-level details are expanded</td></tr></tbody></table>

If there are data returned, you should get the results similar to this screenshot below. You can see that the actual usage data is stored in the `UsageAggregations` property.

![Raw UsageAggregations output properties](/wp-content/uploads/2019/09/usageaggregations.png)

Raw UsageAggregations output properties

### **Dealing with Paging in Get-UsageAggregates**

In the section above, it would be common for the command to return many thousand objects especially for long date ranges. To prevent overwhelming the API, the `Get-UsageAggregates` command only returns a maximum of 1000 results. If you’ve saved the `$usageData` variable as covered in the previous section, you can confirm it by using running this command `$usageData.UsageAggregations.count`.

What if there are more than 1000 results? You’re going to have to do a little more work.

When you example the properties returned by `Get-UsageAggregates`, you’ll notice a property called `ContinuationToken` as shown below. You can see this token is a long string of characters.

![Usage aggregates continuation token](https://adamtheautomator.com/wp-content/uploads/2020/06/ee-this-token-is-a-long-string-of-characters..png)

Usage aggregates continuation token

The `ContinuationToken` is a pointer to the next set of results. This property acts as a bookmark to know from which page to get the next batch of results.

To demonstrate, get the last item in the previous result using `$usageData.UsageAggregations[-1]` as shown below. Note the `Usage Start` and `Usage End` times.

![First usage object](https://adamtheautomator.com/wp-content/uploads/2020/06/Note-the-Usage-Start-and-Usage-End-times..png)

First usage object

Now pass the same parameters to the `Get-UsageAggregates` command again. But this time, use the `ContinuationToken` parameter and use the value of the `ContinuationToken` property returned earlier. Below you can see an example of how to do this.

```powershell
$params = @{
    ReportedStartTime      = '04-01-19'
    ReportedEndTime        = '09-12-19'
    AggregationGranularity = 'Hourly'
    ShowDetails            = $true
    ContinuationToken      = $usageData.ContinuationToken
}
$usageData = Get-UsageAggregates @params
```

Now get the last item in the `UsageAggregations` property array using `$usageData.UsageAggregations[-1]`. Compare it to the previous result to confirm that the new results are different.

The comparison should be similar to the ones you see below. Notice the date ranges are seven days apart. By using the `ContinuationToken`, you retrieved the second page of results.

![Second page of usage reports](https://adamtheautomator.com/wp-content/uploads/2020/06/retrieved-the-second-page-of-results..png)

Second page of usage reports

![First page of usage reports](https://adamtheautomator.com/wp-content/uploads/2020/06/retrieved-the-second-page-of-results.1.png)

First page of usage reports

## **Building an Azure Resource Usage Reporting Function**

You should know how paging works and how to use the `ContinuationToken` property and parameter. But what if there are tens or even hundreds of thousands of results to retrieve? Manually using the token in this way isn’t going to work too well.

Let’s build a PowerShell that handles this paging requirement for us and allows us some further flexibility. This script will allow you to provide your own parameters and to handle the paging requirement. It’ll also give you the flexibility to extend it down the road to perform other tasks if need be.

### **Building the Parameters**

First build some function scaffolding. Below you can see an example function called `Get-AzureUsage`. This function has three parameters that may look familiar.

Previously, these parameters were defined on the `Get-UsageAggregates` cmdlet itself. You’re now building a “wrapper” function which will pass values to this cmdlet.

```powershell
Function Get-AzureUsage {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [datetime]$FromTime,
 
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [datetime]$ToTime,
 
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Hourly', 'Daily')]
        [string]$Interval = 'Daily'
    )
```

Below is a table providing further information on all of these parameters.

<table><tbody><tr><td><strong>Parameter</strong></td><td><strong>Usage</strong></td></tr><tr><td>FromTime</td><td>This is a mandatory parameter that accepts a DateTime value. The value represents the oldest date of the report.</td></tr><tr><td>ToTime</td><td>This is a mandatory parameter that accepts a DateTime value. The value represents the latest date of the report.</td></tr><tr><td>Interval</td><td>This is a non-empty parameter that accepts two possible values: <em>‘Daily’ </em>and <em>‘Hourly’</em>. The default value is Daily. This represents the granularity of the report to return.</td></tr></tbody></table>

### **Querying Resource Usage**

Once the function has been created and all parameters defined, it’s time to fill out the rest of the function.

You can see the rest of the `Get-AzureUsage` function below. Be sure to take a look at the comments for a deeper understanding of what the code is doing.

```powershell
Write-Verbose -Message "Querying usage data [$($FromTime) - $($ToTime)]..."
    $usageData = $null
    ## Start the do/while loop to automatically handle the continuation token
    do {    
        ## Define all parameters to pass to Get-UsageAggregates
        $params = @{
            ReportedStartTime      = $FromTime
            ReportedEndTime        = $ToTime
            AggregationGranularity = $Interval
            ShowDetails            = $true
        }
        ## Only use the ContinuationToken parameter if this is not the first run
        if ((Get-Variable -Name usageData -ErrorAction Ignore) -and $usageData) {
            Write-Verbose -Message "Querying usage data with continuation token $($usageData.ContinuationToken)..."
            $params.ContinuationToken = $usageData.ContinuationToken
        }
        $usageData = Get-UsageAggregates @params
        $usageData.UsageAggregations | Select-Object -ExpandProperty Properties
    } while ('ContinuationToken' -in $usageData.psobject.properties.name -and $usageData.ContinuationToken)
}
```

### **The Completed Script (Copy/Pastable)**

After putting the parameters and functional code together, you’ll get a completed script as you can see below. You can now copy this out into your own script or directly into the PowerShell console for testing.

```powershell
Function Get-AzureUsage {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [datetime]$FromTime,
 
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [datetime]$ToTime,
 
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Hourly', 'Daily')]
        [string]$Interval = 'Daily'
    )
    
    Write-Verbose -Message "Querying usage data [$($FromTime) - $($ToTime)]..."
    $usageData = $null
    do {    
        $params = @{
            ReportedStartTime      = $FromTime
            ReportedEndTime        = $ToTime
            AggregationGranularity = $Interval
            ShowDetails            = $true
        }
        if ((Get-Variable -Name usageData -ErrorAction Ignore) -and $usageData) {
            Write-Verbose -Message "Querying usage data with continuation token $($usageData.ContinuationToken)..."
            $params.ContinuationToken = $usageData.ContinuationToken
        }
        $usageData = Get-UsageAggregates @params
        $usageData.UsageAggregations | Select-Object -ExpandProperty Properties
    } while ('ContinuationToken' -in $usageData.psobject.properties.name -and $usageData.ContinuationToken)
}
```

## **Querying Resource Usage with Our Function**

Now is the time to put the function to the test. Either paste the code above in a script and [_dot source_](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts?view=powershell-6#script-scope-and-dot-sourcing) it into your current PowerShell session or copy the code directly into your PowerShell session.

> _Tip: If you’re using PowerShell ISE or Visual Studio Code, you can highlight the code you want to import and press F8. Otherwise, it is easier to copy and paste the code into a PowerShell session._

Now run the function providing a value to `FromTime`, `ToTime` and the interval you’d like to see the results as. You can see an example below on how to call this function.

```powershell
$usage = Get-AzureUsage -FromTime '08-12-19' -ToTime '09-12-19' -Interval Hourly -Verbose
```

Once this runs, you’ll see some verbose messages if you’ve chosen to use the optional `Verbose` parameter. As you can see from the example below, the usage report count is 4,659. You’ll also notice that function ran the `Get-UsageAggregates` function four times getting the next page of results each time. The function was able to do this because it used the correct `ContinuationToke` value for each call.

![Automatically handling the continuation token](https://adamtheautomator.com/wp-content/uploads/2020/06/because-it-used-the-correct-ContinuationToke-value-for-each-call..png)

Automatically handling the continuation token

## **Filtering the Report**

At this point, the report includes all usage details about all resource types available. But you can filter the report to display only the resource you want. To do this, you could either extend the function to allow this functionality or pipe the output to other PowerShell cmdlets.

The output from the `Get-Azure` function returns all resource types but includes a property called `MeterCategory`. This property defines the type of resource that row represents. For example, to get only Azure Virtual Machine usage reports, you could group together all of the objects with a `MeterCategory` of `Virtual Machines` using the [`Group-Object`](https://adamtheautomator.com/powershell-group-object/ "Group-Object") cmdlet.

The `Group-Object` cmdlet will return how many rows were present in the output as the `Count` property. Then, limiting the output to just the `Count` and `Name` property (value for `MeterCategory`), you can see how many usage report rows exist for all Azure resource types.

As you can see in the screenshot below, there are 768 entries for _Virtual Machines_ in the report.

![Azure Virtual Machines resource usage](https://adamtheautomator.com/wp-content/uploads/2020/06/768-entries-for-Virtual-Machines-in-the-report..png)

Azure Virtual Machines resource usage

To take this filtering concept a bit further, you could also leverage calculated properties to create friendlier output as shown below.

```powershell
$usage | Where-Object {$_.MeterCategory -eq 'Virtual Machines'} | `
Format-Table UsageStartTime,UsageEndTime,@{n="VM Name";e={(($_.InstanceData | `
ConvertFrom-Json).'Microsoft.Resources'.resourceURI -split "/")[-1]}},Quantity,Unit
```

When you run the code snippet above, you should see output similar to what you see below.

![Advanced filtering for Get-AzureUsage](https://adamtheautomator.com/wp-content/uploads/2020/06/When-you-run-the-code-snippe.png)

Advanced filtering for Get-AzureUsage

## **Ideas for Extending the Report**

Using the code in this article, you can extend the functionality of the tool just created many different ways.

You could [export the output to a CSV](https://adamtheautomator.com/export-csv/) fileand manipulate your data in Excel or [create an HTML](https://adamtheautomator.com/html-report/) report using [ConvertTo-HTML](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-html?view=powershell-7.1) or the [EnhancedHTML2](https://github.com/PowerShellOrg/EnhancedHTML2) PowerShell module.

Take things a bit further and add an email notification to the result too with the [Send-MailMessage](https://adamtheautomator.com/send-mailmessage/) cmdlet. The world is your oyster!

## **Summary**

In this post, you learned how to retrieve resource usage reports from Azure. You’ve also learned how to build a custom [PowerShell function](https://adamtheautomator.com/powershell-functions/ "PowerShell function") to automate the process and use that function to manipulate the output.

The next time you’re hit with an expected Azure bill, you have no excuse! Build yourself a PowerShell function to query Azure resource usage at any time to keep an eye on that bill.

## **Further Reading**

*   **_[How to Remove Microsoft Azure Virtual Machines and Cleanup with PowerShell](https://adamtheautomator.com/azure-vm-delete/)_**

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fazure-detailed-usage-report%2F&text=Build%20an%20Azure%20Detailed%20Usage%20Report%20with%20PowerShell)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fazure-detailed-usage-report%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fazure-detailed-usage-report%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2019/08/microsoft-graph.png)

### [Mastering PowerShell Graph API: Easy-to-Follow Insights](/powershell-graph-api/)

Master the PowerShell Graph API with our concise guide. Learn to access, read, and manage data effortlessly, enhancing your API skills quickly and efficiently.

![](https://adamtheautomator.com/wp-content/uploads/2020/02/braydon-anderson-wOHH-NUTvVc-unsplash-scaled.jpg)

### [Deploy Azure DSC Configurations with ARM Templates](/azure-dsc-2/)

Master the deployment of Azure DSC configurations to Azure VMs using ARM templates. Boost your cloud management skills and IT expertise.

![](https://adamtheautomator.com/wp-content/uploads/2019/12/network-2402637_1280.jpg)

### [Optimize Azure Scale Sets Management with PowerShell](/azure-powershell-scale-set/)

Master Azure Scale Sets management using PowerShell. Learn to create, configure, and automate VM scale sets for improved cloud infrastructure.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
