Updated – 13/08/2025 – The tool below has been updated to fix the incident and grouping configuration for the analytic rule template to validate the time span value in ISO 8601 format.
Updated – 06/05/2025 – The tool below has been updated to include a new option that excludes Preview and Deprecated Rule Templates from deployment and activation.
Updated – 01/05/2025 – The tool below has been updated to include a new option that allows you to exclude specific rule template names from deployment and activation.
Updated – 22/05/2024 – The tool below has been updated to include the MITRE ATT&CK “Sub techniques” for the analytic rule, which requires a preview API version in addition to the “Tactics” and “Techniques“.
Updated – 27/12/2023 – The tool below has been updated to identify all installed solutions; you need to enter and pass the name of the solution(s) [Content title] as shown in the Content Hub blade.
Updated – 25/10/2023 – The tool below has been updated to identify all installed solutions, despite the discrepancy between the solution name that you see in the Microsoft Sentinel portal and the API.
Updated – 15/10/2023 – The tool below has been updated to incorporate the recent API changes for Content Hub.
Updated – 28/07/2023 – The tool below has been updated to leverage Content Hub GA changes. The Resource Graph is being deprecated by Microsoft and replaced by the REST API.
Microsoft Sentinel comes with analytics rules built-in templates that you can turn into active analytics rules by effectively creating a copy of them – that’s what happens when you create a rule from a template.
What if you have a large number of analytics rule templates?
In this article, we will share with you how to create and enable Microsoft Sentinel Analytics Rules at scale using PowerShell. This is very useful if you have many Analytics Rule templates and you want to enable them at once; this will save thousands of mouse clicks.
Table of Contents
Introduction
Microsoft Sentinel is a cloud-native Security Information Event Management (SIEM) and Security Orchestration Automated Response (SOAR) solution. Microsoft Sentinel delivers intelligent security analytics and threat intelligence across the enterprise, providing a single solution for alert detection, threat visibility, proactive hunting, and threat response.
Microsoft Sentinel Analytics Rules templates were designed by Microsoft’s team of security experts and analysts based on known threats, common attack vectors, and suspicious activity escalation chains. Many of these templates can be customized to search for activities or filter them out, according to your needs.
Solutions in Microsoft Sentinel Content Hub provide a consolidated way to acquire Microsoft Sentinel content, like data connectors, workbooks, analytics, and automation, in your workspace with a single deployment step.
The question that often comes is, what if we have imported a solution from Content Hub that has more than 50 Analytics rules, and we need to create rules from these templates?

As you probably know, this is a tedious operation to do in the Azure and Defender portal. Let’s see how to automate this process and detect threats faster by creating and enabling the Microsoft Sentinel built-in rules at scale.
Prerequisites
To follow this article, you need to have the following:
1) Azure subscription – If you don’t have an Azure subscription, you can create a free one here.
2) Log Analytics workspace – To create a new workspace, follow the instructions to create a Log Analytics workspace.
3) Enable Microsoft Sentinel at no additional cost on an Azure Monitor Log Analytics workspace for the first 31 days, follow the instructions here. Once Microsoft Sentinel is enabled on your Azure Monitor Log Analytics workspace, every GB of data ingested into the workspace can be retained at no charge for 90 days. You need to have at least Microsoft Sentinel Contributor rights.
4) Azure PowerShell installed locally on your machine or using the Cloud Shell.
5) The Azure Resource Graph module for PowerShell. Please note that this module can be used with locally installed PowerShell, with Azure Cloud Shell, or with the PowerShell Docker image.
To install the Azure Accounts PowerShell modules on your machine, you can run the following command:
# Install and update to the latest Az PowerShell module
Install-Module -Name Az.Accounts -AllowClobber -Force
# Check Az PowerShell modules version installed
Get-Module -Name Az.Accounts -ListAvailable | Select Name, Version
6) Make sure that the solution is installed from Content Hub first before you run the script described below. However, some default Analytics rules already exist without installing any solution from Content Hub. In this case, you can also run the script by targeting the Source name that you see in the Rule Templates tab under the Analytics page as shown in the figure below.

Enable Gallery Content Analytics Rules
If you are interested in enabling and activating the default built-in rules, which are listed under the “galleryContent” as a source, then you need to use the native Microsoft Azure PowerShell – Microsoft Sentinel cmdlets (Az.SecurityInsights) in Windows PowerShell and PowerShell Core.
Here is an example of how you can enable the default Analytics Rules from the Gallery Content. Please note that for the solution(s) that you import from Content Hub, please refer to the next section.
#! Install Az Module If Needed
function Install-Module-If-Needed {
param([string]$ModuleName)
if (Get-Module -ListAvailable -Name $ModuleName) {
Write-Host "Module '$($ModuleName)' already exists, continue..." -ForegroundColor Green
}
else {
Write-Host "Module '$($ModuleName)' does not exist, installing..." -ForegroundColor Yellow
Install-Module $ModuleName -Force -AllowClobber -ErrorAction Stop
Write-Host "Module '$($ModuleName)' installed." -ForegroundColor Green
}
}
#! Install Az Security Insights Module If Needed
Install-Module-If-Needed Az.SecurityInsights
#! Install Az Accounts Module If Needed
Install-Module-If-Needed Az.Accounts
#! Check Azure Connection
Try {
Write-Verbose "Connecting to Azure Cloud..."
Connect-AzAccount -ErrorAction Stop | Out-Null
}
Catch {
Write-Warning "Cannot connect to Azure Cloud. Please check your credentials. Exiting!"
Break
}
#! For the Built-in Scheduled Analytics Rule Type, you can run the following command:
#! Get the list of all built-in Scheduled Analytics Rule Type
$scheduledRules = Get-AzSentinelAlertRuleTemplate -ResourceGroupName <RG-Name> -WorkspaceName <LogAnalytics-Name> | where Kind -EQ "Scheduled"
#! For the Built-in Microsoft Security Analytics Rule Type, you can run the following command:
#! Get the list of all built-in Microsoft Security Analytics Rule Type
$securityRules = Get-AzSentinelAlertRuleTemplate -ResourceGroupName <RG-Name> -WorkspaceName <LogAnalytics-Name> | where Kind -EQ "MicrosoftSecurityIncidentCreation"
#! For the Built-in Near Real-Time (NRT) Analytics Rule Type, you can run the following command:
#! Get the list of all built-in Near Real-Time (NRT) Analytics Rule Type
$nrtRules = Get-AzSentinelAlertRuleTemplate -ResourceGroupName <RG-Name> -WorkspaceName <LogAnalytics-Name> | where Kind -EQ "NRT"
#! For the Built-in Threat Intelligence Analytics Rule Type, you can run the following command:
#! Get the list of all built-in Threat Intelligence Analytics Rule Type
$tiRules = Get-AzSentinelAlertRuleTemplate -ResourceGroupName <RG-Name> -WorkspaceName <LogAnalytics-Name> | where Kind -EQ "ThreatIntelligence"
#! For the Built-in ML Behavior Analytics Rule Type, you can run the following command:
#! Get the list of all built-in ML Behavior Analytics Rule Type
$mlRules = Get-AzSentinelAlertRuleTemplate -ResourceGroupName <RG-Name> -WorkspaceName <LogAnalytics-Name> | where Kind -EQ "MLBehaviorAnalytics"
Let’s suppose you want to enable a specific built-in [Scheduled] – [Microsoft Defender XDR] Analytics Rule from the [Gallery Content], called “Multiple Teams deleted by a single user“, for example.
First, you need to identify the Alert Rule Template name, which is in GUID. You run the following command to get the GUID name:
#! Get the Alert GUID for "Multiple Teams deleted by a single user"
$AlertRuleTemplateName = Get-AzSentinelAlertRuleTemplate -ResourceGroupName <RG-Name> -WorkspaceName <LogAnalytics-Name> `
| where DisplayName -eq "Multiple Teams deleted by a single user"
#! Display the GUID Name
$AlertRuleTemplateName

Then you run the following PowerShell command to create and activate the “Scheduled” rule. Note that you need to pass the rule type (Kind), the rule template name (GUID), the severity, the KQL query, the frequency, and so on.
#! Create a Scheduled Analytics Rule "Multiple Teams deleted by a single user"
New-AzSentinelAlertRule -ResourceGroupName <RG-Name> -WorkspaceName <LogAnalytics-Name> `
-Kind $AlertRuleTemplateName.Kind -AlertRuleTemplateName $AlertRuleTemplateName.Name -enabled `
-Query $AlertRuleTemplateName.Query -Severity $AlertRuleTemplateName.Severity `
-DisplayName $AlertRuleTemplateName.DisplayName -QueryFrequency $AlertRuleTemplateName.QueryFrequency `
-QueryPeriod $AlertRuleTemplateName.QueryPeriod -TriggerOperator $AlertRuleTemplateName.TriggerOperator `
-TriggerThreshold $AlertRuleTemplateName.TriggerThreshold

Of course, you can build upon it and enable multiple built-in Analytics Rules from the Gallery Content. Please refer to the official documentation to see other examples of how to create or update the built-in Analytics Rule from the Gallery Content.
Enable Microsoft Sentinel Analytics Rules
This section will describe how to enable Microsoft Sentinel Analytics Rules for the solution(s) you import from Content Hub.
You have a couple of options to run the script: You can either use Azure Cloud Shell, Visual Studio Code, or Windows Terminal. The Script works with PowerShell 5.1 or PowerShell 7 (core) with the Az module.
.EXAMPLE-1
.\Set-AnalyticsRules.ps1 `
-SubscriptionId "xxxxxxxx-aaaa-bbbb-cccc-zzzzzzzzzzzz" `
-ResourceGroup "RG-Name" `
-WorkspaceName "Log-Analytics-Name" `
-SolutionName "Microsoft Entra ID" `
-enableRules Yes -Verbose
.EXAMPLE-2
.\Set-AnalyticsRules.ps1 `
-SubscriptionId "xxxxxxxx-aaaa-bbbb-cccc-zzzzzzzzzzzz" `
-ResourceGroup "RG-Name" `
-WorkspaceName "Log-Analytics-Name" `
-SolutionName "Azure SQL database" `
-enableRules Yes -Verbose
.EXAMPLE-3
.\Set-AnalyticsRules.ps1 `
-SubscriptionId "xxxxxxxx-aaaa-bbbb-cccc-zzzzzzzzzzzz" `
-ResourceGroup "RG-Name" `
-WorkspaceName "Log-Analytics-Name" `
-SolutionName "Windows Security Events" `
-enableRules Yes -Verbose
To supply the list of rule template names to exclude when running the script, you can pass the -excludeRuleTemplates parameter as an array of strings. This ensures the script receives the array of rule template names to exclude. Here’s how you can do it:
.EXAMPLE-4
.\Set-AnalyticsRules.ps1 `
-subscriptionId "xxxxxxxx-aaaa-bbbb-cccc-zzzzzzzzzzzz" `
-resourceGroupName "RG-Name" `
-workspaceName "Log-Analytics-Name" `
-solutionName "Azure Activity" `
-excludeRuleTemplates @("New CloudShell User", "Creation of expensive computes in Azure") `
-enableRules Yes -Verbose
To exclude the Preview and Deprecated Rule Templates when running the script, you can pass the -excludePreviewDeprecated parameter as a switch [Yes/No]. Here’s how you can do it:
.EXAMPLE-5
.\Set-AnalyticsRules.ps1 `
-subscriptionId "xxxxxxxx-aaaa-bbbb-cccc-zzzzzzzzzzzz" `
-resourceGroupName "RG-Name" `
-workspaceName "Log-Analytics-Name" `
-solutionName "Microsoft Entra ID" `
-excludePreviewDeprecated Yes `
-enableRules Yes -Verbose
This example will connect to your Azure account using the subscription ID specified, and then create all analytics rules from templates for the specified Microsoft Sentinel content solution name. Please note that you need to enter and pass the name of the solution(s) [Content title] as shown in the Content hub blade in the figure below (E.g. Microsoft Entra ID, Azure SQL Database, DNS Essentials, Windows Security Events, Azure Activity, SAP applications, etc.) – Case-insensitive.

By default, all of the rules will be created in a Disabled state, however, you have the option to enable the rules at creation time as well by setting the parameter (enable rules) to Yes.
Here is an example of the output once you run this tool:

PowerShell Code
Updated – 13/08/2025 – The tool below has been updated to fix the incident and grouping configuration for the analytic rule template to validate the time span value in ISO 8601 format.
Updated – 06/05/2025 – The tool below has been updated to include a new option that excludes Preview and Deprecated Rule Templates from deployment and activation.
Updated – 01/05/2025 – The tool below has been updated to include a new option that allows you to exclude specific rule template names from deployment and activation.
Updated – 22/05/2024 – The tool below has been updated to include the MITRE ATT&CK “Sub techniques” for the analytic rule, which requires a preview API version in addition to the “Tactics” and “Techniques“.
Updated – 27/12/2023 – The tool below has been updated to identify all installed solutions. You need to enter and pass the name of the solution(s) [Content title] as shown in the Content hub blade.
Updated – 25/10/2023 – The tool below has been updated to identify all installed solutions, despite the discrepancy between the solution name that you see in the Microsoft Sentinel portal and the API.
Updated – 15/10/2023 – The tool below has been updated to incorporate the recent API changes for Content Hub.
Updated – 28/07/2023 – The tool below has been updated to leverage Content Hub GA changes. The Resource Graph is being deprecated by Microsoft and replaced by the REST API.
The complete script is detailed below to automate the entire process of creating and activating the Analytics Rules content pack:
<#
.SYNOPSIS
Enable Microsoft Sentinel Analytics Rules at Scale.
.DESCRIPTION
How to create and enable Microsoft Sentinel Analytics Rules at Scale using PowerShell.
.NOTES
File Name : Set-AnalyticsRules.ps1
Author : Microsoft MVP/MCT - Charbel Nemnom
Version : 3.1
Date : 24-October-2022
Updated : 13-August-2025
Requires : PowerShell 7.4.x (Core)
Module : Az Module
.LINK
To provide feedback or for further assistance please visit:
https://charbelnemnom.com
.EXAMPLE
.\Set-AnalyticsRules.ps1 -SubscriptionId "SUB-ID" -ResourceGroup "RG-NAME" -WorkspaceName "Log-Analytics" -SolutionName "Source-Name" -enableRules [Yes] -Verbose
This example will connect to your Azure account using the subscription Id specified, and then create all analytics rules from templates for the specified Microsoft Sentinel solution.
By default, all of the rules will be created in a Disabled state, however, you have the option to enable the rules at creation time by setting the parameter -enableRules [Yes].
You also have the option to exclude specific rule templates by using the -excludeRuleTemplates parameter, and you can specify the names of the templates you want to exclude.
The "Preview" and "Deprecated" rule templates can be also excluded by setting the -excludePreviewDeprecated parameter to [Yes]. This option is set to [Yes] by default.
#>
param (
[Parameter(Position = 0, Mandatory = $true, HelpMessage = 'Enter Azure Subscription ID')]
[string]$subscriptionId,
[Parameter(Position = 1, Mandatory = $true, HelpMessage = 'Enter Resource Group Name where Microsoft Sentinel is deployed')]
[string]$resourceGroupName,
[Parameter(Position = 2, Mandatory = $true, HelpMessage = 'Enter Log Analytics Workspace Name')]
[string]$workspaceName,
[Parameter(Position = 3, Mandatory = $true, HelpMessage = 'Enter Microsoft Sentinel Content Hub Solution Name')]
[string]$solutionName,
[Parameter(Position = 4, Mandatory = $false, HelpMessage = 'Exclude Rule Templates Names i.e: @("ABC","DEF")')]
[ValidateNotNullOrEmpty()]
[array]$excludeRuleTemplates,
[Parameter(Position = 5, Mandatory = $false, HelpMessage = 'Exclude [Preview] and [Deprecated] Rule Templates [Yes/No]')]
[ValidateNotNullOrEmpty()]
[ValidateSet("Yes", "No")]
[String]$excludePreviewDeprecated = 'Yes',
[Parameter(Position = 6, Mandatory = $false, HelpMessage = 'Enable Rules at Creation Time [Yes/No]')]
[ValidateNotNullOrEmpty()]
[ValidateSet("Yes", "No")]
[String]$enableRules = 'No'
)
#! Install Az Module If Needed
function Install-Module-If-Needed {
param([string]$ModuleName)
if (Get-Module -ListAvailable -Name $ModuleName) {
Write-Host "Module '$($ModuleName)' already exists, continue..." -ForegroundColor Green
}
else {
Write-Host "Module '$($ModuleName)' does not exist, installing..." -ForegroundColor Yellow
Install-Module $ModuleName -Force -AllowClobber -ErrorAction Stop
Write-Host "Module '$($ModuleName)' installed." -ForegroundColor Green
}
}
#! Install Az Accounts Module If Needed
Install-Module-If-Needed Az.Accounts
#! Check Azure Connection
Try {
Write-Verbose "Connecting to Azure Cloud..."
Connect-AzAccount -ErrorAction Stop | Out-Null
}
Catch {
Write-Warning "Cannot connect to Azure Cloud. Please check your credentials. Exiting!"
Break
}
# Define the Preview API Version to use for Microsoft Sentinel
# The Preview API Version is needed to include the MITRE ATT&CK "Sub techniques"
$apiVersion = "?api-version=2025-01-01-preview"
# Create the authentication access token
Write-Verbose "Creating authentication access token..."
$context = Get-AzContext
if (-not $context) {
throw "No Azure context found. Please re-authenticate."
}
$tokenRequest = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id, $null, "Never", $null, "https://management.azure.com/")
if (-not $tokenRequest) {
throw "Failed to obtain access token. Please check your authentication."
}
$AzureAccessToken = $tokenRequest.AccessToken
$authHeader = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$authHeader.Add("Content-Type", "application/json")
$authHeader.Add("Authorization", "Bearer $AzureAccessToken")
# Get Content Product Packages
$contentURI = "https://management.azure.com/subscriptions/$subscriptionid/resourceGroups/$resourceGroupName/providers/Microsoft.OperationalInsights/workspaces/$workspaceName/providers/Microsoft.SecurityInsights/contentProductPackages$($apiVersion)"
$contentResponse = (Invoke-RestMethod $contentURI -Method 'GET' -Headers $authHeader).value
$solutions = $contentResponse | Where-Object { $null -ne $_.properties.version }
$solution = ($solutions | Where-Object { $_.properties.displayName -eq "$solutionName" }).properties.contentId
# Get Content Templates
$contentURI = "https://management.azure.com/subscriptions/$subscriptionid/resourceGroups/$resourceGroupName/providers/Microsoft.OperationalInsights/workspaces/$workspaceName/providers/Microsoft.SecurityInsights/contentTemplates$($apiVersion)"
$contentResponse = (Invoke-RestMethod $contentURI -Method 'GET' -Headers $authHeader).value
try {
$contentTemplates = $contentResponse | Where-Object { $_.properties.packageId -eq $solution -and $_.properties.contentKind -eq "AnalyticsRule" }
if ($contentTemplates.count -eq 0) {
throw "Solution Name: [$solutionName] cannot be found. Please check the solution name and Install it from the Content Hub blade"
}
}
catch {
Write-Error $_ -ErrorAction Stop
}
if ($excludePreviewDeprecated -eq 'Yes') {
Write-Verbose "Excluding Preview and Deprecated Rule Templates"
$contentTemplatesExcluded = $contentTemplates | Where-Object {
$_.properties.displayName -notmatch '^(Preview|Deprecated)' -and
$_.properties.displayName -notmatch '\[Preview\]' -and
$_.properties.displayName -notmatch '\[Deprecated\]'
}
if ($contentTemplatesExcluded.Count -ne $contentTemplates.Count) {
Write-Verbose "$($contentTemplates.Count - $contentTemplatesExcluded.Count) Analytic Rule(s) were excluded for: [$solutionName]"
$contentTemplates = $contentTemplatesExcluded
}
else {
Write-Verbose "No Preview and Deprecated Analytic Rules were excluded for: [$solutionName]"
}
}
if ($excludeRuleTemplates) {
Write-Verbose "Excluding Rule Templates: $($excludeRuleTemplates -join ', ')"
foreach ($ruleTemplate in $excludeRuleTemplates) {
$contentTemplates = $contentTemplates | Where-Object { $_.properties.displayname -ne "$ruleTemplate" }
}
}
Write-Verbose "$($contentTemplates.count) Analytic Rules found for: [$solutionName]"
foreach ($contentTemplate in $contentTemplates) {
$ruleName = $contentTemplate.name
$ruleTemplateURI = "https://management.azure.com/subscriptions/$subscriptionid/resourceGroups/$resourceGroupName/providers/Microsoft.OperationalInsights/workspaces/$workspaceName/providers/Microsoft.SecurityInsights/contentTemplates/$($ruleName)$($apiVersion)"
$ruleResponse = Invoke-RestMethod $ruleTemplateURI -Method 'GET' -Headers $authHeader -Verbose:$false
$ruleProperties = $ruleResponse.properties.mainTemplate.resources | Where-Object type -eq 'Microsoft.OperationalInsights/workspaces/providers/metadata' | Select-Object properties
$ruleProperties.properties = $ruleProperties.properties | Select-Object * -ExcludeProperty description, parentId
$rule = $ruleResponse.properties.mainTemplate.resources | Where-Object type -eq 'Microsoft.SecurityInsights/AlertRuleTemplates'
$rule.properties | Add-Member -NotePropertyName alertRuleTemplateName -NotePropertyValue $rule.name
$rule.properties | Add-Member -NotePropertyName templateVersion -NotePropertyValue $ruleResponse.properties.version
# Fix Grouping Configuration
if ($rule.properties.PSObject.Properties.Name -contains "incidentConfiguration") {
if ($rule.properties.incidentConfiguration.PSObject.Properties.Name -contains "groupingConfiguration") {
if (-not $rule.properties.incidentConfiguration.groupingConfiguration) {
$rule.properties.incidentConfiguration | Add-Member -NotePropertyName "groupingConfiguration" -NotePropertyValue @{
matchingMethod = "AllEntities"
lookbackDuration = "PT1H"
}
}
else {
# Ensure `matchingMethod` exists
if (-not ($rule.properties.incidentConfiguration.groupingConfiguration.PSObject.Properties.Name -contains "matchingMethod")) {
$rule.properties.incidentConfiguration.groupingConfiguration | Add-Member -NotePropertyName "matchingMethod" -NotePropertyValue "AllEntities"
}
# Ensure `lookbackDuration` is in ISO 8601 format
if ($rule.properties.incidentConfiguration.groupingConfiguration.PSObject.Properties.Name -contains "lookbackDuration") {
$lookbackDuration = $rule.properties.incidentConfiguration.groupingConfiguration.lookbackDuration
if ($lookbackDuration -match "^(\d+)(h|d|m)$") {
$timeValue = $matches[1]
$timeUnit = $matches[2]
switch ($timeUnit) {
"h" { $isoDuration = "PT${timeValue}H" }
"d" { $isoDuration = "P${timeValue}D" }
"m" { $isoDuration = "PT${timeValue}M" }
}
$rule.properties.incidentConfiguration.groupingConfiguration.lookbackDuration = $isoDuration
}
}
}
}
}
If ($enableRules -eq "Yes") {
$rule.properties.enabled = $true
}
$rulePayload = $rule | ConvertTo-Json -EnumsAsStrings -Depth 50
$ruleURI = "/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.OperationalInsights/workspaces/$workspaceName/providers/Microsoft.SecurityInsights/alertRules/$($rule.name)$($apiVersion)"
try {
$ruleResult = Invoke-AzRestMethod -Method PUT -path $ruleURI -Payload $rulePayload -Verbose:$false
If (!($ruleResult.StatusCode -in 200, 201)) {
Write-Host $ruleResult.StatusCode
Write-Host $ruleResult.Content
throw "Error when enabling Analytics rule: $($rule.properties.displayName)"
}
If ($enableRules -eq "Yes") {
Write-Verbose "Creating and Enabling Analytic rule: $($rule.properties.displayName)"
}
Else {
Write-Verbose "Creating Analytic rule: $($rule.properties.displayName)"
}
}
catch {
Write-Error $_ -ErrorAction Continue
}
If ($ruleResult.StatusCode -in 200, 201) {
$ruleResult = $ruleResult.Content | ConvertFrom-Json
$ruleProperties.properties | Add-Member -NotePropertyName parentId -NotePropertyValue $ruleResult.id
$metadataURI = "/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.OperationalInsights/workspaces/$workspaceName/providers/Microsoft.SecurityInsights/metadata/analyticsrule-$($rule.name)$($apiVersion)"
$metadataPayload = $ruleProperties | ConvertTo-Json -EnumsAsStrings -Depth 50
try {
$resultMetadata = Invoke-AzRestMethod -Method PUT -path $metadataURI -Payload $metadataPayload -Verbose:$false
if (!($resultMetadata.StatusCode -in 200, 201)) {
Write-Host $resultMetadata.StatusCode
Write-Host $resultMetadata.Content
throw "Error when updating Metadata for Analytic rule: $($rule.properties.displayName)"
}
Write-Verbose "Updating Metadata for Analytic rule: $($rule.properties.displayName)"
}
catch {
Write-Error $_ -ErrorAction Continue
}
}
}
Before running the tool, we can see that we don’t have any active rules created in the Disabled state. In this example, we have 15 Active rules only.

Once you run this tool, you can refresh the Analytics rules page and check all the rules are created in the Disabled state. In this example, we have 58 Active rules.

That’s it, there you have it. Happy Analytics Rules creation with Microsoft Sentinel!
If you have any feedback or changes that everyone should receive, please feel free to leave a comment below.
Summary
This article showed you how to create and enable Microsoft Sentinel Analytics Rules at scale using PowerShell, this is very useful if you have many Analytics Rule templates as part of a Content Hub solution and you want to enable them at once.
Analytics rules search for specific events or sets of events across your environment, alert you when certain event thresholds or conditions are reached, generate incidents for your SOC to triage and investigate, and respond to threats with automated tracking and remediation processes.
This is one of the many features in Microsoft Sentinel that can be utilized to provide immense value to threat detection out-of-the-box.
The power of Microsoft Sentinel comes from the ability to detect, investigate, respond to, and remediate threats.
__
Thank you for reading my blog.
If you have any questions or feedback, please leave a comment.
-Charbel Nemnom-
Hello Ben, thanks for the comment and reporting this issue!
Again, Microsoft has changed the API for Content hub one more time.
I have update the tool to incorporate the recent changes.
Please get a new copy (version 2.1) and let me know if it works for you.
Currently, the tool will work on most the Content hub solutions but not all of them.
I am still working on newer version, but for now it should solve your issue.
Hope it helps!
Thanks for you quick reply, I ended up tweaking the script to get all templates, it involved doing another API call to get the parameters I needed. I’ve included it below. It enabled all rules at the mo.
Hello Ben, thanks for sharing and I am happy to hear that it’s working for you now.
Yes, as I mentioned, Microsoft has recently updated their API from “
2023-06-01-preview” to “2023-07-01-preview”, and they moved the “Analytic rule template” from the “Content Templates – List” API to “Content Template – Get” API. So, the final solution require three API calls.The first API call is to get the full Content solution, the second API call is to get the Analytic rule template, and the third API call is to create the Analytic rule.
I have published the final working version to target a specific solution (source) name.
Thanks!
Hi,
Thanks for sharing the script.
I’ve been trying to use the API for bulk enabling of content pack analytic rules. However, post enabling a rule via API, the “Source Name” field on the Sentinel GUI’s Active Analytics Rules page shows “Gallery” instead of the actual content pack name.
Contrarily, when enabling a rule through the GUI, the “Source Name” field correctly displays the content pack name, like “Azure Active Directory” instead of “Gallery”.
I was curious if you’ve observed this too or have any insights on this?
On executing a GET request on an enabled rule, the response doesn’t mention the content pack source name.
Although, under Content Hub > Manage Content Pack, the rules are marked active, affirming they are linked correctly. It’s just the “Source Name” field on the analytic rules page that isn’t reflecting accurately.
Hello, thanks for the comment and for reporting this issue!
Yes, what you observed when you enabled the content pack analytic rules via the API and Sentinel’s blade does not match the “Source Name” of the content pack solution.
This is because the recent API changes by Microsoft were updated to split these operations.
I updated the tool to have a consistent experience between the API and Sentinel’s Analytics blade.
The “Source Name” field on the analytic rules page is reflecting accurately now.
Let me know if it works for you.
Hope it helps!
I tried using this script (Version : 2.3) today but it’s throwing the Solution Name cannot be found error. Noticed this version of the script is using the packageId so I tried using that but no joy.
Hello Kevin, thanks for the comment!
Could you please advise which Content hub Solution Name are you using?
I was trying the following:
Azure Active Directory
Windows Security Events
Azure SQL Database
Hello Kevin, thanks for reporting this!
The issue is resolved now. I was validating an invalid variable.
Please get a new copy for version 2.4 and it should work as expected.
You might see that the solution names in the portal are not the same in the API.
The “Azure Active Directory” is correct, for “Windows Security Events”, you need to enter “Security Events” as a Solution Name, and for “Azure SQL Database”, you need to enter “SQL” as a Solution Name.
Update: I released a new version 2.5 that will identify all solutions, despite the discrepancy between the solution name that you see in the Microsoft Sentinel portal and the API. Now you can pass the Display Name of the Solution as shown in Content Hub – Content title (E.g. Microsoft Entra ID, Windows Security Events, Azure SQL Database, SAP Applications, etc.)
Thanks!
Hi, my team tested your script and rules are created with following error: –
ConvertFrom-Json : A parameter cannot be found that matches parameter name ‘Depth’.
At C:\Users\XXX\OneDrive – XXX\Desktop\XXX\XXX\Script\AnalyticsRulesV2.5.ps1:134 char:54
+ $ruleResult = $ruleResult.Content | ConvertFrom-Json -Depth 100
+ ~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ConvertFrom-Json], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
Not a script guy, hope this comment provide insights.
Hello Amizan, thanks for the comment and for sharing the error!
Based on the error message, you need to use PowerShell 6.2 or higher version.
The “-Depth” parameter was introduced in PowerShell 6.2 and later.
Please let your team test the script in PowerShell Core 7.4 if possible.
Let me know if that works. Hope it helps!
Hi Charbel,
Thank you for the script. I’ve noticed that sub techniques are not included in rules that are enabled using this method.
Cheers
Hello Alex, thanks for your comment and for testing this tool!
You are right; the MITRE ATT&CK “Sub techniques” were not included in the analytic rules.
I have updated the tool to include now the MITRE ATT&CK “Sub techniques” for the analytic rules, which requires a preview API version in addition to the “Tactics” and “Techniques”.
Microsoft keeps changing its APIs to add and remove features. I will try to keep this tool updated with the latest changes.
Please get the latest version, 2.6, and let me know if it works for you. Thanks!
I get this error when I try to run the tool.
ConvertTo-Json : A parameter cannot be found that matches parameter name ‘EnumsAsStrings’.
At line:116 char:43
+ $rulePayload = $rule | ConvertTo-Json -EnumsAsStrings -Depth 50
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ConvertTo-Json], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.ConvertToJsonCommand
Hello Matt, thanks for the comment!
Please note that based on the error you are facing, it’s related to the PowerShell version that you are running.
I guess you are using PowerShell version 5.1. I would recommend using PowerShell Core version 7.4.x or later. The
-EnumsAsStringsparameter was introduced in PowerShell Core.I’ve just ran the tool on my side (latest version 2.6) and it’s working without any issue.
The
-EnumsAsStringsparameter provides an alternative serialization option that converts all enumerations to their string representation.Please check your PowerShell version and try again.
Hope it helps!
Charbel you are the best! Thank you so much for this as I have just used it in an engagement and got great results with it.
Thank you, dear Oguzhan, for the feedback, much appreciated!
I am running the example from the post:
.\Set-AnalyticsRules.ps1 `
-SubscriptionId “xxxxxxxx-aaaa-bbbb-cccc-zzzzzzzzzzzz” `
-ResourceGroup “RG-Name” `
-WorkspaceName “Log-Analytics-Name” `
-SolutionName “Microsoft Entra ID” `
-enableRules Yes -Verbose
But I get this error for all the rules:
400
{
“error”: {
“code”: “BadRequest”,
“message”: “The string ‘1h’ is not a valid TimeSpan value. ISO 8601 format is expected. Path ‘properties.incidentConfiguration.groupingConfiguration.lookbackDuration'”
}
}
Exception: Error when enabling Analytics rule: Conditional Access – A Conditional Access app exclusion has changed
I am running this using Azure Cloud Shell.
Hello Abhi,
Thank you for testing and reporting this issue.
Microsoft has updated the rule template for incident and grouping configuration using the wrong ISO 8601 format. I have updated the tool to version 3.1, which addresses this issue. I tested it using Azure Cloud Shell, and it is working as expected.
Please download the latest version (3.1) and let me know if it works for you.
Thanks!
Hi Charbel, thank you for the solution, It’s very helpful!
regards
David.