Get-WhoAssignedUser
Ever wondered who assigned permission directly to a user in a SharePoint site? This script searches the Microsoft 365 unified audit log for "AddedToGroup" events on a specific SharePoint site, scoped to a specific user, to answer a common access-review question: who added this person to a SharePoint group, and when. It's built for exactly that question rather than general audit log exploration — point it at a site and a user, and it returns a sorted list of matching group-membership events with the actor, the site, the target user, and the raw event detail, which usually names the SharePoint group itself.
Purpose
- Connects to Exchange Online PowerShell, where
Search-UnifiedAuditLoglives - Searches the unified audit log for
AddedToGroupevents over the last 180 days, scoped server-side to the target site via-ObjectIdsand to the target user via-FreeText - Parses each matching record's
AuditDataJSON into a flat object: date, actor, site, target user, and the raw event detail - Re-filters client-side on the site URL as a second check, then sorts the results chronologically
Scope
- Only catches the
AddedToGroupoperation — group membership additions. It won't surface permissions granted via a direct sharing link or an item-level permission grant that doesn't go through a SharePoint group -FreeTextis a free-text match against the whole audit record, not a precise field match — use the person's UPN or exact display name to cut down on false matches, and double-checkDetailon anything that looks borderline- The lookback window is hardcoded to 180 days; if your tenant's audit log retention is shorter, older events won't be there to find, and if it's longer (Audit Premium / E5), this script won't look back far enough on its own — adjust
-StartDateif needed -ResultSizeis capped at 5000, the maximumSearch-UnifiedAuditLogallows in a single call — unlikely to be hit for one site and one user, but a very broad$sitevalue could run into it- Requires unified audit logging to be enabled for the tenant and the records to still be within the retention window — events outside it are gone, not just unsearched
Prerequisites
ExchangeOnlineManagementPowerShell module installed- Audit Logs or View-Only Audit Logs role in the Microsoft Purview compliance portal, to run
Search-UnifiedAuditLog - The target SharePoint site URL and a precise identifier (UPN or exact display name) for the user being searched for
PowerShell Script
<#
.SYNOPSIS
Searches the Microsoft 365 unified audit log for "AddedToGroup" events
on a specific SharePoint site, scoped to a specific user, to find who
added that user to a SharePoint group and when.
#>
Connect-ExchangeOnline
$user = "" # UPN or exact display name of the user to search for
$site = "" # SharePoint site URL (or prefix) to scope the search to
$results = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-180) -EndDate (Get-Date) `
-Operations "AddedToGroup" -ObjectIds "$site*" -FreeText $user -ResultSize 5000
$results | ForEach-Object {
$d = $_.AuditData | ConvertFrom-Json
[pscustomobject]@{
Date = $_.CreationDate
Actor = $_.UserIds # who performed the add
Site = $d.SiteUrl
Target = $d.TargetUserOrGroupName # should match $user
Detail = $d.EventData # contains the SharePoint group name
}
} | Where-Object { $_.Site -like "$site*" } | Sort-Object Date
Usage Notes
$useris matched as free text against the whole audit record, not a specific field — the person's UPN or exact display name gives the most reliable match$sitescopes the search twice: once server-side via a wildcard match against-ObjectIds, and again client-side via-Where-Object, so a partial site URL works for both- The 180-day lookback is hardcoded in the
-StartDatecalculation — shorten or lengthen it depending on how far back the relevant change happened and what your tenant retains Detailholds the fullEventDataJSON string from the audit record, which is usually where the specific SharePoint group name shows up — read it in full rather than relying on the other columns aloneActoris theUserIdsvalue from the audit record — the person or service principal who performed the add- Results are sorted oldest-to-newest by
Date, so the first row is the earliest matching event in the window