In my previous blog I wrote about AWS EC2 cost and usage report using AWS SDK for powershell. It was just for EC2 instances as obviously EC2 instances are one of main contributor to our AWS bill every month. However, we also wanted to have a cost and usage report for all deployed resource types in our AWS account. The script I am going to share today will generate such report in csv file format for a defined date and time interval.
Again, AWS has provided Cost Explorer to generate those reports using nice GUI and might be the most preferred solution for most of us. However, I like to use some automation around it using AWS SDK for powershell.
Here I will be using AWS Tools for powershell and make calls to cost and usage API – Get-CECostAndUsage . Refer here to get detailed documentation on the SDK.
First, I will define a time interval for the duration this cost and usage report will be generated. The First day ($firstDay) and Last day ($lastDay) variables will be either passed as parameters or will be generated in the script. It will be defined in the full script provided below.
$interval = New-Object Amazon.CostExplorer.Model.DateInterval
$interval.Start = $firstDay
$interval.End = $lastDay
Next, we need to define a Dimension to make API call. I will be using “SERVICE” as Dimension as I want my report to include all deployed Services in our AWS Account and the output of the API call will be grouped based on AWS Services.
$groupInfo = New-Object Amazon.CostExplorer.Model.GroupDefinition
$groupInfo.Type = "DIMENSION"
$groupInfo.Key = "SERVICE"
I am using Granularity as Daily, you can use Monthly/ Daily based on your requirements. For Metric, I will use BlendedCost. You can use any one of following – AmortizedCost, BlendedCost, NetAmortizedCost, NetUnblendedCost, NormalizedUsageAmount, UnblendedCost, and UsageQuantity. Refer documentations for more details.
Get-CECostAndUsage -TimePeriod $interval -Granularity DAILY -Metric BlendedCost -GroupBy $groupInfo
Now, we have the cost and usage data.However, it is not formatted in the way I wanted to report. So, now, I will take the output and start parsing and looping through it.
Here is my final script. Feel free to download and use it. You can execute it with or without parameters. For example, .\Generate-AWSServiceBillingReport.ps1 -firstDay “2019-08-01” -lastDay “2019-09-01” or just .\Generate-AWSServiceBillingReport.ps1 . Provide your comments in the comment section if you face any issue or you have any suggestion to improve it. Happy scripting !
Param(
[Parameter(Mandatory=$false)]
[String]$firstDay,
[Parameter(Mandatory=$false)]
[String]$lastDay
)
if([String]::IsNullOrEmpty($firstDay)){
$firstDay = Get-Date -Year (Get-Date).Year -Month (Get-Date).AddMonths(-1).Month -Day 1 -UFormat "%Y-%m-%d"
}
if([String]::IsNullOrEmpty($lastDay)){
$lastDay = Get-Date -Year (Get-Date).Year -Month (Get-Date).AddMonths(-1).Month -Day ([DateTime]::DaysInMonth((Get-Date).Year, (Get-Date).Month)) -UFormat "%Y-%m-%d"
}
$currentDir = $(Get-Location).Path
$oFile = "$($currentDir)\aws_billing_usage_data.csv"
$tFile = "$($currentDir)\aws_billing_usage_data_temp.csv"
if(Test-Path $oFile){
Remove-Item $oFile -Force
}
if(Test-Path $tFile){
Remove-Item $tFile -Force
}
"Service Name,Date,Cost" | Out-File $tFile -Append -Encoding ASCII
$interval = New-Object Amazon.CostExplorer.Model.DateInterval
$interval.Start = $firstDay
$interval.End = $lastDay
$groupInfo = New-Object Amazon.CostExplorer.Model.GroupDefinition
$groupInfo.Type = "DIMENSION"
$groupInfo.Key = "SERVICE"
$costUsage = Get-CECostAndUsage -TimePeriod $interval -Granularity DAILY -Metric BlendedCost -GroupBy $groupInfo
ForEach($c in $costUsage.ResultsByTime){
$sTime = $c.TimePeriod.Start
ForEach($grp in $c.Groups){
$srvName = $grp.Keys
$cost = $grp.Metrics["BlendedCost"].Amount
"$srvName,$sTime,$cost" | Out-File $tFile -Append -Encoding ASCII
}
}
Import-Csv $tFile | Sort-Object 'Service Name','Date' | Export-Csv -Path $oFile -NoTypeInformation
if(Test-Path $tFile){
Remove-Item $tFile -Force
}