Table of Contents
New MoreRecordsAvailable Property Helps When Retrieving Large Numbers of Audit Records
Message center MC1310672 (14 May 2026) reveals a change to the way that the Search-UnifiedAuditLog cmdlet works. The change is rolling out and should be complete for worldwide commercial tenants by the end of May 2026. It’s already active in my tenant. Government cloud tenants will see the change in June 2026.
As you probably know, Search-UnifiedAuditLog is the cmdlet used to run synchronous audit log searches. A synchronous search can return a maximum of 50,000 audit records using the SessionCommand parameter to control pagination (fetching of up to 5,000 records at a time). If you need to fetch more than 50,000 audit records, use the Graph AuditLogQuery API. Although Microsoft has struggled to improve the stability and performance of the API to meet the bar for general availability, I’ve still been able to fetch nearly half a million audit records with an asynchronous audit search.
Ingesting Audit Data
Many Microsoft 365 tenants ingest audit log data into Microsoft Sentinel using the Office 365 Connector for long-term storage and better search facilities. Others export audit records to external repositories like Splunk. In these scenarios, PowerShell scripts are often used to run Search-UnifiedAuditLog to fetch audit log data that’s later processed to insert the audit data into the target repository. If your tenant does this kind of processing, you should review the change to figure out if your script code requires an update.
Tracking the Progress of Audit Log Searches
Until this change, the ResultCount property in audit log records returned by Search-UnifiedAuditLog indicated the total number of results expected from a search. Now, ResultCount holds the running count of results which is updated as the search retrieves audit records. In a nutshell, if a script depends on ResultCount to tell it how many items a search fetches, that information is now no longer valid.
To track the progress of audit log searches, scripts should now use the new AuditSearchRequestMetadata.moreRecordsAvailable property. The property is false if no further audit records are available that match the search criteria. If true, you know that all matching records have been fetched.
Microsoft says that the change improves performance and delivers better visibility into search progress. I don’t know. The cmdlet seems to be as slow as it ever was. The assertion about better visibility is, I guess, justified because a specific property is now available to indicate if additional records are available.
Testing Search-UnifiedAuditLog with Large Searches
To test how the MoreRecordsAvailable property works, I wrote some code to perform a large audit log search using the SessionCommand parameter. Basically, the code fetches pages of 5,000 audit records until no more are available up to the documented maximum of 50,000 records. The MoreRecordsAvailable property is used to break out of the loop when no more records are available.
$AllRecords = @()
$SessionId = [guid]::NewGuid()
[int]$i = 0
$StartDate = (Get-Date).AddDays(-10)
$EndDate = Get-Date
Do {
$i++
Write-Host "page " $i
[array]$Records = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -SessionId $SessionId -SessionCommand ReturnLargeSet -ResultSize 5000
If ($Records) {
# Add the set to the overall array of audit records fetched by the search
$AllRecords += $Records
Write-Host ("{0} audit records found so far…" -f $AllRecords.count)
# Any more records?
$More = ($Records[0].AuditSearchRequestMetadata | ConvertFrom-Json).moreRecordsAvailable
} Else {
$More = $false
}
} While ($More -eq $true -and $AllRecords.count -le 50000)
# Make sure records are deduplicated and sorted in date order
$AllRecords = $AllRecords | Sort-Object Identity -Unique | Sort-Object {$_.CreationDate -as [datetime]}
Write-Host ("All done {0} records found in {1} minutes." -f $AllRecords.Count, [math]::Round((New-TimeSpan -Start $EndDate).TotalMinutes,3))
Interestingly, when testing the code, it retrieved 54,127 records (Figure 1), which is more than the documented limit. After deduplication, which is needed because audit log searches return duplicates for a variety of reasons, the number reduced to 48,541. Each record has a unique identifier, so sorting by the identifier is a simple way to remove duplicates.

You should stay within the 50,000 limit to make sure that searches run smoothly. If needed, split searches into multiple jobs (separate sessions) to fetch all available records.
Here is the first record in the returned set. You can see that MoreRecordsAvailable is true.
CreationDate : 04/05/2026 00:12:44
ResultIndex : 1
ResultCount : 5752
AuditSearchRequestMetadata : {
"moreRecordsAvailable": true
}
Identity : 99899933-91ac-43f6-c7ae-08dea7165e54
When the last record is checked, MoreRecordsAavailable is false:
CreationDate : 14/05/2026 23:22:01
ResultIndex : 5752
ResultCount : 5752
AuditSearchRequestMetadata : {
"moreRecordsAvailable": false
}
Identity : aff287f5-2c78-4821-a994-97239981fc55
If MoreRecordsAvailable is true for the last record in the set, it means that the search was not able to retrieve all matching records. For example, if you run a search that finds more than the 50,000 limit, the cmdlet cannot retrieve all available records and MoreRecordsAvailable will be true. That’s a strong sign that you need to split retrieval across multiple searches.
First exposure to the new property indicates that the MoreRecordsAvailable property should be useful in specific circumstances. It won’t cure some of the other ailments of the audit system, but it is an improvement, and for that I am thankful