public/Get-AzToolsCostSummary.ps1

function Get-AzToolsCostSummary {
    <#
    .DESCRIPTION
    .PARAMETER SubscriptionID
        Optional.
    .PARAMETER StartDate
        Optional.
        Default = 7 days ago
    .PARAMETER EndDate
        Optional.
        Default = Current date
    .PARAMETER CostMetric
        PretaxCost or UsageQuantity
        Cost metric to sum for total estimate cost
        Default = UsageQuantity
    .NOTES
        I don't know. No matter what I throw at this I don't seem to get back numbers
        that match the portal. I've tried Get-AzBilling<abcdef> cmdlets also, but none
        seem to come close to the costs in the portal. Maybe I need to inhale more paint
        fumes or eat kitty litter or something.
    #>

    [CmdletBinding()]
    param (
        [parameter()][string]$SubscriptionID,
        [parameter()][string]$StartDate = $((Get-Date).AddDays(-7).ToString('yyyy-MM-dd')),
        [parameter()][string]$EndDate = $(Get-Date).ToString('yyyy-MM-dd'),
        [parameter()][string][ValidateSet('PretaxCost','UsageQuantity')]$CostMetric = 'UsageQuantity'
    )
    try {
        Write-Verbose "Connecting to Azure..."
        if (![string]::IsNullOrWhiteSpace($SubscriptionID)) {
            [array]$azSubs = Get-AzSubscription -SubscriptionId $SubscriptionID
        } else {
            Write-Host "Getting active Subscriptions..." -ForegroundColor Cyan
            [array]$azSubs = Get-AzSubscription | Where-Object {$_.State -eq 'Enabled'}
        }
        $total = $azSubs.Count
        $counter = 1
        $curContext = Get-AzContext
        foreach ($azSub in $azSubs) {
            if ($azSub.Id -ne $curContext.Subscription.Id) {
                $null = Set-AzContext $azSub
            }
            Write-Host "Subscription $counter of $total : $($azSub.Id) - $($azSub.Name)" -ForegroundColor Cyan
            $cud = $null
            $cud = Get-AzConsumptionUsageDetail -StartDate $StartDate -EndDate $EndDate -Expand MeterDetails -ErrorAction SilentlyContinue
            if ($cud) {
                Write-Host "`tGetting ResourceTypes" -ForegroundColor Cyan
                $svcs = $cud |
                    Select-Object AccountName,ConsumedService,SubscriptionGuid,SubscriptionName,IsEstimated,PretaxCost,UsageQuantity |
                        Group-Object -Property ConsumedService | Select-Object Name,Count
                Write-Verbose "Calculating costs per resource type"
                $svcs | Foreach-Object {
                    $svcName = $_.Name
                    $svcQty  = $_.Count
                    $instances = $cud | Where-Object {$_.ConsumedService -eq $svcName}
                    $cost = $instances | Measure-Object -Property $CostMetric -Sum | Select-Object -ExpandProperty Sum
                    [pscustomobject]@{
                        Subscription    = "$($azSub.Name)"
                        SubscriptionId  = "$($azSub.Id)"
                        ConsumedService = "$svcName"
                        Instances       = "$svcQty"
                        StartDate       = "$StartDate"
                        EndDate         = "$EndDate"
                        SumTotal        = "$cost"
                    }
                }
            } else {
                Write-Host "`tNo resources or consumptions costs were returned for the time period" -ForegroundColor Magenta
            }
            $counter++
        }
    } catch {
        $msg = $_.Exception.Message
        [pscustomobject]@{
            Status   = 'Error'
            Activity = $($_.CategoryInfo.Activity -join(";"))
            Message  = $($_.Exception.Message -join(";"))
            Trace    = $($_.ScriptStackTrace -join(";"))
            RunOn    = $env:COMPUTERNAME
            RunAs    = $env:USERNAME
        }
    } finally {
        if ($curContext -and ($curContext.Subscription.Id -ne $azSub.Id)) {
            Write-Host "Restoring Azure session context" -ForegroundColor Cyan
            $null = Set-AzContext $curContext
        }
    }
}