This repository was archived by the owner on Oct 29, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
Cost retrieval script #31
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
1ee6a04
Cost query
9f804c0
Rename
0e7b63c
Exclude resource.json
ef20c65
.
2566a41
Add granularity
0419f69
Remove unused variables
3a3e6e0
Update gitignore
27187f9
Remove trailing whitespaces
a64d65e
Add README
e81aa23
Add README
31c03cf
Error checking and JSON output
dc30763
Add error checking and Excel output
5437091
Update .gitignor
24902fb
Format billing month
cad6a68
Readability
f33fc59
Fix lint checks
319951f
Fix lint checks
ac1cf44
Rework Az call to use granularity
2042c94
Correct typo
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jfaurskov marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,190 @@ | ||
| <# | ||
| .SYNOPSIS | ||
| Take a collection of given resource IDs and return the cost incurred during previous months, | ||
| grouped as needed. For this we use the Microsoft.CostManagement provider of each subscription. | ||
| Requires Az.CostManagement module 0.4.2 or later. | ||
dohughes-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Requires ImportExcel module if Excel output is requested. | ||
| PS1> Install-Module -Name Az.CostManagement | ||
| PS1> Install-Module -Name ImportExcel | ||
|
|
||
| .PARAMETER startDate | ||
| The start date of the period to be examined (default is the first day of the previous month) | ||
|
|
||
| .PARAMETER endDate | ||
| The end date of the period to be examined (default is the last day of the previous month) | ||
|
|
||
| .PARAMETER resourceFile | ||
| A JSON file containing the resources | ||
|
|
||
| .PARAMETER outputFile | ||
| The stem of the output file to be created. The extension will be added automatically based on the output format. Not used if outputFormat is 'console'. | ||
|
|
||
| .PARAMETER outputFormat | ||
| The format of the output file. Supported formats are 'json', 'csv', and 'console'. Default is 'json'. | ||
|
|
||
| .PARAMETER testMode | ||
| If set, only the first subscription ID will be used to retrieve a quick result set for testing purposes. | ||
|
|
||
| .EXAMPLE | ||
| .\Get-CostInformation.ps1 | ||
| .\Get-CostInformation.ps1 -startDate "2023-01-01" -endDate "2023-06-30" -resourceFile "resources.json" -outputFile "resource_cost" -outputFormat "json" | ||
|
|
||
| #> | ||
|
|
||
| param ( | ||
| [string]$startDate = (Get-Date).AddMonths(-1).ToString("yyyy-MM-01"), # the first day of the previous month | ||
| [string]$endDate = (Get-Date).AddDays(-1 * (Get-Date).Day).ToString("yyyy-MM-dd"), # the last day of the previous month | ||
| [string]$resourceFile = "resources.json", | ||
| [string]$outputFile = "resource_cost", | ||
| [string]$outputFormat = "json", # json, csv, excel or console | ||
| [switch]$testMode | ||
| ) | ||
|
|
||
| # Input checking | ||
| # Check that the resource file exists | ||
| if (-not (Test-Path -Path $resourceFile)) { | ||
| Write-Error "Resource file '$resourceFile' does not exist." | ||
| exit 1 | ||
| } | ||
|
|
||
| # Check that the requested output format is valid | ||
| if ($outputFormat -notin @("json", "csv", "excel", "console")) { | ||
| Write-Error "Output format '$outputFormat' is not supported. Supported formats are 'json', 'csv', 'excel', and 'console'." | ||
| exit 1 | ||
| } | ||
|
|
||
| # Check if the needed modules are installed | ||
| if (-not (Get-Module -ListAvailable -Name Az.CostManagement)) { | ||
| Write-Error "Az.CostManagement module is not installed. Please install it using 'Install-Module -Name Az.CostManagement'." | ||
| exit 1 | ||
| } | ||
| if ($outputFormat -eq "excel" -and -not (Get-Module -ListAvailable -Name ImportExcel)) { | ||
| Write-Error "ImportExcel module is not installed. Please install it using 'Install-Module -Name ImportExcel'." | ||
| exit 1 | ||
| } | ||
|
|
||
| # Read the content of the workloads file | ||
| $jsonContent = Get-Content -Path $resourceFile -Raw | ||
|
|
||
| # Convert the JSON content to a PowerShell object | ||
| $workloads = $jsonContent | ConvertFrom-Json | ||
| $resourceTable = $workloads | Select-Object ResourceSubscriptionId, ResourceId | ||
|
|
||
| if ($testMode) { | ||
| $subscriptionIds = @($subscriptionIds[0]) # For testing, use only the first subscription ID | ||
| } | ||
|
|
||
| # Query parameters | ||
| $timeframe = "Custom" | ||
| $type = "AmortizedCost" | ||
| $granularity = "Monthly" | ||
|
|
||
| $grouping = @( | ||
| @{ | ||
| type = "Dimension" | ||
| name = "ResourceId" | ||
| }, | ||
| @{ | ||
| type = "Dimension" | ||
| name = "PricingModel" | ||
| }, | ||
| @{ | ||
| type = "Dimension" | ||
| name = "MeterCategory" | ||
| }, | ||
| @{ | ||
| type = "Dimension" | ||
| name = "MeterSubcategory" | ||
| }, | ||
| @{ | ||
| type = "Dimension" | ||
| name = "Meter" | ||
| }, | ||
| @{ | ||
| type = "Dimension" | ||
| name = "ResourceGuid" | ||
| } | ||
| ) | ||
|
|
||
| $aggregation = @{ | ||
| PreTaxCost = @{ | ||
| type = "Sum" | ||
| name = "PreTaxCost" | ||
| } | ||
| } | ||
|
|
||
| $table = @() | ||
| $subscriptionIds = $resourceTable.ResourceSubscriptionId | Sort-Object -Unique | ||
|
|
||
| if ($subscriptionIds.Count -eq 1) { | ||
| $subscriptionIds = @($subscriptionIds) # If only one subscription ID is found, use it as an array | ||
| } | ||
|
|
||
| # Group the resources by subscription and issue a cost management query for each subscription | ||
| # This reduces the number of API calls and allows us to handle multiple subscriptions efficiently. | ||
|
|
||
| for ($subIndex = 0; $subIndex -lt $subscriptionIds.Count; $subIndex++) { | ||
| $scope = "/subscriptions/$($subscriptionIds[$subIndex])" | ||
|
|
||
| $resourceIds = $resourceTable | Where-Object { $_.ResourceSubscriptionId -eq $subscriptionIds[$subIndex] } | Select-Object -ExpandProperty ResourceId | ||
| Write-Output "Querying subscription $(${subIndex}+1) of $($subscriptionIds.Count): $($subscriptionIds[$subIndex])" | ||
|
|
||
| $dimensions = New-AzCostManagementQueryComparisonExpressionObject -Name 'ResourceId' -Value $resourceIds | ||
| $filter = New-AzCostManagementQueryFilterObject -Dimensions $dimensions | ||
|
|
||
| $queryResult = Invoke-AzCostManagementQuery ` | ||
| -Scope $scope ` | ||
| -Timeframe $timeframe ` | ||
| -Type $type ` | ||
| -TimePeriodFrom $startDate ` | ||
| -TimePeriodTo $endDate ` | ||
| -DatasetAggregation $aggregation ` | ||
| -DatasetGrouping $grouping ` | ||
| -DatasetFilter $filter ` | ||
| -DatasetGranularity $granularity | ||
|
|
||
| # Convert the query result into a table | ||
| for ($i = 0; $i -lt $queryResult.Row.Count; $i++) { | ||
| $row = [PSCustomObject]@{} | ||
| for ($j = 0; $j -lt $queryResult.Column.Count; $j++) { | ||
| # For column BillingMonth we output it as yyyy-MM | ||
| if ($queryResult.Column.Name[$j] -eq "BillingMonth" -and $queryResult.Column.Type[$j] -eq "Datetime") { | ||
| $value = Get-Date $queryResult.Row[$i][$j] -Format "yyyy-MM" | ||
| } else { | ||
| $value = $queryResult.Row[$i][$j] | ||
| } | ||
| $row | Add-Member -MemberType NoteProperty -Name $queryResult.Column.Name[$j] -Value $value | ||
| } | ||
| $table += $row | ||
| } | ||
| } | ||
|
|
||
| # Output in the desired format | ||
| switch ($outputFormat) { | ||
| "json" { | ||
| if ($outputFile -notmatch '\.json$') { | ||
| $outputFile += ".json" | ||
| } | ||
| $table | ConvertTo-Json | Out-File -FilePath $outputFile -Encoding UTF8 | ||
| Write-Output "$($table.Count) rows written to $outputFile" | ||
| } | ||
| "csv" { | ||
| if ($outputFile -notmatch '\.csv$') { | ||
| $outputFile += ".csv" | ||
| } | ||
| $table | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8 | ||
| Write-Output "$($table.Count) rows written to $outputFile" | ||
| } | ||
| "excel" { | ||
| if ($outputFile -notmatch '\.xlsx$') { | ||
| $outputFile += ".xlsx" | ||
| } | ||
| $label = "CostInformation" | ||
| $table | Export-Excel -WorksheetName $label -TableName $label -Path .\$outputFile | ||
| Write-Output "$($table.Count) rows written to $outputFile" | ||
| } | ||
| Default { | ||
| # Display the table in the console | ||
| $table | Format-Table -AutoSize | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # Cost data retrieval | ||
|
|
||
| ## About the script | ||
|
|
||
| This script is intended to take a collection of given resource IDs and return the cost incurred during previous months, grouped as needed. For this we use the Microsoft.CostManagement provider of each subscription. This means one call of the Cost Management PowerShell module per subscription. | ||
|
|
||
| Requires Az.CostManagement module version 0.4.2. | ||
|
|
||
| `PS1> Install-Module -Name Az.CostManagement` | ||
|
|
||
| Instructions for use: | ||
|
|
||
| 1. Log on to Azure using `Connect-AzAccount`. Ensure that you have Cost Management Reader access to each subscription listed in the resources file (default `resources.json`) | ||
| 2. Navigate to the 3-CostInformation folder and run the script using `.\Get-CostInformation.ps1`. The script will generate a CSV file in the current folder. | ||
|
|
||
| ## Documentation links | ||
| Documentation regarding the Az.CostManagement module is not always straightforward. Helpful links are: | ||
|
|
||
| | Documentation | Link | | ||
| | -------- | ------- | | ||
| | Cost Management Query (API) | [Link](https://learn.microsoft.com/en-us/rest/api/cost-management/query/usage) | | ||
| | Az.CostManagement Query (PowerShell) | [Link](https://learn.microsoft.com/en-us/powershell/module/az.costmanagement/invoke-azcostmanagementquery) | | ||
|
|
||
| Valid dimensions for grouping are: | ||
|
|
||
| ``` text | ||
| AccountName | ||
| BenefitId | ||
| BenefitName | ||
| BillingAccountId | ||
| BillingMonth | ||
| BillingPeriod | ||
| ChargeType | ||
| ConsumedService | ||
| CostAllocationRuleName | ||
| DepartmentName | ||
| EnrollmentAccountName | ||
| Frequency | ||
| InvoiceNumber | ||
| MarkupRuleName | ||
| Meter | ||
| MeterCategory | ||
| MeterId | ||
| MeterSubcategory | ||
| PartNumber | ||
| PricingModel | ||
| PublisherType | ||
| ReservationId | ||
| ReservationName | ||
| ResourceGroup | ||
| ResourceGroupName | ||
| ResourceGuid | ||
| ResourceId | ||
| ResourceLocation | ||
| ResourceType | ||
| ServiceName | ||
| ServiceTier | ||
| SubscriptionId | ||
| SubscriptionName | ||
| ``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.