Public/Get-StorageCost.ps1
function Get-StorageCost { <# .SYNOPSIS Retrieves the Azure costs for one or more billing months for one or more storage accounts. .DESCRIPTION Invokes the Get-AzConsumptionUsageDetail cmdlet against one or more storage accounts to return billing data for a specified number of months. If you are interested to see how costs have changed since the previous mont use the -ComparePrevious switch to return additional properties that contain the cost data for the previous month and properties that calculate the cost difference. .PARAMETER AccountName The name or name/s of the Storage Account/s to query. If not specified all subscriptions available in the current context will be used. .PARAMETER BillingMonth The billing month to query for cost data, specified as a [datetime] object. You can specify just month/year, e.g 10/2023. If not specified uses the current date. .PARAMETER PreviousMonths The number of previous billing months to query. Default: 0. .PARAMETER SparkLineSize The row height of sparklines to generate (requires PSparkines module). Default: 1. .PARAMETER ComparePrevious Switch: Include values for the previous billing month and adds additional properties that compare the current month to the previous. .PARAMETER ComparePreviousOffset The number of months prior you want to compare the current billing month to, when using -ComparePrevious, e.g set to 3 to compare to 3 months prior. .PARAMETER ExcludeSparklines Switch: Do not generate/include Sparklines in the output. .PARAMETER Raw Switch: Include the raw cost consumption data as a property on the returned object. .EXAMPLE Get-StorageCost Description ----------- Returns costs for the current billing month for all Storage accounts in the current Azure context. .EXAMPLE Get-StorageCost -AccountName 'MyStorageAccount' Description ----------- Returns costs for the current billing month for the specified Storage Account name. .EXAMPLE Get-StorageCost -AccountName 'MyStorageAccountA','MyStorageAccountB' Description ----------- Returns costs for the current billing month for the specified Storage Account names. .EXAMPLE Get-StorageCost -BillingMonth 01/2024 -PreviousMonths 3 Description ----------- Returns costs from October 2023 to January 2024 for all Storage Accounts in the current Azure context. .EXAMPLE Get-StorageCost -BillingMonth 01/2024 -PreviousMonths 3 -ComparePrevious Description ----------- Returns costs from October 2023 to January 2024 for all Storage Accounts in the current Azure context and includes properties for comparing each month with the one prior. .EXAMPLE Get-StorageCost -BillingMonth 01/2024 -PreviousMonths 3 -ComparePrevious -ComparePreviousOffset 12 Description ----------- Returns costs from October 2023 to January 2024 for all Storage Accounts in the current Azure context and includes properties for comparing each month with the one 12 months prior #> [CmdletBinding()] param( [Alias('Name', 'Account')] [string[]] $AccountName, [Alias('Month')] [datetime] $BillingMonth = (Get-Date), [Alias('PrevMonths')] [int] $PreviousMonths = 0, [ValidateRange(1, 10)] [int] $SparkLineSize = 1, [Alias('ComparePrev')] [switch] $ComparePrevious, [Alias('ComparePrevOffset')] [int] $ComparePreviousOffset, [switch] $ExcludeSparklines, [switch] $Raw ) process { for ($BillingMonthCount = 0; $BillingMonthCount -le $PreviousMonths; $BillingMonthCount++) { $BillingDate = (Get-Date $BillingMonth).AddMonths(-$BillingMonthCount) $BillingPeriod = $BillingDate.ToString('yyyyMM') if (-not $ComparePreviousOffset) { $ComparePreviousOffset = 1 } try { $StorageConsumption = if ($PrevStorageConsumption -and $ComparePreviousOffset -eq 1) { $PrevStorageConsumption } else { Write-Progress -Activity "Getting data for billing period $BillingPeriod" -Status 'Microsoft.Storage' Get-AzConsumptionUsageDetail -BillingPeriodName $BillingPeriod | Where-Object { $_.ConsumedService -eq 'Microsoft.Storage' } } if ($ComparePrevious) { $PrevBillingDate = (Get-Date $BillingMonth).AddMonths( - ($ComparePreviousOffset + $BillingMonthCount)) $PrevBillingPeriod = $PrevBillingDate.ToString('yyyyMM') $PrevStorageConsumption = Get-AzConsumptionUsageDetail -BillingPeriodName $PrevBillingPeriod | Where-Object { $_.ConsumedService -eq 'Microsoft.Storage' } Write-Progress -Activity "Getting data for previous billing period $PrevBillingPeriod" -Status 'Microsoft.Storage' } if (-not $AccountName) { $AccountName = ($StorageConsumption.InstanceName | Sort-Object -Unique) } foreach ($Name in $AccountName) { $Consumption = $null $PrevConsumption = $null $Consumption = $StorageConsumption | Where-Object { $_.InstanceName -eq $Name } $CostInstance = $Consumption | Where-Object { $_.InstanceId } | Select-Object -First 1 if ($CostInstance) { $Currency = $CostInstance.Currency $InstanceIdArray = $CostInstance.InstanceId -split '/' $ResourceGroupName = if ($InstanceIdArray.count -ge 4) { $InstanceIdArray[4] } else { $null } } else { $Currency = $null $ResourceGroupName = $null } $Cost = ($Consumption | Measure-Object -Property PretaxCost -Sum).Sum $DailyCost = Get-DailyCost -Consumption $Consumption $DailyCostCalc = $DailyCost.Cost | Measure-Object -Maximum -Minimum -Average -Sum $CostPerProduct = Get-StorageProductCost -Consumption $Consumption if (Test-PSparklinesModule -and -not $ExcludeSparklines) { $CostSparkLine = if ($DailyCost.Count -gt 1) { Get-Sparkline $DailyCost.Cost -NumLines $SparkLineSize | Write-Sparkline } } $CostObject = [ordered]@{ PSTypeName = 'Storage.Cost' StorageAccountName = $Name ResourceGroupName = $ResourceGroupName SubscriptionName = $CostInstance.SubscriptionName BillingPeriod = $BillingPeriod Currency = $Currency Cost = [math]::Round($Cost, 2) DailyCost_SparkLine = ($CostSparkLine -join "`n") DailyCost_Min = [math]::Round(($DailyCostCalc).Minimum, 2) DailyCost_Max = [math]::Round(($DailyCostCalc).Maximum, 2) DailyCost_Avg = [math]::Round(($DailyCostCalc).Average, 2) MostExpensive_Date = ($DailyCost | Sort-Object Cost -Descending | Select-Object -First 1).Date LeastExpensive_Date = ($DailyCost | Sort-Object Cost | Select-Object -First 1).Date DailyCost = $DailyCost CostPerProduct = $CostPerProduct } if ($ExcludeSparklines) { $CostObject.Remove('DailyCost_SparkLine') $CostObject['PSTypeName'] = 'Storage.CostNoSparkLines' } if ($ComparePrevious) { $PrevConsumption = $PrevStorageConsumption | Where-Object { $_.InstanceName -eq $Name } if ($PrevConsumption) { $PrevCost = ($PrevConsumption | Measure-Object -Property PretaxCost -Sum).Sum } else { $PrevCost = $null } $PrevDailyCost = Get-DailyCost -Consumption $PrevConsumption $PrevDailyCostCalc = $PrevDailyCost.Cost | Measure-Object -Maximum -Minimum -Average -Sum $PrevCostPerProduct = Get-StorageProductCost -Consumption $PrevConsumption $CostChange = $Cost - $PrevCost if ($PrevCost -gt 0) { $ChangePct = $CostChange / $PrevCost } else { $ChangePct = $null } $DailyCostChange = Get-DailyCostChange -DailyCost $DailyCost -PrevDailyCost $PrevDailyCost -ComparePreviousOffset $ComparePreviousOffset if (Test-PSparklinesModule -and -not $ExcludeSparklines) { $PrevCostSparkLine = if ($PrevDailyCost.Count -gt 1) { Get-Sparkline $PrevDailyCost.Cost -NumLines $SparkLineSize | Write-Sparkline } } $ComparePreviousCostObject = [ordered]@{ PrevBillingPeriod = $PrevBillingPeriod PrevCost = [math]::Round($PrevCost, 2) PrevDailyCost_SparkLine = ($PrevCostSparkLine -join "`n") PrevDailyCost_Min = [math]::Round(($PrevDailyCostCalc).Minimum, 2) PrevDailyCost_Max = [math]::Round(($PrevDailyCostCalc).Maximum, 2) PrevDailyCost_Avg = [math]::Round(($PrevDailyCostCalc).Average, 2) PrevMostExpensiveDate = ($DailyCost | Sort-Object Cost -Descending | Select-Object -First 1).Date PrevLeastExpensiveDate = ($DailyCost | Sort-Object Cost | Select-Object -First 1).Date PrevDailyCost = $PrevDailyCost PrevCostPerProduct = $PrevCostPerProduct CostChange = [math]::Round($CostChange, 2) CostChange_Pct = "{0:p2}" -f $ChangePct DailyCostChange = $DailyCostChange } if ($ExcludeSparklines) { $ComparePreviousCostObject.Remove('PrevDailyCost_SparkLine') $CostObject['PSTypeName'] = 'Storage.Cost.ComparePrevNoSparklines' } else { $CostObject['PSTypeName'] = 'Storage.Cost.ComparePrev' } $CostObject += $ComparePreviousCostObject } if ($Raw) { $RawCostObject = [ordered]@{ Consumption_Raw = $Consumption } $CostObject += $RawCostObject } if ($ComparePrevious -and $Raw) { $PrevRawCostObject = [ordered]@{ PrevConsumption_Raw = $PrevConsumption } $CostObject += $PrevRawCostObject } [pscustomobject]$CostObject } } catch { Write-Error $_ } } } } |