Estimating your annual Azure bill

2015, Jun 01    

Following on from my last post when i was tinkering with the Azure EA Billing API…

If you have an Azure Enterprise Agreement, you might want to get a regular idea of where you usage (and money) is heading.

I got the idea from MyFitnessPal, which is a popular nutrition app.  At the end of every day, when you’ve logged your food and told it that you’re finished eating for the day it tells you that; “If every day was like today, then in 5 weeks you’d weigh 160lb’s” (Or something similar).

With utility billing, your usage could fluctuate wildly from day to day so it’s probably best not to take the single estimate without context from other metrics and information… But it’s fun to see what the bill would end up being.

Rather than just providing a straight powershell script, i’ve created a workflow that runs in the Azure Automation platform and submitted it to the public runbook gallery.

“Uses the Microsoft Azure Enterprise Agreement API to estimate your annual Microsoft Azure bill based on the last days usage.

The default Azure EA account is the sample account id and accesskey just so you can see it working before plugging your own details in. You should use the Microsoft Azure Enterprise portal to request your own accesskey.

I recommend adding the script to a daily schedule.

This script requires a credential asset for the your SMTP server in order to send the email.”

Here’s the (v1.0) version of the powershell script;

workflow Send-BillEstimate
{
    param (
        [Parameter(Mandatory=$true)]
        [string] 
        $enrollmentNo = "100",

        [Parameter(Mandatory=$true)]
        [string] 
        $accesskey = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Il92ZHZieDJYRUkyb2l5N09abVpVelZGelM2TSJ9.eyJpc3MiOiJlYS5taWNyb3NvZnRhenVyZS5jb20iLCJhdWQiOiJjbGllbnQuZWEubWljcm9zb2Z0YXp1cmUuY29tIiwibmJmIjoxNDI4NDYwOTgxLCJleHAiOjE0NDQyNzIxODEsIkVucm9sbG1lbnROdW1iZXIiOiIxMDAiLCJJZCI6Ijk3OGQ5MGRjLTEyZjUtNDVmZC1hZWY2LWNiZTQ0ZDE0NmFmNiIsIlJlcG9ydFZpZXciOiJTeXN0ZW0iLCJQYXJ0bmVySWQiOiIifQ.QEHdbHmUz4TXO8Ljhn8ktnt5m7rHO0hsRrDLTvoQP4luL-8gy98CywFi2OByhfPL6UY5Vx8MYtwTQhMbzefS6Cd8hNopP74AL1ENLT-WGn42JG2mWesizIuN1QHV-obZR5rKDT57leurgEWy3LscWlwM0v5vhtk-9e5p8_9YgYqnF3rC05l1kUBQYzEIeYeMxcp8YxsqlnQNoEdCIA4UN08Py7zjr0ohCYbkm76a0-XdquqOTdSKGrnFkmwPxzjWMkuX3f2zpck_Ps8x8TVBpfvywly0QjUbN0ssmLV20zrS8FqkKSdx13uQVzM3MXCBylu5WvhTKE_ogRJdxPpfiA",

        [Parameter(Mandatory=$true)]
        [string] 
        $mailfrom="",

        [Parameter(Mandatory=$true)]
        [string]
        $mailto="",

        [Parameter(Mandatory=$true)]
        [string]
        $smtpServer = "Smtp.gmail.com",
        
        [Parameter(Mandatory=$true)]
        [PSCredential] 
        $smtpServerCreds       
    )
    
    $baseurl = "https://ea.azure.com/rest/"
    $authHeaders = @{"authorization"="bearer $accesskey";"api-version"="1.0"}

    Write-Verbose "Getting billing summary"
    $url= $baseurl + $enrollmentNo + "/usage-reports"
    Write-Verbose $url
    $sResponse = InlineScript {Invoke-WebRequest $using:url -Headers $using:authHeaders -UseBasicParsing}
    Write-Verbose $sResponse.StatusCode
    $sContent = $sResponse.Content | ConvertFrom-Json 

    $month=$sContent.AvailableMonths[0].Month
    $url= $baseurl + $enrollmentNo + "/usage-report?month=$month&type=detail"
    Write-Verbose $url
    $mResponse = InlineScript {Invoke-WebRequest $using:url -Headers $using:authHeaders -UseBasicParsing}
    Write-Verbose $mResponse.StatusCode

    Write-Verbose "Split the response up into an array from a string"
    $mContent = ($mResponse.Content -split '[rn]')
    
    Write-Verbose "Convert from CSV to object"
    $monthBill = $mContent | Where-Object -FilterScript { [regex]::matches($_,",").count -gt 28} | ConvertFrom-Csv
    
    Write-Verbose "Get the last day of data available"
    $filterDay =$monthBill[-1].Date #
    $aday = $monthBill | Where-Object -FilterScript {$_.date -eq $filterDay}
    
    Write-Verbose "Calculate day cost"
    $adayCost = [math]::round($($aday | Select-Object -ExpandProperty ExtendedCost | Measure-Object -Sum).sum,2)
    
    Write-Output "Day Cost for $filterDay : $adayCost"
    
    if([int]$adayCost -gt 0) {
        Write-Verbose "Sending email"
    
        $body = ""
        $body += ""
        $body += "If every day were like today, your annual Azure bill would be..."
        $body += "" + ($adayCost*365) + ""
        $body += "Based on usage for " + ([datetime]$filterDay).tostring("dd MMM yyyy") + " ($adayCost)"
        send-mailmessage $mailto "Azure Billing Notification" -bodyashtml -body $body -from $mailfrom -SmtpServer $smtpServer -port "587" -UseSsl -credential $smtpServerCreds

        Write-Output "Sent email"
    }
}