All scripts
Azure AI 249

Get-AzureSqlDatabaseUsageReport

Reports database size, service tier, elastic pool membership, and 24 hour average CPU usage across every Azure SQL server in a subscription or a single resource group, and flags any database running hot so you catch capacity problems before they cause timeouts.

Get-AzureSqlDatabaseUsageReport.ps1
<#
.SYNOPSIS
    Reports size, tier, and CPU usage for every Azure SQL database in a subscription.

.DESCRIPTION
    Loops through every Azure SQL server, or every server in one resource
    group if you provide one, and pulls the current size, max size,
    service tier, elastic pool membership, and average CPU percent over
    the last 24 hours for each database. Results are exported to a CSV
    and any database averaging 80 percent CPU or higher is printed out
    separately so you can spot compute problems before they cause
    timeouts for users.

.PARAMETER ResourceGroupName
    Optional. Limits the report to SQL servers in this resource group.
    If omitted, every resource group in the current subscription is checked.

.PARAMETER OutputPath
    Path for the CSV report. Defaults to .\AzureSqlDatabaseUsageReport.csv
    in the current folder.

.EXAMPLE
    .\Get-AzureSqlDatabaseUsageReport.ps1 -ResourceGroupName "rg-prod-data"

.AUTHOR
    Shehryar Hassan
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory = $false)]
    [string]$ResourceGroupName,

    [Parameter(Mandatory = $false)]
    [string]$OutputPath = ".\AzureSqlDatabaseUsageReport.csv"
)

if (-not (Get-AzContext)) {
    Connect-AzAccount | Out-Null
}

$servers = if ($ResourceGroupName) {
    Get-AzSqlServer -ResourceGroupName $ResourceGroupName
} else {
    Get-AzSqlServer
}

if (-not $servers) {
    Write-Warning "No Azure SQL servers found."
    return
}

$report = [System.Collections.Generic.List[object]]::new()

foreach ($server in $servers) {
    $databases = Get-AzSqlDatabase -ResourceGroupName $server.ResourceGroupName -ServerName $server.ServerName |
        Where-Object { $_.DatabaseName -ne "master" }

    foreach ($db in $databases) {
        $avgCpu = $null
        $cpuMetric = Get-AzMetric -ResourceId $db.ResourceId -MetricName "cpu_percent" `
            -TimeGrain 01:00:00 -StartTime (Get-Date).AddHours(-24) -EndTime (Get-Date) `
            -AggregationType Average -WarningAction SilentlyContinue

        if ($cpuMetric.Data) {
            $values = $cpuMetric.Data | Where-Object { $null -ne $_.Average } | Select-Object -ExpandProperty Average
            if ($values) {
                $avgCpu = [math]::Round(($values | Measure-Object -Average).Average, 1)
            }
        }

        $maxSizeGb = [math]::Round($db.MaxSizeBytes / 1GB, 1)

        $report.Add([PSCustomObject]@{
            ServerName       = $server.ServerName
            DatabaseName     = $db.DatabaseName
            Edition          = $db.Edition
            ServiceObjective = $db.CurrentServiceObjectiveName
            ElasticPool      = $db.ElasticPoolName
            MaxSizeGB        = $maxSizeGb
            Status           = $db.Status
            AvgCpuPercent24h = $avgCpu
            Location         = $server.Location
        })
    }
}

$report | Sort-Object AvgCpuPercent24h -Descending | Export-Csv -Path $OutputPath -NoTypeInformation

$highUsage = $report | Where-Object { $_.AvgCpuPercent24h -ge 80 }
if ($highUsage) {
    Write-Host "Databases averaging 80 percent CPU or higher over the last 24 hours:" -ForegroundColor Yellow
    $highUsage | Format-Table ServerName, DatabaseName, AvgCpuPercent24h -AutoSize
}

Write-Host "Report saved to $OutputPath ($($report.Count) databases)." -ForegroundColor Green

Read it before you run it, and test in a safe tenant first.