🔧 New: User Management Graph PowerShell Toolkit

Simplify user tasks like bulk creation, updates, password resets, deletions, license checks & more — all from one place.

🚀 Launch Toolkit

Audit Who Changed What in Entra ID Using Graph PowerShell (Directory Audit Logs)

Ever had a ticket like this land on your desk?

  • “Who disabled this user?”
  • “Who added members to that group?”
  • “Who granted this Entra role?”
  • “Who changed my app owners?”

In Microsoft Entra ID (Azure AD), almost every admin action is logged. The only real problem is finding the right event fast.

That’s where Directory Audit Logs help. And with Microsoft Graph PowerShell, you can query them in seconds using:

  • Get-MgAuditLogDirectoryAudit
  • Get-MgAuditLogDirectoryAuditCount

This guide shows you the exact filters, scripts, and investigation patterns admins use to answer “who changed what” without opening the portal 50 times.


What Are Directory Audit Logs in Entra ID?

Directory Audit Logs are Entra’s built-in change history. They capture actions across:

  • Users (create, delete, disable, password reset)
  • Groups (membership adds/removes, property edits)
  • Roles (role assignment changes)
  • Apps / service principals (owners, permissions, secrets)
  • Policies & directory settings

Each audit record typically includes:

  • ActivityDisplayName → what happened
  • ActivityDateTime → when it happened
  • InitiatedBy → who/what triggered it
  • TargetResources → which object was affected

Which means your three investigation questions are always answerable:

✅ Who did it?

✅ What did they do?

✅ When + to what object?


Prerequisites

  1. Install the Graph Reports module
  2. Install-Module Microsoft.Graph.Reports -Scope CurrentUser
    Import-Module Microsoft.Graph.Reports
                                                
  3. Connect with audit permissions
  4. You need the Graph permission:

    • AuditLog.Read.All
    Connect-MgGraph -Scopes "AuditLog.Read.All"

    Using app-only auth? Grant AuditLog.Read.All (Application) to your Entra app and admin-consent it.


Quick Start: Get Recent Entra Audit Events

Get-MgAuditLogDirectoryAudit

That returns the most recent logs (paged).

In small tenants it’s fine — in large tenants you’ll want filters immediately.


View the important fields neatly

Get-MgAuditLogDirectoryAudit -Top 5 |
Select-Object Id, ActivityDisplayName, Category, ActivityDateTime, LoggedByService, Result, InitiatedBy, TargetResources |Format-List
                                        

Best Filters for “Who Changed What?”

Here are the filters admins actually use in real investigations.


  1. Find everything changed by a specific user
  2. $UserId = "00000000-0000-0000-0000-000000000000"
    Get-MgAuditLogDirectoryAudit -Filter "initiatedBy/user/id eq '$UserId'"
                                                

    Perfect for “what did this admin do today?”

  3. Track changes made by an application
  4. Scheduled automation, provisioning agents, sync apps, etc.

    Get-MgAuditLogDirectoryAudit -Filter "initiatedBy/app/displayName eq 'Azure AD Cloud Sync'"
  5. Filter by category (users, groups, apps, roles)
  6. Get-MgAuditLogDirectoryAudit -Filter "category eq 'GroupManagement'"

    Useful categories you’ll see often:

    • UserManagement
    • GroupManagement
    • RoleManagement
    • ApplicationManagement
  7. Pull events after a specific time window
  8. $Since = (Get-Date).AddDays(-7).ToString("yyyy-MM-ddTHH:mm:ssZ")
    Get-MgAuditLogDirectoryAudit -Filter "activityDateTime gt $Since"
                                                
  9. Combine smart filters (fast investigation scope)
  10. $Since = (Get-Date).AddDays(-3).ToString("yyyy-MM-ddTHH:mm:ssZ")
    
    Get-MgAuditLogDirectoryAudit -Filter "
    initiatedBy/user/userPrincipalName eq 'admin@contoso.com' and
    category eq 'RoleManagement' and
    activityDateTime gt $Since"
                                                

    This narrows to role changes by one admin in the last 3 days.


Real Admin Recipes (Copy-Paste Ready)

  1. Who added or removed a member from a group?
  2. $GroupId = "11111111-1111-1111-1111-111111111111"
    $Since   = (Get-Date).AddDays(-14).ToString("yyyy-MM-ddTHH:mm:ssZ")
    
    Get-MgAuditLogDirectoryAudit -Filter "
    activityDisplayName eq 'Add member to group' and
    activityDateTime gt $Since" -All |
    Where-Object {
        $_.TargetResources.Id -contains $GroupId
    } |
    Select-Object ActivityDateTime, ActivityDisplayName,
        @{n="InitiatedBy";e={$_.InitiatedBy.User.UserPrincipalName}},
        @{n="TargetGroup";e={$_.TargetResources.DisplayName}},
        TargetResources
    

    Use this when: “Who touched this group?” tickets come in.

  3. Who disabled or deleted a user?
  4. $UserUPN = "jane@contoso.com"
    $Since   = (Get-Date).AddDays(-30).ToString("yyyy-MM-ddTHH:mm:ssZ")
    
    Get-MgAuditLogDirectoryAudit -Filter "
    category eq 'UserManagement' and
    activityDateTime gt $Since" -All |
    Where-Object {
        $_.TargetResources.UserPrincipalName -contains $UserUPN
    } |
    Select-Object ActivityDateTime, ActivityDisplayName,
        @{n="InitiatedBy";e={$_.InitiatedBy.User.UserPrincipalName}},
        Result, ResultReason
    

    Use this when: Users mysteriously “stop working.”

  5. Who assigned / removed Entra roles?
  6. $Since = (Get-Date).AddDays(-7).ToString("yyyy-MM-ddTHH:mm:ssZ")
    
    Get-MgAuditLogDirectoryAudit -Filter "
    category eq 'RoleManagement' and
    activityDateTime gt $Since" -All |
    Select-Object ActivityDateTime, ActivityDisplayName,
        @{n="InitiatedBy";e={$_.InitiatedBy.User.UserPrincipalName}},
        TargetResources
    

    Use this when: Someone suddenly has Global Admin rights.


Export a Weekly “Change History” Report

$Since = (Get-Date).AddDays(-7).ToString("yyyy-MM-ddTHH:mm:ssZ")
$Logs = Get-MgAuditLogDirectoryAudit -Filter "activityDateTime gt $Since" -All
$Logs |
Select-Object ActivityDateTime, Category, ActivityDisplayName, Result,
    @{n="InitiatedByUPN";e={$_.InitiatedBy.User.UserPrincipalName}},
    @{n="InitiatedByApp";e={$_.InitiatedBy.App.DisplayName}},
    @{n="Targets";e={($_.TargetResources | ForEach-Object {$_.DisplayName}) -join "; "}} |
Export-Csv ".\Entra-Audit-Last7Days.csv" -NoTypeInformation -Encoding UTF8
                                        

Get a Quick Log Count (Before Pulling Everything)

$Since = (Get-Date).AddDays(-1).ToString("yyyy-MM-ddTHH:mm:ssZ")
Get-MgAuditLogDirectoryAuditCount -Filter "activityDateTime gt $Since"
                                        

Use this first in large tenants to avoid surprise 20k pulls.


Common Errors + Fixes (Admin Edition)

Error Cause Solution
Insufficient privileges to complete the operation Missing AuditLog.Read.All scope. Connect-MgGraph -Scopes "AuditLog.Read.All"
Ensure the admin consent is granted.
Request_UnsupportedQuery / BadRequest Filter syntax wrong or unsupported property.
  • Start broad, then narrow
  • Use only supported fields:
  • category, activityDisplayName, activityDateTime, initiatedBy
  • Validate your quotes and operators (eq, gt, and, or)
Empty results even though changes happened
  • Action logged under a different display name
  • Retention period passed
  • Filter too strict
Pull by category/time first:
Get-MgAuditLogDirectoryAudit -Filter "category eq 'GroupManagement'" -Top 50
Then locate the right operation label.


Why This Script Pattern Belongs in Every Admin Toolkit

Directory audit logs + Graph PowerShell help you:

  • Investigate incidents fast
  • Track admin changes for governance
  • Rebuild event timelines
  • Automate compliance exports
  • Feed SIEM / Sentinel workflows

If you’re serious about tenant governance, this is a must-have reporting block.


Conclusion

With just one cmdlet, you can answer the most common Entra investigation questions:

  • Who made the change? → initiatedBy
  • What exactly changed? → activityDisplayName
  • When did it happen? → activityDateTime
  • What object was affected? → targetResources

If you’ve been depending on portal searches until now, this is your upgrade.


Did You Know? Managing Microsoft 365 applications is even easier with automation. Try our Graph PowerShell scripts to automate tasks like generating reports, cleaning up inactive Teams, or assigning licenses efficiently.

Ready to get the most out of Microsoft 365 tools? Explore our free Microsoft 365 administration tools to simplify your administrative tasks and boost productivity.

© Your Site Name. All Rights Reserved. Design by HTML Codex