How to Audit Active Directory Group Memberships with PowerShell

Faris Malaeb

Read more posts by this author.

Active Directory changes occur a lot, especially the bigger an organization gets. Active Directory is a critical component for any organization; ensuring the appropriate users are members of the right groups is important. Luckily, you’ve come to the right place to audit group membership changes in Active Directory.

In this tutorial, you’ll learn how to detect group membership changes in Active Directory. You’ll do so by setting up an audit policy and using PowerShell to look for events in the Windows event log.

Let’s get at it!

Prerequisites

This article will be a hands-on tutorial. If you’d like to follow along, be sure you have the following:

  • An Active Directory domain – This tutorial will use Windows Server 2019 but domain controllers (DCs) running Windows 2008 R2 or later should work. The tutorial will be using a domain called test.local with two DCs, DC01 and DC02.
  • A domain-joined Windows PC with PowerShell installed. This tutorial will use Windows 10 with Windows PowerShell v5.1.
  • An Active Directory user account to change groups on. This tutorial will use a user account called User1.
  • A user account as a member of the Domain Admins groups in the domain.

Building and Assigning an Audit Policy

To audit group membership changes in Active Directory, you must first ensure those changes are recorded somewhere. By default, many important events are not recorded in the event log. To tell Windows to store important Active Directory group membership changes, you must define an audit policy.

An audit policy creates a set of rules that tells Windows and other services to record certain events to the Windows event log it; by default, it would not. Once created, you must then assign the audit policy via Group Policy to target machines (domain controllers in this case).

Let’s start this tutorial off by creating an audit policy to force Windows to log important group membership changes to the Windows event log.

To create a new audit policy, you must create a Group Policy Object (GPO) and define the audit policy with the GPO.

On any domain controller or any domain-joined machine with Windows Remote Administration Tools (RSAT) installed:

1. Open Group Policy Management Console (GPMC) and create a new GPO attaching it to the Domain Controllers organizational unit (OU), giving it a meaningful name, such as Audit Group Membership Changes.

2. Open the GPO and expand Computer Configuration —> Windows Settings —> Advanced Audit Policy Configuration —> Audit Policies.

Clicking on each category like Account Logon, DS Access and System, for example, will provide more granular categories in the righthand pane as you can see below.

The Path to Audit Policies
The Path to Audit Policies

3. Now, click on Account Management in the left window and open the Audit Security Group Management subcategory in the right window.

4. Enable the Configure the following audit events: box with Success and Failure. Once this audit policy is applied to a machine, it will then log all attempts at modifying the groups. In addition, it will log all successful and unsuccessful attempts, such as when a user attempts to make a change but doesn’t have permission.

Auditing Group Membership
Auditing Group Membership

5. Click OK on the Audit Security Group Management Properties box and close the GPO. You now have a GPO set up with an audit policy defined ready to go to work!

The GPO should be linked to the Active Directory Domain Controllers OU. As a result, whenever you modify the GPO, each DC in that OU should apply the policy during their typical group policy refresh process.

Auditing Group Membership Change Events with the Windows Event Viewer

Now that you’ve built the audit policy and linked it to the Domain Controllers OU, let’s make a change and test it out.

On any domain controller or any domain-joined machine with Windows Remote Administration Tools (RSAT) installed:

1. Open Active Directory Users and Computers (ADUC) and open any user account that you can test with. This tutorial will use an account called User1.

2. Click on the MemberOf tab. Here you’ll see each group that the user is a member of. Click on Add and type Enterprise Admins and click OK to add the user to the Enterprise Admins group.

Adding User1 to Enterprise Admins Group.
Adding User1 to Enterprise Admins Group

3. Now, open the Windows Event Viewer, expand Windows Logs and click on the Security event log.

Windows Event Viewer
Windows Event Viewer

In the events pane, you should see that Windows has recorded an event with an ID of 4756.

Security event
Security event

When modifying an Active Directory group, you will see one of three different events logged in the Security event log depending on the type of group modified; 4728 for a global group, 4732 for a domain-local group, and 4756 for a universal group.

4. Open the event with ID 4756, and you’ll see all of the information Windows records about this particular group membership change event.

  • Subject – the user who did the change. This will show your logged on user account name.
  • Member – the user who was affected by this change. This is User1.
  • Group – the group to which the member added. This is the Enterprise Admins group.
Event ID 4756 tracking group membership change
Event ID 4756 tracking group membership change

Auditing Group Membership Change Events with PowerShell

Now that your domain controllers are logging, group membership change events to the Windows event log, you don’t just have to use the Windows Event Viewer. You can use PowerShell too!

Are you new to working with the Windows event log and PowerShell? Get the first steps on PowerShell and Windows Event Log basics at PowerShellcenter.com.

Assuming you’re still on the DC’s desktop:

1. Open Windows PowerShell.

2. Run the Get-WinEvent cmdlet to query the Security event log looking for all events with the ID of 4756, as shown below. This command will return all group membership change events for universal groups.

Change the ID value to 4728 for global groups or 4732 for domain-local groups.

Get-WinEvent -FilterHashtable @{ Logname='Security'; ID='4756'}

The FilterHashtable parameter is a hashtable and accepts its value as a key-value pairs e.g. @{Key1='Value1' ; Key2='Value2'}.

3. If you don’t want to see changes to all Active Directory groups, limit the output using the Where-Object cmdlet by looking in the Message property for the string Enterprise Admins, as shown below.

Get-WinEvent -FilterHashtable @{ Logname='Security'; ID='4756'}  | Where-Object {$_.Message -like "Enterprise Admins"} | Format-Table -AutoSize -Wrap

PowerShell will then return all events where the Enterprise Admins group membership has changed.

Reading Security Logs related to Enterprise Admins
Reading Security Logs related to Enterprise Admins

Monitoring Active Directory Administrative Groups

In the previous section, you learned how to audit group membership changes in Active Directory for a single group. Since that went so well, why not monitor all built-in groups in Active Directory?

Identifying Default (Administrative) Active Directory Groups

Active Directory comes with a set of administrative groups. These groups can define privileged permissions for any user within. Let’s first figure out how to discover all of these administrative groups.

To find these administrative groups, you must first figure some commonality between them. That commonality is a pattern in their security identifier (SID). Each object in Active Directory has a unique security identifier (SID). Windows uses the SID rather than the group name whenever it references objects.

All Active Directory administrative security groups have a SID that always ends with fewer than 1000 called the Relevant Identifier (RID). Knowing this, you build some PowerShell code to find them.

Assuming that you still have PowerShell open on the domain controller:

1. Run the Get-ADGroup command and return only the group’s SID as shown below.

(Get-ADGroup 'Enterprise Admins').SID

You’ll see from the screenshot below the SID is broken out into two parts; the domain SID and RID.

Getting the Group SID
Getting the Group SID

The domain SID is the same for all objects in the same domain; only the RID changes.

2. Now use that same command but this time, perform a search for all groups with a RID of 1000 or less to get a full list of Active Directory administrative groups.

## Find the domain SID to use in the filter
 $LocalDomain=(Get-ADDomain).DomainSID
## Search for all AD groups ensuring the objectSID property is returned.
## Then filter the results based on the SID ending in a dash and three numbers.
 Get-ADGroup -Properties objectSid -Filter * |where {($_.ObjectSid.Value -match ("-\d{3}$")) -and ($_.Objectsid.value.length -gt $LocalDomain.Value.length)} | select name,Objectsid,GroupScope
Active Directory Security Groups SID
Active Directory Security Groups SID

Building a PowerShell Script to Audit All Administrative Group Changes

You now have the code necessary to find all administrative groups and, from a previous section, the PowerShell code necessary to query the event log. Let’s now combine these to create a handy PowerShell tool.

Open your favorite code editor, copy/paste the following script and save it. Explanations of the code are all inline.

## Create an array to save all events
[email protected]()

## Find the Domain SID to filter administrative groups
$LocalDomain=(Get-addomain).domainsid

## Define the earliest event date to search from
$dateFrom=(Get-Date).AddDays(-1)

## Find all of the AD administrative groups
$ADAdminGroups=(Get-ADGroup -Properties objectSid -Filter * |where {($_.ObjectSid.Value -match ("-\\d{3}$")) -and ($_.Objectsid.value.length -gt $LocalDomain.Value.length)}).Name

## Query the Security event log for all events with IDs 4728, 4732 or 4756
## that start from $dateFrom and end right now.
$PossibleEvents= Get-WinEvent -FilterHashtable @{id=(4728,4732,4756)
                                                logname="Security"
                                                StartTime=$dateFrom
                                                EndTime=(get-date)}

## Begin processing each Windows event found
Foreach ($Events in $PossibleEvents) {
	## Check if the event was for a membership change for an administrative group
	if ($ADAdminGroups | where {$Events.message -match $_}){
		## If so, add an object with the time of event and the details to the $EventResult array
		$Result=[pscustomObject]@{
			Date=($foreach.current).TimeCreated
			Message=($foreach.current).message
		}
    
    $EventsResult+=$Result           
	}
}
## If any events found, send an email with the event as the body
if ($EventsResult){
	Send-MailMessage -From "[email protected]" -To "[email protected]" -Body $EventsResult
}

Using this script provides details on who changed what and is a standard method in many security solutions.

Conclusion

You now have the know-how to audit group membership changes in Active Directory using PowerShell. How will you use the aforementioned script? How can you improve upon it to help your organization audit group membership changes in Active Directory?

Subscribe to Stay in Touch

Never miss out on your favorite ATA posts and our latest announcements!

Looks like you're offline!