Monitoring updates to user accounts in Microsoft 365 (M365) is crucial for maintaining security and compliance in any organization. Changes to user accounts, such as profile updates or password changes, can impact the overall security posture, and it’s important to track who is making these changes and when. In this article, we will create a PowerShell script using the Microsoft Graph API to query Azure AD for recently updated users. The output will display the updated user's email, the admin who performed the update, the time of the update, and the result status (success or failure).
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "AuditLog.Read.All" "User.Read.All"
# Fetch all directory audits where users were updated (filter applied to activityDisplayName)
$updatedUsers = Get-MgAuditLogDirectoryAudit -Filter "activityDisplayName eq 'Update user'" -All
# Initialize an array to store results
$results = @()
# Define the cutoff date (last 30 days)
$cutoffDate = (Get-Date).AddDays(-30)
# Iterate through each log entry and capture the details
foreach ($log in $updatedUsers) {
# Only process logs that are within the last 30 days
if ([DateTime]$log.activityDateTime -ge $cutoffDate) {
# Extract the updated time
$updatedTime = $log.activityDateTime
# Extract the updated user email (target)
$updatedUser = $log.targetResources | Where-Object { $_.userPrincipalName } | Select-Object -ExpandProperty userPrincipalName
# Extract the admin who performed the update (initiated by)
$updatedBy = $log.initiatedBy.user.userPrincipalName
# Check the log's status success property or error code to determine result status
if ($log.status.success -eq $true) {
$resultStatus = "Success"
} elseif ($log.status.success -eq $false) {
$resultStatus = "Failure"
} else {
# Fallback to error code check if success property is not present
$resultStatus = if ($log.status.errorCode -eq 0) { "Success" } else { "Failure" }
}
# Add the result to the array
$results += [pscustomobject]@{
'Updated Time' = $updatedTime
'Updated User' = $updatedUser
'Updated By' = $updatedBy
'Result Status' = $resultStatus
}
}
}
# Display results in table format
$results | Format-Table -AutoSize
activityDisplayName eq 'Update user'
ensures we only capture user update events.activityDateTime
(update time) is within the last 30 days. It extracts key details such as the updated user’s email, the admin responsible for the update, and the result status.status.success
property. If this property is true, the update was successful; otherwise, it was a failure. If the property is not available, the script defaults to checking the ErrorCode
.initiatedBy.user.userPrincipalName
or targetResources.userPrincipalName
.$results | Export-Csv -Path "C:\Path\To\Output.csv" -NoTypeInformation
$cutoffDate
variable.Cause: Incorrect or unsupported filter syntax in the -Filter
parameter.
Solution: Ensure you use valid OData filters. For instance, date filtering should be done in PowerShell instead of directly in the Graph query.
Cause: Insufficient permissions granted during the connection to Microsoft Graph.
Solution: Ensure that the AuditLog.Read.All
and User.Read.All
permissions are granted. You may need admin consent for these permissions.
Cause: Some properties may not be filterable or searchable directly using the -Filter
parameter.
Solution: Test queries with supported properties and check the Microsoft Graph API documentation for any limitations.
Tracking user account updates in Microsoft 365 is an important task for security and compliance monitoring. This PowerShell script leverages Microsoft Graph to make it easy to pull audit logs and list recent updates in a structured format. With simple modifications, you can enhance the script to suit your specific needs, such as filtering by users or exporting the data for reporting purposes. Regularly running this script will give you better insight into how and when M365 accounts are being modified as well as who is making the changes.
© m365corner.com. All Rights Reserved. Design by HTML Codex