Executive Summary
For many organizations, maintaining control over Group Policy (GPO) changes is critical, especially in environments where change control processes are inconsistently followed. Tracking GPO changes can help you monitor unexpected modifications and ensure compliance with security policies. However, one significant challenge is that GPOs are identified by GUIDs, making it difficult to track changes by name.
Earlier this year, I tackled this issue by creating a script to map GPO GUIDs to their corresponding names and monitor changes using Microsoft Sentinel and KQL. This blog outlines the steps to implement this solution, providing clarity and actionable insights into Group Policy changes in your environment.
Step 1: Collect Group Policy Information
The first step is to extract all GPO names and their GUIDs using PowerShell. Run the following command to retrieve the necessary data for your domain:
Get-GPO -All -Domain "sales.contoso.com"
This command outputs a list of GPOs and their GUIDs. The next step is to convert this data into a table format that can be used in your script. Below is an example of how to structure this table in KQL:
// DataTable for Group Policy Name and GUIDs
let GPIDs = datatable (id: int, name: string, ID: string)
[
0, "GPO0", "2f4f2c37-9860-4c65-ae06-01a7f33915e6",
1, "GPO1", "055a02fe-8e4b-4914-a8fb-16890c916e0e",
2, "GPO2", "eb71f282-760c-4cd8-8171-68c80cf6c90b",
3, "GPO3", "6c17625b-f335-4e6d-804c-c3ce0cd51ce5",
4, "GPO4", "3a029b8a-7f26-4bdb-af50-645af9a7d423",
5, "GPO5", "2fcbf2e3-6d9a-45bd-98aa-f46f40f3db57",
6, "GPO6", "ad9921f4-36b4-4a7e-bc55-cf2cb84a4303",
7, "GPO7", "0a01a6e2-d9c1-433c-9e1b-89fd316d3ed5"
];
Step 2: Write the KQL Query
Events to Track
To monitor Group Policy changes, ensure your Azure Monitor Agent (AMA) is configured to collect the following event IDs:
- 5136: Object attribute changes
- 5137: Object creation
- 5139: Object movement
- 5141: Object deletion
Building the Query
Below is the KQL script to analyze these events within the SecurityEvent table:
// Filter relevant event IDs and Group Policy changes
SecurityEvent
| where EventID in (5136, 5137, 5139, 5141)
| where EventData contains "grouppolicy"
// Parse the EventData field in XML format
| extend EvData = parse_xml(EventData)
// Extract and normalize the GUID from the event data
| extend CN_Path = tostring(parse_json(tostring(parse_json(tostring(EvData.EventData)).Data))[8].["#text"])
| extend FirstCN = split(CN_Path, ',')[0]
| extend CN_Value = tostring(split(FirstCN, '=')[1])
| extend CleanCN_Value = replace_string(tostring(CN_Value), "{", "")
| extend CleanCN_Value = replace_string(CleanCN_Value, "}", "")
| extend LowercaseCleanCN = tolower(CleanCN_Value)
// Join with the GPIDs table to map GUIDs to GPO names
| lookup kind=leftouter GPIDs on $left.LowercaseCleanCN == $right.ID
// Extract relevant information and present results
| extend
TimeGenerated,
Account,
Activity,
GroupPolicy = coalesce(name, CN_Value)
| project TimeGenerated, Account, Activity, GroupPolicy
Step 3: Insights and Automation
With this query, you can:
- Generate a report of users making changes and the corresponding GPO names.
- Set up a scheduled Analytics Rule in Microsoft Sentinel to receive alerts whenever changes are detected.
By mapping GUIDs to GPO names, this script simplifies the process of tracking Group Policy changes, making it easier to maintain security and operational efficiency in your organization.
Final Thoughts
Tracking Group Policy changes doesn’t have to be a daunting task. By combining the power of PowerShell, KQL, and Microsoft Sentinel, you can efficiently monitor changes and ensure your environment stays secure.
For the full script and additional resources, visit my GitHub repository.