Download Azure Usage and Resource Prices using Powershell

Microsoft has released APIs you can use to download Azure resource usage and prices (RateCard) programmatically. The API is very useful and quite easy to use. For me the problem was to figure out how to authenticate an API request from Powershell. For now they have only published code examples in C#. As Powershell is .NET based, too, I knew there had to be a solution.

To authenticate an API request the key point is to get hold of an Azure AD Access token. To do that you will need the URI of a Service Principal that has been granted at least read access to an Azure Subscription. To create the Service Principal using Powershell is well documented, but the only example of how to retrieve an access token was in C#. Luckily I found a blog post that explained how to query Azure AD using Graph API. The authentication method is the same, I just used an overload that matched the C# examples.

Requirements

You will first have to install the Azure Powershell module. Then you will have create a Service Principal (basically a service user) in the Azure subscription you wish to use to access the API. For Resource Cards you can use any subscription, as you specify the bid code, currency, locale and region you want prices for in the API request. If you are going to download usage data you will of course have to grant the service principal access to any subscriptions you need to download data from.

The procedure to create a service principal using Powershell is documented here. The steps I use are adopted from there.

# Import the Azure cmdlets
Import-Module Azure

# Enable Resource Manager cmdlets, Service Manager cmdlets are default. Ignore warning for now...
Switch-AzureMode -Name AzureResourceManager

# Select the Azure subscription you wish to run API requests against
$subscription = Get-AzureSubscription -SubscriptionName 'Azure On Open' # Or whatever your subscription is called
$subscription | Select-AzureSubscription

$ServicePrincipalName = 'Klemmestad.AzureResourceManagerPsApi'
$HelpPage = 'http://klemmestad.com/2015/07/30/download-azure-usage-and-resource-prices-using-powershell'
$ServiceUri = 'https://resmanapi.klemmestad.com' # An identifier unique to your own environment
$ServicePassword = 'A Very Secret Password.' # Any passphrase you deem secure enough

$azureAdApplication = New-AzureADApplication -DisplayName $ServicePrincipalName -HomePage $HelpPage -IdentifierUris $ServiceUri -Password $ServicePassword
New-AzureADServicePrincipal -ApplicationId $azureAdApplication.ApplicationId
New-AzureRoleAssignment -RoleDefinitionName Reader -ServicePrincipalName $azureAdApplication.ApplicationId

# Copy subscription id and subscription tenant id for later use:
$subscription.SubscriptionId
$subscription.TenantId

Download a Resource Card

This is how you can download an Azure in Open Licensing pricelist with prices specified in Norwegian Kroner, localized to Norwegian Bokm�l, valid in Norway. You create the OfferDurableId with a prefix of ‘MS-AZR-‘ and an offer number from this page. The other options (currency, locale and region) are probably well known to you. The API version is currently ‘2015-06-01-preview’ and will of course change sooner or later.

The resource card is formatted as JSON, and the easiest way by far to parse JSON is to let Powershell do it for you. Save JSON content to disk, use Get-Content -RAW and pipe it to ConvertFrom-JSON. The result is a proper Powershell object with all the resource meters available as an array in a property named ‘Meters’. At the end I pipe the array to Out-Gridview for you to browse.

# Activate Azure Powershell module
Import-Module Azure

# Subscription and Service Principal information
$SubscriptionId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$AzureTenantId = 'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy' # TenantId of above subscription
$ServiceUri = 'https://resmanapi.klemmestad.com' # Unique Id of a Service Principal you must create
$ServicePassword = 'A Very Secret Password.' # The password of the Service Principal
$Password = ConvertTo-SecureString $ServicePassword -AsPlainText -Force

# Authentication
$AuthenticationCreds = New-object Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential($ServiceUri,$Password)

$AuthenticationUri = 'https://login.windows.net/{0}' -f $AzureTenantId
$authenticationContext = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext($AuthenticationUri,$false)

$resource = 'https://management.core.windows.net/'
$authenticationResult = $authenticationContext.AcquireToken($resource, $AuthenticationCreds)

$ResHeaders = @{'authorization' = $authenticationResult.CreateAuthorizationHeader()}
$ApiVersion = '2015-06-01-preview'
$OfferDurableId = 'MS-AZR-0111p' # Azure on Open
$Currency = 'NOK'
$Locale = 'nb-no'
$RegionInfo = 'NO'
$ResourceCard = 'https://management.azure.com/subscriptions/{5}/providers/Microsoft.Commerce/RateCard?api-version={0}&`$filter=OfferDurableId eq '{1}' and Currency eq '{2}' and Locale eq '{3}' and RegionInfo eq '{4}'' -f $ApiVersion, $OfferDurableId, $Currency, $Locale, $RegionInfo, $SubscriptionId

$File = $env:TEMP + '\resourcecard.json'
Invoke-RestMethod -Uri $ResourceCard -Headers $ResHeaders -ContentType 'application/json' -OutFile $File
$Resources = Get-Content -Raw -Path $File -Encoding UTF8 | ConvertFrom-Json

Remove-Item -Force -Path $File

# Display result
$Resources.Meters | Out-GridView

Download Usage Data

The API call to download usage data can be called like this:

# API call
$ResHeaders = @{'authorization' = $authenticationResult.CreateAuthorizationHeader()}
$ApiVersion = '2015-06-01-preview'

# Last and first day of previous month
$EndDateTime = (Get-Date -Day 1 -Hour 0 -Minute 0 -Second 0 -Millisecond 0).AddDays(-1)
$StartDateTime = Get-Date -Day 1 $EndDateTime

# URL encode dates, formatted as SortableDateTimePattern
$StartTime = [System.web.httputility]::UrlEncode($(Get-Date -Format s $StartDateTime))
$EndTime = [System.web.httputility]::UrlEncode($(Get-Date -Format s $EndDateTime))
$Granularity = 'Daily'
$Details = 'false'

$UsageData = 'https://management.azure.com/subscriptions/{0}/providers/Microsoft.Commerce/UsageAggregates?api-version={1}&reportedStartTime={2}&reportedEndTime={3}&aggreagationGranularity={4}&showDetails={5}' -f $SubscriptionId, $ApiVersion, $StartTime, $EndTime, $Granularity, $Details

# Temporary output file
$File = $env:TEMP + '\resourceusage.json'

Invoke-RestMethod -Uri $UsageData -Headers $ResHeaders -ContentType 'application/json' -OutFile $File
$Usage = Get-Content -Raw -Path $File -Encoding UTF8 | ConvertFrom-Json

Remove-Item -Force -Path $File

$Usage.value |out-gridview

Now that you have the downloaded data available as Powershell objects you can convert it to any other format you may need.