Table of Contents
Use PowerShell and the Audit Log to Find Targeted Accounts in Teams Memberships
A request came into the Office 365 Technical Discussions Facebook group for a way to monitor member additions to teams. The idea is that if a team owner adds an account with a specific attribute in the display name, something picks up the addition and notifies someone that the action happened.
PowerShell is the normal way to answer questions of this nature. That is, if you can get at the data. In this instance, the unified audit log captures events for team membership additions, so the raw data exists, even if a little manipulation is necessary to extract the information we need (thankfully, the needed manipulation is less than in other scenarios, such as tracking updates for properties of user accounts).
Specifying User Accounts to Monitor in Teams Memberships
The first thing to do is identify the set of users to check for. The original request didn’t specify what kind of attribute to look for in the display name, so the solution outlined here assumes that it’s a string after the combination of first name and last name. For instance, “Tom Smith (Project Management).”
Identifying the accounts to monitor is a key part of the solution. Here’s the code to use the Get-MgUser cmdlet with the Search parameter to find licensed member accounts that include “Project” in the display name.
[array]$Users = Get-MgUser -Search "displayName:Project" -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel Eventual If (!($Users)) { Throw "No users found" }
There might be many user accounts that need to be monitored. To speed things up when we check audit records, the script creates a hash table composed of the user principal name and display name.
$UserLookup = @{} ForEach ($User in $Users) { $UserLookup.Add($User.UserPrincipalName, $User.DisplayName) }
Searching the Audit Log for Additions to Teams Memberships
Next, the script calls the Search-UnifiedAuditLog cmdlet to look for MemberAdded events generated by Teams over the past seven days:
$StartDate = (Get-Date).AddDays(-7) $EndDate = (Get-Date).AddDays(1) [array]$Records = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Formatted -ResultSize 5000 -RecordType MicrosoftTeams -Operations MemberAdded
To check the audit events, the script converts the AuditData property for each event from JSON and examines what’s stored in the Members property (an array). For each item in Members, the script looks up the hash table to see if the account is monitored, and if so, captures details of the event in a list:
$Report = [System.Collections.Generic.List[Object]]::new() ForEach ($Rec in $Records) { $Role = $Null $AuditData = $Rec.AuditData | ConvertFrom-Json # Check the members noted as added to a group ForEach ($Member in $AuditData.Members) { If ($UserLookup[$Member.Upn]) { Write-Host ("User {0} added to team {1}" -f $Member.DisplayName, $AuditData.TeamName) Switch ($Member.Role) { "1" { $Role = "Member" } "2" { $Role = "Owner"} "3" { $Role = "Guest" } } $ReportLine = [PSCustomObject]@{ Date = $AuditData.CreationTime User = $Member.Upn Name = $Member.DisplayName Team = $AuditData.TeamName Role = $Role AddedBy = $AuditData.UserId } $Report.Add($ReportLine) } } }
Here’s an example of the output:
Date : 20/08/2023 12:12:55 User : Hans.Geering@office365itpros.com Name : Hans Geering (Project Management) Team : Office 365 Adoption Role : Member AddedBy : Tony.Redmond@office365itpros.com
Sharing the Results
To share the results, we send email from a shared mailbox. This action requires the Mail.Send.Shared Graph permission and uses the Send-MgUsermail cmdlet using a variety of the code explained in this article. Figure 1 shows an example of an email sent to the designated recipient (which should probably be a distribution list in production) to report results.

Posting the information to a Teams channel is another way to sharing details about new membership additions. Another option is to upload the file to a SharePoint Online document library, a topic explored in this article when Azure Automation runs a script to create content like a report. Monitoring for changes in a Microsoft 365 tenant is the kind of task that is well suited to Azure Automation, and it’s the way that I would go in production.
You can download the sample script from GitHub. Feel free to change (hopefully improve) the code.
Learn about using the Graph SDK, the unified audit log, and the rest of Office 365 by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand what’s important and how best to protect your tenant.