skip to Main Content

I am trying to get last month’s cost for each resource we have in Azure. I am aware of the cmdlet Get-AzConsumptionUsageDetail and I am able to get the information I need using the following, which gets the costs for the last complete billing period:

$data = $data = Get-AzConsumptionUsageDetail -BillingPeriod $(Get-Date (Get-Date).AddMonths(-1) -Format "yyyyMM")

That command takes about 4 minutes to run, and with our thousands of resources returns over 100,000 records. Given that we have a large number of resources, I realized it would not be feasible to do a separate call for each resource, or even each resource group. Looping through each resource group using Get-AzConsumptionUsageDetail was surpassing the threshold of calls allowed by Azure.

The end goal is to calculate the total monthly cost for each individual resource. Since I cannot do an individual call for each resource, I decided to use the command shown above to get everything at once. However if I define $Resource as

$Resources = Get-AzResource

and run the following, it took 57 seconds for a small sample of all of the resources in $Resources, due to the sheer size of $data:

measure-command {
    $Resources | select-object -first 200 | foreach-object -parallel {
        $test = $using:data | where-object InstanceName -eq $psitem.Name
    }
}

My question is: is there a way to get this pricing/consumption information where the data already shows the monthly total? This would greatly reduce the total number of records in $data and would speed it up a lot. At the very least, is there some way I can get the information more efficiently?

2

Answers


  1. Chosen as BEST ANSWER

    Thank you everyone for the feedback. I ended up modifying @Jahnavi's code and got it to work, but I will provide multiple solutions in case anybody finds this thread in the future.

    The final code I am using is:

    $BillingPeriodName = $(Get-Date (Get-Date).AddMonths(-1) -Format "yyyyMM")
    $ResourceConsumption = Get-AzConsumptionUsageDetail -BillingPeriod $BillingPeriodName
    $TotalMonthlyCosts = $ResourceConsumption | Group-Object -Property InstanceId | ForEach-Object {
       $totalCost = ($_.Group | Measure-Object -Property PretaxCost -Sum).Sum
        [pscustomobject]@{
            BillingPeriod = $BillingPeriodName
            ResourceId = $psitem.Name
            LastMonthCost = [math]::Round($totalCost,2)
       }
    }
    

    I decided to group by InstanceID instead of InstanceName because we have some identical resource names in our environment. Additionally, if you use Get-AzResource the ResourceID of that cmdlet will match to the InstanceID.

    I did also look into creating an export in Azure Cost Manager and using that data instead of Get-AzConsumptionUsageDetail. If anybody wants to see the documentation for setting up an export click here. From there, you can use Get-AzCostManagementExport and Invoke-AzCostManagementExecuteExport to get and run the export. You can see that documentation here. I set up a new container on a storage account. You can get that data with Get-AzStorageAccount, Get-AzStorageContainer, and Get-AzStorageBlobContent. Click here for that documentation. However, the main reasons I did not go down that route of using the export are:

    • The file names are dynamically set with a long ID in the csv name that is buried deep in a series of directories in the container, some directory names also based on the date. The coding involved was not worth the hassle given the other reasons below
    • It still returned the exact same number of records as Get-AzConsumptionDetail, so the only real benefit of it was speed
    • The code snippet above is only part 1 of 2 for my required code. Using the Group-Object recommended by @Jahnavi greatly sped up the Where-Object that is required in part 2. This is for when I cross-reference the consumption detail with Get-AzResource. Given that this already needed to change my script from ad hoc to running nightly on a schedule (due to the time it took, which was not horrible but still too long for an application user to wait for), I figured an extra minute or two would not matter at the end of the day.
    • I did not want to be fully dependent on an export, because if somebody else deletes the export in Azure my script would no longer work. Using Get-AzConsumptionUsageDetail may be a little slower, but it is more consistent.

    Thank you to everyone who contributed, and hopefully this thread can help somebody in the future.


  2. PowerShell get monthly consumption for all Azure resources: –

    Get-AzConsumptionUsageDetail is commonly used in PowerShell to collect cost use details for Azure resources. However, if you have a huge amount of data/resources, you should use the other Cost details solutions as detailed in the given MSDoc. And as @mclayton mentioned, the consumption usage information API has been deprecated and will no longer exist. For huge data sets, you can use Power BI or cost exports instead. You can easily go with the Portal download or PowerShell commands for lesser sorts of data.

    There are some resources in my Azure environment, but not many. I tried to extract each individual cost information using the below loop and was successful.

    $cost=Get-AzConsumptionUsageDetail -StartDate 2023-08-07 -EndDate 2023-08-08 -Top 10 -IncludeMeterDetails
    $cost | Group-Object -Property InstanceName | ForEach-Object {
       $totalCost = ($_.Group | Measure-Object -Property PretaxCost -Sum).Sum
       Write-Output "$($_.Name) - Total monthly cost: $totalCost"
    }
    

    enter image description here

    You can also refer Cost API requests samples for less amount of data.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search