Monitor and Report Additions to Teams Membership

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 -SessionCommand ReturnLargeSet
$Records = $Records | Sort-Object Identity -Unique

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.

Email to report additions made to Teams memberships
Figure 1: Email to report additions made to Teams memberships

Posting the information to a Teams channel is another way to share 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.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.