Add Azure Monitor alerts using PowerShell

Hey Geeks! Today I’ve got for you PowerShell script to add Azure Monitor alerts.

For people who tries to add Azure Monitor alerts using PowerShell AZ module probably now think why I prepare separate script for that. Basically in Az module is one command to do that so it’s quite easy. But what in case that requirement is to use AzureRM module? Now it’s a little bit complicated as there is no command for it and we need to use Azure API in order to send proper request. In previous article I showed you function to generate Azure access token which will be very usefull for us in this script. Let me describe step by step how script works.

HOW SCRIPT WORKS?

As an input scipt requires 5 parameters

  • Subscription ID
  • Action Group Name
  • Log Analytics Name
  • Log Analytics Resource Group Name
  • Alerts definition

Alerts defintion was defined directly inside script to simplify input processing (of course you can change it). Please define query carrefully at it required additional escaping for special characters to be used. There can be multiple alerts if needed, you must only preoprly add it to $alerts variable

Once all parameters are provided script is gathering Azure access token – remember to be logged already in to Azure otherwise script will fail. Next it’s checking if provided Action Group and Log Analytics exist and in case one of them is not it’s skipping request processing. Next it’s gathering all alerts from subscription, filtering if alert with provided name exist and if not it’s starting with sending request base on $body variable defintion. Once it’s completed it’s returning information if alerts was added correctly to subscription.

SCRIPT:

Param (
  [String] [Parameter(Mandatory)]$SubscriptionId = '',
  [String] [Parameter(Mandatory)]$ActionGroupName = '',
  [String] [Parameter(Mandatory)]$LogAnalyticsWorkspaceName = '',
  [String] [Parameter(Mandatory)]$LogAnalyticsWorkspaceRGName = ''
)

# IMPORTANT! During query definition remember that special characters should be escaped using "\"
$alerts = @(
  @{
    Query              = 'AzureQuota_CL | where Usage_CL >= 0.5';
    Interval           = 60;
    TimeSpan           = 60;
    Name               = "Azure Quota reached 50% percent";
    Description        = "Azure Quota 50% percent";
    Severity           = "3";
    ThresholdOperator  = "GreaterThan";
    ThresholdValue     = 0;
    CustomEmailSubject = "Quota usage at 50%";
  }
  
)

# Generate Token and prepare auth header for API
if (-not (Get-Module AzureRm.Profile)) {
  Import-Module AzureRm.Profile
}
$azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
if (-not $azureRmProfile.Accounts.Count) {
  Write-Error "Ensure you have logged in before calling this function."
}
$currentAzureContext = Get-AzureRmContext
if (!$currentAzureContext) {
  Write-Error "Ensure you have logged in before calling this function."
}

$profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureRmProfile)
Write-Debug ("Getting access token for tenant" + $currentAzureContext.Subscription.TenantId)
$token = $profileClient.AcquireAccessToken($currentAzureContext.Subscription.TenantId)


$authHeader = @{
  'Content-Type'  = 'application\json';
  'Authorization' = "Bearer $token"
}


Select-AzureRmSubscription -SubscriptionId $subscriptionId | Out-Null

# Gather information about action group
$ActionGroup = Get-AzureRmResource -Name $ActionGroupName -ResourceType "Microsoft.Insights/ActionGroups"
   
# Check if Log Analytics workspace is created
$LogAnalytics = Get-AzureRmOperationalInsightsWorkspace -Name $LogAnalyticsWorkspaceName -ResourceGroupName $LogAnalyticsWorkspaceRGName

if (!$LogAnalytics -or !$ActionGroup) {
  Write-Output "Log Analytics or Action group not found. Skipping processing on subscription $subscriptionId"
}
else {
  $ResourceGroupName = $LogAnalytics.ResourceGroupName
  $omsAlerts = Get-AzureRmResource -ResourceType "microsoft.insights/scheduledqueryrules"

  foreach ($alert in $Alerts) {
    Write-Output "Checking if alert $($alert.Name) is created in subscription $subscriptionId"
    $omsAlertExist = $omsAlerts | Where-Object Name -eq $alert.name
    if (!$omsAlertExist) {
      Write-Output "Alert $($alert.Name) does not exist in subscription $subscriptionId. Proceeding with creation..."
      $body = @"
        {
            "location": "westeurope",
            "properties": {
              "description": "$($Alert.Description)",
              "enabled": "true",
              "source": {
                "query": "$($alert.Query)",
                "dataSourceId": "$($LogAnalytics.ResourceId)"
              },
              "schedule": {
                "frequencyInMinutes": $($alert.Interval),
                "timeWindowInMinutes": $($alert.TimeSpan)
              },
              "action": {
                "odata.type": "Microsoft.WindowsAzure.Management.Monitoring.Alerts.Models.Microsoft.AppInsights.Nexus.DataContracts.Resources.ScheduledQueryRules.AlertingAction",
                "severity": "$($Alert.Severity)",
                "aznsAction": {
                  "actionGroup": [
                    "$($ActionGroup.ResourceId)"
                ],
                  "emailSubject": "$($Alert.CustomEmailSubject)",
                  "customWebhookPayload": "{}"
                },
                "trigger": {
                  "thresholdOperator": "$($alert.ThresholdOperator)",
                  "threshold": $($alert.ThresholdValue)
                }
              }
            }
          }
"@

      try {
        $result = Invoke-RestMethod `
          -Uri "https://management.azure.com/subscriptions/$subscriptionId/resourcegroups/$ResourceGroupName/providers/microsoft.insights/scheduledQueryRules/$($alert.alert.Name)?api-version=2018-04-16" `
          -UseBasicParsing `
          -Headers $authHeader `
          -ContentType "application/json" `
          -Method PUT `
          -Body $body
        
        $result
        Write-Output "Successfully added alert $($alert.Name) to subscription $subscriptionId"
      }
      catch {
        Write-Error "Unexpected error occured during adding alert in subscription $subscriptionId"
      }
    }
    else {
      Write-Output "Alert $($alert.Name) already exist in subscription $subscriptionId. Skipping..."
    }
  }
}
    

Hope that it will be usefull for some of you 😉

Enjoy!

One thought on “Add Azure Monitor alerts using PowerShell

  1. Hi,

    I would like to ask if you guys know method to check if there are any alerts in “Fired” state, if there is no workspace available/alerts and alerthistory is not stored there?

    Just to clear it out a bit, when I go to Monitor->logs–> selected scope -eq “My ResGroup” -> in table Other I cant get any result from “Alert” or “AlertHistory” tables (If I run “{AlertHistory” i get

    ” operator: Failed to resolve table or column or scalar expression named ‘AlertHistory’)

    Thanks,

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.