Use Watchlists and a Playbook to automatically add Tasks to Incidents

Introduction

With the public preview of being able to add Tasks to Incidents is a great step forward, it seems to be missing a feature IMHO. The ability to add the tasks as part of the rule so they automatically get added to the incidents would be a great feature to have. I am not sure if this is coming in a future release or not, but one would hope.

In the meantime, this post will show you how you can do this using two watchlists and a playbook. All the code can be found in the “AddTasksToIncidents” Github repository located here.

Watchlists

There are two watchlists that make up this offering; “TaskTemplates” and “RuleTasks”. The reason I have two is that I want to be able to reuse the Task templates, rather than having to recreate the wheel each time.

As you may have guessed, “TaskTemplates” will hold the templates for the tasks. The “TaskTemplates.csv” file can be used as the template for this watchlist. I have included some sample entries to help you get started. Remember that not all of the HTML tags are supported so make sure you only those tags that are supported.

It should be noted that the rules will be applied based on the “ID” field. So, if you want the rule with “ID” 4 to show up before the rule with “ID” 3, you will need to change the rules around.

The second watchlist is “RuleTasks”. This will match the Rule’s GUID with the listing of the tasks that you want assigned to the incidents it creates. Note that in the “TaskTemplates” field, the rule IDs must be surrounded by “[]” to the column can be properly expanded in KQL.

I have included the “Export-AzSentinelAnalyticRulesToCSV.ps1” PowerShell script to help generate this file for you since it is kind of a PITA to get all the Rules’ GUIDs. BTW, this script will ignore the Fusion rule, since it is the only one that doesn’t have a GUID for an ID, but you can add that if you like.

File out the CSV files and upload them as Watchlists into your environment, making sure to use the appropriate names.

Playbook

The playbook, “CreateTaskFromWatchlist” will be kicked off when an incident is created (I am sure you know how to create the Automation rule to call this when an incident is created). It will perform a KQL query to get the needed task information, loop through that data, and create the tasks.

I added a 3-minute pause at the beginning of the playbook to give Log Analytics time to record everything so that the query will actually find data. I also added a short 10 second pause after writing each task to make sure it has time to be written before the next task is added.

This actually leads me to an interesting quirk of the “For each” loop in Logic Apps that I was not aware of before working on this project. I would run the code and for some reason, the tasks were added in an almost random order. Some were added at the exact same time as others, even with a delay added. Turns out that the “For each” action runs all the tasks in parallel. So, all the tasks were being written at pretty much the same time. If you go into settings and enable “Concurrency Control” you can control the degree of parallelism. For this playbook, I set it to 1 to basically turn it off.

You will also need to make sure that the System assigned identity used to run this playbook has “Sentinel Contributor” rights to your environment so that it can write the tasks to the incidents.

You will also need to make sure the action to run the query is configured to use your Microsoft Sentinel environment.

The KQL query that gets run is as follows. It will take the Incident, determine the rule(s) that created it (so far only the incidents created by Fusion has multiple rules associated with a single incident). For each rule ID, it will then do a join with the “RuleTasks” watchlist to see if there are any tasks associated with that rule. It will then perform another join with the “TaskTemplates” watchlist to get the needed information to create the task. This will then all be sorted by the ID number of the task so that they show up in order.

SecurityIncident
| where IncidentName == "@{triggerBody()?['object']?['name']}"
| summarize arg_max(TimeGenerated, *) by IncidentNumber
| mv-expand todynamic(RelatedAnalyticRuleIds)
| extend singleRelatedAnalyticRuleId = tostring(RelatedAnalyticRuleIds)
| join (_GetWatchlist('RuleTasks')
    | mv-expand todynamic(TaskTemplates)
    | extend singleTaskTemplate = tostring(TaskTemplates)
    | extend RuleID = tostring(RuleID))
    on $left.singleRelatedAnalyticRuleId == $right.RuleID
| project singleTaskTemplate
| join (_GetWatchlist('TaskTemplates')
    | project Title, Description, ID)
    on $left.singleTaskTemplate == $right.ID
| order by int(ID) asc
| project Title, Description

Summary

This post shows you how to automatically create task for an incident. It uses two different watchlists and a playbook to perform this action. Hope it helps.

Leave a Reply

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.