Monitoring administrative activities is crucial for ensuring the security and compliance of your Microsoft 365 environment. Admins frequently perform sensitive actions such as updating user roles, adding new groups, and consenting to applications, all of which should be logged and monitored. This article demonstrates how to use Microsoft Graph PowerShell to track these activities by logging admin operations from the Azure AD audit logs. We will walk through a custom script that provides detailed logging of admin activities, including the time of the event, the admin’s email, the operation performed, and the admin’s role.
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "AuditLog.Read.All" "Directory.Read.All"
# Query Directory Audit Logs (retrieve all logs)
$adminAuditLogs = Get-MgAuditLogDirectoryAudit -All
# If logs are retrieved, display the total count and preview the data structure
Write-Host "Total Logs Retrieved: $($adminAuditLogs.Count)" -ForegroundColor Green
# Create a table for logging admin activities
$logTable = @()
# Loop through the logs and extract relevant information
foreach ($log in $adminAuditLogs) {
# Get admin email
$adminEmail = $log.initiatedBy.user.userPrincipalName
# Check if the adminEmail exists and activity is initiated by a user
if ($adminEmail) {
# Get admin role, handling missing role data
$adminRole = if ($log.initiatedBy.user.roles) {
$log.initiatedBy.user.roles -join " "
} else {
"Role Not Found"
}
# Define the operation carried out
$operation = $log.activityDisplayName
# Capture the event time, handle cases where it's missing
$eventTime = if ($log.activityDateTime) {
$log.activityDateTime
} else {
"Event Time Not Found"
}
# Store the result in the table
$logTable += [pscustomobject]@{
'Event Time' = $eventTime
'Admin Email' = $adminEmail
'Operation' = $operation
'Admin Role' = $adminRole
}
}
}
# Output the table in a readable format if data exists
if ($logTable.Count -gt 0) {
$logTable | Format-Table -AutoSize
} else {
Write-Host "No admin activities found." -ForegroundColor Red
AuditLog.Read.All and Directory.Read.All), which grant permission to read audit logs and directory data.Get-MgAuditLogDirectoryAudit cmdlet retrieves all directory audit logs. Instead of filtering logs directly in the query, we retrieve them all and filter locally within the script.userPrincipalName property identifies the admin who initiated the action.roles property exists and joins any available roles into a string for output.activityDisplayName property.activityDateTime property with a fallback for missing data.Format-Table.You need one of the following delegated or application permissions:
AuditLog.Read.All (recommended for admin tracking)Directory.Read.All (for limited visibility)Ensure that admin consent is granted for your app registration before running the cmdlet.
Yes. You can use the -Filter parameter with conditions like:
Get-MgAuditLogDirectoryAudit -Filter "initiatedBy/user/displayName eq 'Alex Wilber'"
This returns all actions initiated by a particular admin.
Audit logs are typically retained for 90 days by default in Microsoft 365.
For extended retention (up to 1 year or more), you need a Microsoft 365 E5 or Audit Add-on license.
This can happen due to API throttling or missing permissions. Try rerunning the query using pagination ($skiptoken) or the -All parameter, and ensure the account used has proper audit access rights.
activityDateTime property.$startDate = (Get-Date).AddDays(-7)
$adminAuditLogs = Get-MgAuditLogDirectoryAudit -All | Where-Object { $_.activityDateTime -ge $startDate }
$logTable | Export-Csv -Path "C:\path\to\admin_activities.csv" -NoTypeInformation
| Error | Cause | Solution |
| Empty Role or Email | Some logs might not include roles or userPrincipalName, leading to incomplete records. |
The script accounts for missing roles and emails by using fallback values ("Role Not Found" or "Email Not Found"). |
| Insufficient Permissions | The account running the script does not have the required permissions (AuditLog.Read.All or Directory.Read.All). |
Ensure that the user account has been granted these permissions in Azure AD or connect using an account with Global Admin privileges. |
| No Data Returned | No logs are returned, possibly due to no recent admin activity or an incorrect scope. | Verify recent admin activities and ensure the correct scopes are provided when connecting to Microsoft Graph. |
Get-MgAuditLogDirectoryAudit, narrow results to high-risk actions (e.g., add/remove role assignments) and high-privilege roles. This helps you spotlight sensitive changes made by Global/Privileged admins.
Get-MgAuditLogDirectoryAudit -All | Select-Object Id, ActivityDisplayName, Category, ActivityDateTime, InitiatedBy | Export-Csv "C:\AdminActivity\DirectoryAudit_Weekly.csv" -NoTypeInformation
Tracking admin activities is essential for maintaining a secure and compliant Microsoft 365 environment. This PowerShell script provides a simple yet effective way to log administrative actions using Microsoft Graph. By regularly monitoring these logs, you can keep track of critical changes, detect unusual behavior, and ensure that all actions taken by administrators are properly recorded.
With further enhancements, this script can become a powerful tool for automating audit log management and ensuring the security of your M365 environment.
© m365corner.com. All Rights Reserved. Design by HTML Codex