Track Admin Activity in Microsoft 365 Using Graph PowerShell

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.

The Script

# 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

How the Script Works

  • Connecting to Microsoft Graph: The script begins by connecting to Microsoft Graph using the required scopes (AuditLog.Read.All and Directory.Read.All), which grant permission to read audit logs and directory data.
  • Retrieving Admin Audit Logs: The 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.
  • Processing the Logs: The script loops through each log entry and extracts the relevant information:
    • Admin Email: The userPrincipalName property identifies the admin who initiated the action.
    • Admin Role: The script checks if the roles property exists and joins any available roles into a string for output.
    • Operation: The action performed by the admin is captured using the activityDisplayName property.
    • Event Time: The script records when the activity occurred using the activityDateTime property with a fallback for missing data.
  • Output: The script stores the extracted information in a custom object and formats the output into a neat table using Format-Table.

Further Enhancements

  • Filtering by Date Range: You can modify the script to track activities within a specific date range by adding a filter on the activityDateTime property.
  • $startDate = (Get-Date).AddDays(-7)
    $adminAuditLogs = Get-MgAuditLogDirectoryAudit -All | Where-Object { $_.activityDateTime -ge $startDate }
  • Exporting to CSV: The output can be exported to a CSV file for future reference or integration with other tools.
  • $logTable | Export-Csv -Path "C:\path\to\admin_activities.csv" -NoTypeInformation

Possible Errors & Solutions

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.

Conclusion

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