mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
631 lines
32 KiB
PowerShell
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 |