Files
Cloud-20Engineering/Powershell/Lists/Azure/AlertRules.ps1
Jurjen Ladenius a226ca97ac added documetation
2025-11-03 08:12:01 +01:00

631 lines
32 KiB
PowerShell

<#
.SYNOPSIS
Exports comprehensive Azure Alert Rules inventory across all enabled subscriptions with associated action groups and configuration details.
.DESCRIPTION
This script performs a complete audit of Azure Alert Rules across multiple alert types and all enabled subscriptions.
It inventories Smart Detector Alert Rules, Scheduled Query Rules, Metric Alerts, and Activity Log Alerts,
including their associated Action Groups, receivers, and tag information.
The script processes four main types of Azure alerts:
- Smart Detector Alert Rules (Application Insights anomaly detection)
- Scheduled Query Rules (Log Analytics/KQL-based alerts)
- Metric Alert Rules (Resource metric-based alerts)
- Activity Log Alert Rules (Azure Activity Log event alerts)
For each alert rule, the script captures detailed information including:
- Alert configuration and state
- Associated Action Groups and their receivers
- Tag information for governance tracking
- Subscription and resource group context
.PARAMETER None
This script does not accept parameters. It processes all enabled Azure subscriptions accessible to the current user.
.OUTPUTS
CSV file named with timestamp pattern: "yyyy-MM-dd HHmm alert rules.csv"
Also displays results in formatted table output to console.
CSV contains columns for alert details, action group information, and governance tags.
.EXAMPLE
.\AlertRules.ps1
Exports all alert rules from all enabled subscriptions to a timestamped CSV file and displays results.
.NOTES
Author: Cloud Engineering Team
Version: 1.0
Created: 2024
Prerequisites:
- Azure PowerShell module (Az) must be installed
- User must be authenticated (Connect-AzAccount)
- Requires read permissions on Azure Monitor, Action Groups, and resource tags across all subscriptions
- Tenant ID is hardcoded and may need adjustment for different environments
Security Considerations:
- Script uses Azure access tokens for REST API authentication
- Requires permissions to read alert rules and action groups across all subscriptions
- Output file contains sensitive alerting configuration information
Performance Notes:
- Processing time varies based on number of subscriptions and alert rules
- Script processes all enabled subscriptions sequentially
- REST API calls for Smart Detector rules add processing time
Alert Types Covered:
- microsoft.alertsmanagement/smartdetectoralertrules (Application Insights anomalies)
- microsoft.insights/scheduledqueryrules (Log Analytics queries)
- Microsoft.Insights/metricAlerts (Resource metrics)
- Microsoft.Insights/ActivityLogAlerts (Activity log events)
.LINK
https://docs.microsoft.com/en-us/azure/azure-monitor/alerts/
https://docs.microsoft.com/en-us/azure/azure-monitor/alerts/action-groups
#>
#Requires -Modules Az
#Connect-AzAccount
# Get Azure access token for REST API calls (required for Smart Detector rules)
# Note: Tenant ID is hardcoded and should be updated for different environments
$access_token_secure = (Get-AzAccessToken -TenantId "e9792fd7-4044-47e7-a40d-3fba46f1cd09").Token
$access_token = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($access_token_secure))
# Set output field separator for array-to-string conversion
$ofs = ', '
<#
.SYNOPSIS
Retrieves Action Group IDs and details for Smart Detector Alert Rules using Azure Management REST API.
.DESCRIPTION
This function queries the Azure Management REST API to retrieve detailed information about Smart Detector Alert Rules,
including their associated Action Groups. Smart Detector rules are used for Application Insights anomaly detection
and require REST API calls as they're not fully supported by PowerShell cmdlets.
.PARAMETER alertRuleName
The name of the Smart Detector Alert Rule to query.
.PARAMETER resourceGroupName
The resource group containing the Smart Detector Alert Rule.
.PARAMETER subscriptionId
The subscription ID containing the alert rule.
.OUTPUTS
Returns an array of custom objects containing alert rule details and associated Action Group IDs.
.EXAMPLE
GetSmartDetectorActionGroupIds -alertRuleName "Failure Anomalies - authorization-functions-v2" -resourceGroupName "authorization" -subscriptionId "3190b0fd-4a66-4636-a204-5b9f18be78a6"
Retrieves Action Group details for the specified Smart Detector Alert Rule.
.NOTES
- Uses REST API version 2019-06-01 for Smart Detector Alert Rules
- Requires valid Azure access token for authentication
- URL-encodes alert rule names to handle special characters
#>
function GetSmartDetectorActionGroupIds {
param (
[Parameter(Mandatory = $true)]
[string] $alertRuleName,
[Parameter(Mandatory = $true)]
[string] $resourceGroupName,
[Parameter(Mandatory = $true)]
[string] $subscriptionId
)
try {
# URL-encode the alert rule name to handle special characters
$escapedAlertRuleName = [uri]::EscapeDataString($alertRuleName)
# Construct REST API URL for Smart Detector Alert Rule
$url = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/microsoft.alertsManagement/smartDetectorAlertRules/$escapedAlertRuleName`?api-version=2019-06-01"
# Create authorization header with bearer token
$head = @{ Authorization = " Bearer $access_token" }
# Execute REST API call to retrieve Smart Detector rule details
$response = Invoke-RestMethod -Uri $url -Method GET -Headers $head
# Process response and extract Action Group information
$response | ForEach-Object {
$alert = $_
# Process each Action Group associated with the alert rule
$alert.properties.actionGroups | ForEach-Object {
$actionGroup = $_
# Extract individual Action Group IDs
$_.groupIds | ForEach-Object {
[pscustomobject]@{
Id = $alert.id
Name = $alert.name
Description = $alert.properties.description
State = $alert.properties.state
Alert = $alert.properties
ActionGroups = $alert.actionGroups
ActionGroup = $actionGroup
ActionGroupId = $_
}
}
}
}
}
catch {
Write-Warning "Failed to retrieve Smart Detector Alert Rule: $alertRuleName in $resourceGroupName. Error: $($_.Exception.Message)"
return $null
}
}
<#
.SYNOPSIS
Sanitizes alert rule descriptions for CSV export by removing newline characters.
.DESCRIPTION
This utility function cleans up alert rule descriptions by replacing newline and carriage return
characters with hyphens to ensure proper CSV formatting. It also removes duplicate hyphens
that might result from the replacement process.
.PARAMETER description
The description string to sanitize. Can be null or empty.
.OUTPUTS
Returns a cleaned description string suitable for CSV export, or empty string if input is null.
.EXAMPLE
GetDecentDescription -description "Line 1`nLine 2`rLine 3"
Returns "Line 1 - Line 2 - Line 3"
.NOTES
- Handles null input gracefully
- Replaces both Unix (`n) and Windows (`r) newline characters
- Removes duplicate hyphens that may result from consecutive newlines
#>
function GetDecentDescription {
param (
[AllowEmptyString()]
[string] $description
)
# Handle null or empty descriptions
if ($null -eq $description -or $description -eq "") {
return ""
}
else {
# Replace newline characters with hyphens and clean up duplicates
return $description.Replace("`n", " - ").Replace("`r", " - ").Replace(" - - ", " - ")
}
}
# Main script execution begins
Write-Host "======================================================================================================================================================================"
Write-Host "Starting comprehensive Azure Alert Rules inventory across all enabled subscriptions."
Write-Host "======================================================================================================================================================================"
# Generate timestamped filename for CSV export
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
$fileName = ".\$date alert rules.csv"
Write-Host "Output file: $fileName"
# Retrieve all enabled Azure subscriptions
Write-Host "Retrieving enabled subscriptions..."
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
Write-Host "Found $($subscriptions.Count) enabled subscription(s) to process."
# Class definition for structured alert rule data
class AlertRule {
# Subscription and resource context
[string] $SubscriptionId = "" # Azure subscription GUID
[string] $SubscriptionName = "" # Subscription display name
[string] $Id = "" # Full Azure resource ID of the alert rule
[string] $ResourceGroupName = "" # Resource group containing the alert rule
[string] $Type = "" # Azure resource type of the alert rule
[string] $Name = "" # Alert rule name
# Alert rule configuration
[string] $Description = "" # Alert rule description (sanitized for CSV)
[string] $State = "" # Alert rule state (Enabled/Disabled)
# Action Group associations
[string] $ActionGroupId = "" # Associated Action Group resource ID
[string] $ActionGroupName = "" # Action Group name
[string] $ActionGroupResourceGroupName = "" # Resource group containing the Action Group
[string] $ActionGroupEnabled = "" # Action Group enabled status
# Action Group receiver details
[string] $ActionGroupArmRoleReceivers = "" # ARM role-based receivers (comma-separated)
[string] $ActionGroupEmailReceivers = "" # Email receivers (comma-separated)
[string] $AzureFunctionReceivers = "" # Azure Function receivers (comma-separated)
# Governance and metadata tags
[string] $Tag_Team = "" # Team responsible for the alert
[string] $Tag_Product = "" # Product/service associated with the alert
[string] $Tag_Environment = "" # Environment (dev, test, prod, etc.)
[string] $Tag_Data = "" # Data classification tag
[string] $Tag_CreatedOnDate = "" # Creation date tag
[string] $Tag_Deployment = "" # Deployment pipeline tag
}
# Pre-load all Action Groups from all subscriptions for efficient lookup
Write-Host "Pre-loading Action Groups from all subscriptions for efficient processing..."
[Microsoft.Azure.PowerShell.Cmdlets.Monitor.ActionGroup.Models.IActionGroupResource[]]$actionGroups = @()
foreach ($subscription in $subscriptions) {
Write-Host " Loading Action Groups from subscription: $($subscription.Name)"
Set-AzContext -SubscriptionId $subscription.Id | Out-Null
$actionGroups += Get-AzActionGroup
}
Write-Host "Loaded $($actionGroups.Count) Action Group(s) across all subscriptions."
Write-Host ""
# Initialize result collection for all alert rules
[AlertRule[]]$Result = @()
# Process each subscription for alert rules
foreach ($subscription in $subscriptions) {
Write-Host "======================================================================================================================================================================"
Write-Host "Processing subscription: [$($subscription.Name)] - $($subscription.Id)"
Write-Host "======================================================================================================================================================================"
# Set Azure context to current subscription
Set-AzContext -SubscriptionId $subscription.Id | Out-Null
# Process Smart Detector Alert Rules (Application Insights anomaly detection)
Write-Host "Processing Smart Detector Alert Rules..."
$smartDetectorRules = Get-AzResource -ResourceType "microsoft.alertsmanagement/smartdetectoralertrules"
Write-Host " Found $($smartDetectorRules.Count) Smart Detector Alert Rule(s)"
foreach ($smartDetectorRule in $smartDetectorRules) {
# Retrieve Action Group details for the Smart Detector rule via REST API
$actions = GetSmartDetectorActionGroupIds -alertRuleName $smartDetectorRule.Name -resourceGroupName $smartDetectorRule.ResourceGroupName -subscriptionId $subscription.Id
# Handle Smart Detector rules without Action Groups
if (($null -eq $actions) -or ($actions.Length -eq 0)) {
# Create alert rule entry without Action Group details
[AlertRule] $AlertRule = [AlertRule]::new()
$AlertRule.SubscriptionId = $subscription.Id
$AlertRule.SubscriptionName = $subscription.Name
$AlertRule.Id = $smartDetectorRule.Id
$AlertRule.Name = $smartDetectorRule.Name
$AlertRule.Type = $smartDetectorRule.ResourceType
$AlertRule.ResourceGroupName = $smartDetectorRule.ResourceGroupName
# Extract governance tags
$AlertRule.Tag_Team = $smartDetectorRule.Tags.team
$AlertRule.Tag_Product = $smartDetectorRule.Tags.product
$AlertRule.Tag_Environment = $smartDetectorRule.Tags.environment
$AlertRule.Tag_Data = $smartDetectorRule.Tags.data
$AlertRule.Tag_CreatedOnDate = $smartDetectorRule.Tags.CreatedOnDate
$AlertRule.Tag_Deployment = $smartDetectorRule.Tags.drp_deployment
$Result += $AlertRule
}
else {
# Process Smart Detector rules with Action Groups
foreach ($action in $actions) {
# Create alert rule entry with Action Group details
[AlertRule] $AlertRule = [AlertRule]::new()
# Find corresponding Action Group from pre-loaded collection
$actionGroup = $actionGroups | Where-Object { $_.id -eq [uri]::UnescapeDataString($action.ActionGroupId) }
# Populate basic alert rule information
$AlertRule.SubscriptionId = $subscription.Id
$AlertRule.SubscriptionName = $subscription.Name
$AlertRule.Id = $smartDetectorRule.Id
$AlertRule.Name = $smartDetectorRule.Name
$AlertRule.Type = $smartDetectorRule.ResourceType
$AlertRule.ResourceGroupName = $smartDetectorRule.ResourceGroupName
$AlertRule.Description = GetDecentDescription $action.Description
$AlertRule.State = $action.State
$AlertRule.ActionGroupId = $action.ActionGroupId
# Populate Action Group details if found
if ($null -ne $actionGroup) {
$AlertRule.ActionGroupName = $actionGroup.Name
$AlertRule.ActionGroupResourceGroupName = $actionGroup.ResourceGroupName
$AlertRule.ActionGroupEnabled = $actionGroup.Enabled
# Extract receiver information (convert arrays to comma-separated strings)
$AlertRule.ActionGroupArmRoleReceivers = [string] ( $actionGroup.ArmRoleReceivers | ForEach-Object { $_.Name } )
$AlertRule.ActionGroupEmailReceivers = [string] ( $actionGroup.EmailReceivers | ForEach-Object { $_.EmailAddress } )
$AlertRule.AzureFunctionReceivers = [string] ($actionGroup.AzureFunctionReceivers | ForEach-Object { $_.FunctionName } )
}
# Extract governance tags
$AlertRule.Tag_Team = $smartDetectorRule.Tags.team
$AlertRule.Tag_Product = $smartDetectorRule.Tags.product
$AlertRule.Tag_Environment = $smartDetectorRule.Tags.environment
$AlertRule.Tag_Data = $smartDetectorRule.Tags.data
$AlertRule.Tag_CreatedOnDate = $smartDetectorRule.Tags.CreatedOnDate
$AlertRule.Tag_Deployment = $smartDetectorRule.Tags.drp_deployment
$Result += $AlertRule
}
}
}
# Process Scheduled Query Rules (Log Analytics/KQL-based alerts)
Write-Host "Processing Scheduled Query Rules (Log Analytics alerts)..."
$scheduledQueryRules = Get-AzScheduledQueryRule
$scheduledQueryRulesResources = Get-AzResource -ResourceType "microsoft.insights/scheduledqueryrules"
Write-Host " Found $($scheduledQueryRules.Count) Scheduled Query Rule(s)"
foreach ($scheduledQueryRule in $scheduledQueryRules) {
# Get corresponding resource for tag information
$resource = $scheduledQueryRulesResources | Where-Object { $_.id -eq $scheduledQueryRule.Id }
# Handle Scheduled Query Rules without Action Groups
if (($null -eq $scheduledQueryRule.ActionGroup) -or ($scheduledQueryRule.ActionGroup.Length -eq 0)) {
# Create alert rule entry without Action Group details
[AlertRule] $AlertRule = [AlertRule]::new()
$AlertRule.SubscriptionId = $subscription.Id
$AlertRule.SubscriptionName = $subscription.Name
$AlertRule.Id = $scheduledQueryRule.Id
$AlertRule.Name = $scheduledQueryRule.Name
$AlertRule.Type = $scheduledQueryRule.Type
$AlertRule.ResourceGroupName = $resource.ResourceGroupName
$AlertRule.Description = GetDecentDescription $scheduledQueryRule.Description
$AlertRule.State = $scheduledQueryRule.Enabled -eq $true ? "Enabled" : "Disabled"
# Extract governance tags from the resource (note: using $resource instead of $smartDetectorRule)
$AlertRule.Tag_Team = $resource.Tags.team
$AlertRule.Tag_Product = $resource.Tags.product
$AlertRule.Tag_Environment = $resource.Tags.environment
$AlertRule.Tag_Data = $resource.Tags.data
$AlertRule.Tag_CreatedOnDate = $resource.Tags.CreatedOnDate
$AlertRule.Tag_Deployment = $resource.Tags.drp_deployment
$Result += $AlertRule
}
else {
# Process Scheduled Query Rules with Action Groups
foreach ($action in $scheduledQueryRule.ActionGroup) {
# Create alert rule entry with Action Group details
[AlertRule] $AlertRule = [AlertRule]::new()
# Find corresponding Action Group from pre-loaded collection
$actionGroup = $actionGroups | Where-Object { $_.id -eq [uri]::UnescapeDataString($action) }
# Populate basic alert rule information
$AlertRule.SubscriptionId = $subscription.Id
$AlertRule.SubscriptionName = $subscription.Name
$AlertRule.Id = $scheduledQueryRule.Id
$AlertRule.Name = $scheduledQueryRule.Name
$AlertRule.Type = $scheduledQueryRule.Type
$AlertRule.ResourceGroupName = $resource.ResourceGroupName
$AlertRule.Description = GetDecentDescription $scheduledQueryRule.Description
$AlertRule.State = $scheduledQueryRule.Enabled -eq $true ? "Enabled" : "Disabled"
$AlertRule.ActionGroupId = $action
# Populate Action Group details if found
if ($null -ne $actionGroup) {
$AlertRule.ActionGroupName = $actionGroup.Name
$AlertRule.ActionGroupResourceGroupName = $actionGroup.ResourceGroupName
$AlertRule.ActionGroupEnabled = $actionGroup.Enabled
# Extract receiver information (convert arrays to comma-separated strings)
$AlertRule.ActionGroupArmRoleReceivers = [string] ( $actionGroup.ArmRoleReceivers | ForEach-Object { $_.Name } )
$AlertRule.ActionGroupEmailReceivers = [string] ( $actionGroup.EmailReceivers | ForEach-Object { $_.EmailAddress } )
$AlertRule.AzureFunctionReceivers = [string] ($actionGroup.AzureFunctionReceivers | ForEach-Object { $_.FunctionName } )
}
# Extract governance tags from the resource
$AlertRule.Tag_Team = $resource.Tags.team
$AlertRule.Tag_Product = $resource.Tags.product
$AlertRule.Tag_Environment = $resource.Tags.environment
$AlertRule.Tag_Data = $resource.Tags.data
$AlertRule.Tag_CreatedOnDate = $resource.Tags.CreatedOnDate
$AlertRule.Tag_Deployment = $resource.Tags.drp_deployment
$Result += $AlertRule
}
}
}
# Process Metric Alert Rules (Resource metric-based alerts)
Write-Host "Processing Metric Alert Rules..."
$metricAlerts = Get-AzMetricAlertRuleV2
Write-Host " Found $($metricAlerts.Count) Metric Alert Rule(s)"
foreach ($metricAlert in $metricAlerts) {
# Handle Metric Alerts without Action Groups
if (($null -eq $metricAlert.Actions) -or ($metricAlert.Actions.Length -eq 0)) {
# Create alert rule entry without Action Group details
[AlertRule] $AlertRule = [AlertRule]::new()
$AlertRule.SubscriptionId = $subscription.Id
$AlertRule.SubscriptionName = $subscription.Name
$AlertRule.Id = $metricAlert.Id
$AlertRule.Name = $metricAlert.Name
$AlertRule.Type = $metricAlert.Type
$AlertRule.ResourceGroupName = $metricAlert.ResourceGroup
$AlertRule.Description = GetDecentDescription $metricAlert.Description
$AlertRule.State = $metricAlert.Enabled -eq $true ? "Enabled" : "Disabled"
# Extract governance tags
$AlertRule.Tag_Team = $metricAlert.Tags.team
$AlertRule.Tag_Product = $metricAlert.Tags.product
$AlertRule.Tag_Environment = $metricAlert.Tags.environment
$AlertRule.Tag_Data = $metricAlert.Tags.data
$AlertRule.Tag_CreatedOnDate = $metricAlert.Tags.CreatedOnDate
$AlertRule.Tag_Deployment = $metricAlert.Tags.drp_deployment
$Result += $AlertRule
}
else {
# Process Metric Alerts with Action Groups
foreach ($action in $metricAlert.Actions) {
# Create alert rule entry with Action Group details
[AlertRule] $AlertRule = [AlertRule]::new()
# Find corresponding Action Group from pre-loaded collection
$actionGroup = $actionGroups | Where-Object { $_.id -eq [uri]::UnescapeDataString($action.ActionGroupId) }
# Populate basic alert rule information
$AlertRule.SubscriptionId = $subscription.Id
$AlertRule.SubscriptionName = $subscription.Name
$AlertRule.Id = $metricAlert.Id
$AlertRule.Name = $metricAlert.Name
$AlertRule.Type = $metricAlert.Type
$AlertRule.ResourceGroupName = $metricAlert.ResourceGroup
$AlertRule.Description = GetDecentDescription $metricAlert.Description
$AlertRule.State = $metricAlert.Enabled -eq $true ? "Enabled" : "Disabled"
$AlertRule.ActionGroupId = $action.ActionGroupId
# Populate Action Group details if found
if ($null -ne $actionGroup) {
$AlertRule.ActionGroupName = $actionGroup.Name
$AlertRule.ActionGroupResourceGroupName = $actionGroup.ResourceGroupName
$AlertRule.ActionGroupEnabled = $actionGroup.Enabled
# Extract receiver information (convert arrays to comma-separated strings)
$AlertRule.ActionGroupArmRoleReceivers = [string] ( $actionGroup.ArmRoleReceivers | ForEach-Object { $_.Name } )
$AlertRule.ActionGroupEmailReceivers = [string] ( $actionGroup.EmailReceivers | ForEach-Object { $_.EmailAddress } )
$AlertRule.AzureFunctionReceivers = [string] ($actionGroup.AzureFunctionReceivers | ForEach-Object { $_.FunctionName } )
}
# Extract governance tags
$AlertRule.Tag_Team = $metricAlert.Tags.team
$AlertRule.Tag_Product = $metricAlert.Tags.product
$AlertRule.Tag_Environment = $metricAlert.Tags.environment
$AlertRule.Tag_Data = $metricAlert.Tags.data
$AlertRule.Tag_CreatedOnDate = $metricAlert.Tags.CreatedOnDate
$AlertRule.Tag_Deployment = $metricAlert.Tags.drp_deployment
$Result += $AlertRule
}
}
}
# Process Activity Log Alert Rules (Azure Activity Log event alerts)
Write-Host "Processing Activity Log Alert Rules..."
$activityLogAlerts = Get-AzActivityLogAlert
Write-Host " Found $($activityLogAlerts.Count) Activity Log Alert Rule(s)"
foreach ($activityLogAlert in $activityLogAlerts) {
# Handle Activity Log Alerts without Action Groups
if (($null -eq $activityLogAlert.ActionGroup) -or ($activityLogAlert.ActionGroup.Length -eq 0)) {
# Create alert rule entry without Action Group details
[AlertRule] $AlertRule = [AlertRule]::new()
$AlertRule.SubscriptionId = $subscription.Id
$AlertRule.SubscriptionName = $subscription.Name
$AlertRule.Id = $activityLogAlert.Id
$AlertRule.Name = $activityLogAlert.Name
$AlertRule.Type = $activityLogAlert.Type
$AlertRule.ResourceGroupName = $activityLogAlert.ResourceGroupName
$AlertRule.Description = GetDecentDescription $activityLogAlert.Description
$AlertRule.State = $activityLogAlert.Enabled -eq $true ? "Enabled" : "Disabled"
# Extract governance tags
$AlertRule.Tag_Team = $activityLogAlert.Tags.team
$AlertRule.Tag_Product = $activityLogAlert.Tags.product
$AlertRule.Tag_Environment = $activityLogAlert.Tags.environment
$AlertRule.Tag_Data = $activityLogAlert.Tags.data
$AlertRule.Tag_CreatedOnDate = $activityLogAlert.Tags.CreatedOnDate
$AlertRule.Tag_Deployment = $activityLogAlert.Tags.drp_deployment
$Result += $AlertRule
}
else {
# Process Activity Log Alerts with Action Groups
foreach ($action in $activityLogAlert.ActionGroup) {
# Create alert rule entry with Action Group details
[AlertRule] $AlertRule = [AlertRule]::new()
# Find corresponding Action Group from pre-loaded collection
$actionGroup = $actionGroups | Where-Object { $_.id -eq [uri]::UnescapeDataString($action.Id) }
# Populate basic alert rule information
$AlertRule.SubscriptionId = $subscription.Id
$AlertRule.SubscriptionName = $subscription.Name
$AlertRule.Id = $activityLogAlert.Id
$AlertRule.Name = $activityLogAlert.Name
$AlertRule.Type = $activityLogAlert.Type
$AlertRule.ResourceGroupName = $activityLogAlert.ResourceGroupName
$AlertRule.Description = GetDecentDescription $activityLogAlert.Description
$AlertRule.State = $activityLogAlert.Enabled -eq $true ? "Enabled" : "Disabled"
$AlertRule.ActionGroupId = $action.Id
# Populate Action Group details if found
if ($null -ne $actionGroup) {
$AlertRule.ActionGroupName = $actionGroup.Name
$AlertRule.ActionGroupResourceGroupName = $actionGroup.ResourceGroupName
$AlertRule.ActionGroupEnabled = $actionGroup.Enabled
# Extract receiver information (convert arrays to comma-separated strings)
$AlertRule.ActionGroupArmRoleReceivers = [string] ( $actionGroup.ArmRoleReceivers | ForEach-Object { $_.Name } )
$AlertRule.ActionGroupEmailReceivers = [string] ( $actionGroup.EmailReceivers | ForEach-Object { $_.EmailAddress } )
$AlertRule.AzureFunctionReceivers = [string] ($actionGroup.AzureFunctionReceivers | ForEach-Object { $_.FunctionName } )
}
# Extract governance tags
$AlertRule.Tag_Team = $activityLogAlert.Tags.team
$AlertRule.Tag_Product = $activityLogAlert.Tags.product
$AlertRule.Tag_Environment = $activityLogAlert.Tags.environment
$AlertRule.Tag_Data = $activityLogAlert.Tags.data
$AlertRule.Tag_CreatedOnDate = $activityLogAlert.Tags.CreatedOnDate
$AlertRule.Tag_Deployment = $activityLogAlert.Tags.drp_deployment
$Result += $AlertRule
}
}
}
Write-Host "Completed processing subscription: $($subscription.Name)"
Write-Host ""
}
# Export results and display summary
Write-Host "======================================================================================================================================================================"
Write-Host "Exporting results and generating summary..."
Write-Host "======================================================================================================================================================================"
# Export comprehensive alert rules data to CSV
$Result | Export-Csv -Path $fileName -NoTypeInformation -Force
# Generate summary statistics
$summaryStats = @{
TotalAlertRules = $Result.Count
SmartDetectorRules = ($Result | Where-Object { $_.Type -eq "microsoft.alertsmanagement/smartdetectoralertrules" }).Count
ScheduledQueryRules = ($Result | Where-Object { $_.Type -eq "microsoft.insights/scheduledqueryrules" }).Count
MetricAlerts = ($Result | Where-Object { $_.Type -eq "Microsoft.Insights/metricAlerts" }).Count
ActivityLogAlerts = ($Result | Where-Object { $_.Type -eq "Microsoft.Insights/ActivityLogAlerts" }).Count
EnabledRules = ($Result | Where-Object { $_.State -eq "Enabled" }).Count
DisabledRules = ($Result | Where-Object { $_.State -eq "Disabled" }).Count
RulesWithActionGroups = ($Result | Where-Object { $_.ActionGroupId -ne "" }).Count
RulesWithoutActionGroups = ($Result | Where-Object { $_.ActionGroupId -eq "" }).Count
}
Write-Host "Alert Rules Inventory Summary:"
Write-Host "==============================="
Write-Host "Total Alert Rules Found: $($summaryStats.TotalAlertRules)"
Write-Host ""
Write-Host "By Alert Type:"
Write-Host " Smart Detector Rules: $($summaryStats.SmartDetectorRules)"
Write-Host " Scheduled Query Rules (Log Analytics): $($summaryStats.ScheduledQueryRules)"
Write-Host " Metric Alert Rules: $($summaryStats.MetricAlerts)"
Write-Host " Activity Log Alert Rules: $($summaryStats.ActivityLogAlerts)"
Write-Host ""
Write-Host "By State:"
Write-Host " Enabled Rules: $($summaryStats.EnabledRules)"
Write-Host " Disabled Rules: $($summaryStats.DisabledRules)"
Write-Host ""
Write-Host "By Action Group Association:"
Write-Host " Rules with Action Groups: $($summaryStats.RulesWithActionGroups)"
Write-Host " Rules without Action Groups: $($summaryStats.RulesWithoutActionGroups)"
Write-Host ""
Write-Host "Results exported to: $fileName"
Write-Host "======================================================================================================================================================================"
# Display formatted table output to console
Write-Host ""
Write-Host "Detailed Alert Rules (displaying first 50 rows):"
$Result | Select-Object -First 50 | Format-Table -AutoSize