{"id":59301,"date":"2026-10-21T13:01:27","date_gmt":"2026-10-21T03:01:27","guid":{"rendered":"https:\/\/www.cloudproinc.com.au\/index.php\/2026\/10\/21\/a-practical-search-unifiedauditlog-migration-to-auditlogquery-api\/"},"modified":"2026-10-21T13:02:48","modified_gmt":"2026-10-21T03:02:48","slug":"a-practical-search-unifiedauditlog-migration-to-auditlogquery-api","status":"publish","type":"post","link":"https:\/\/www.cloudproinc.com.au\/index.php\/2026\/10\/21\/a-practical-search-unifiedauditlog-migration-to-auditlogquery-api\/","title":{"rendered":"A Practical Search-UnifiedAuditLog Migration to AuditLogQuery API"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In this blog post A Practical Search-UnifiedAuditLog Migration to AuditLogQuery API we will explain how to replace the retiring PowerShell command without disrupting security investigations, compliance reports or automated monitoring.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\">The immediate problem is not that Microsoft 365 will stop recording activity. It is that scripts relying on Search-UnifiedAuditLog will no longer retrieve that evidence after 15 October 2027. A failed audit script may go unnoticed until your business is investigating a compromised account, responding to a legal request or preparing for an audit.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is changing at a high level?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Microsoft 365 maintains a unified audit log containing records of important actions across Exchange Online, SharePoint, OneDrive, Teams, Microsoft Entra ID and other services. These records can show who changed an administrator setting, accessed a mailbox, shared a document or performed another monitored action.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Search-UnifiedAuditLog is a PowerShell command administrators have traditionally used to retrieve these records. Microsoft is replacing it with the Microsoft Graph AuditLogQuery API, which is a controlled way for approved applications and scripts to request audit information.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The important difference is how searches run. The old command generally waits for results during the PowerShell session. The new API creates a search job, processes it in the background and allows your automation to collect the results when the job finishes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This approach is designed for larger and more reliable searches. It also supports workload-specific permissions and exports of up to one million records per query, compared with the lower practical limits of the retiring command.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For an executive overview of the retirement risk, start with our Search-UnifiedAuditLog retirement and migration plan. This article goes a step further by showing how to structure the technical migration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why a simple command replacement will not work<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The Graph API is not a new spelling for the same PowerShell command. Authentication, permissions, query submission, status checking and result collection all work differently.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A script that currently runs one command may need to perform four actions:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create the audit search.<\/li>\n<li>Store the query identification number returned by Microsoft.<\/li>\n<li>Check the query until its status changes to succeeded or failed.<\/li>\n<li>Download every page of results and send them to the required report, archive or security platform.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Missing any of these steps can produce incomplete evidence. A script might create a valid search but never collect it, or download the first page while silently ignoring thousands of additional records.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1 Find every dependency before changing code<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Start by searching your environment for Search-UnifiedAuditLog. Look beyond the scripts stored on an administrator\u2019s computer.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Azure Automation accounts and runbooks<\/li>\n<li>Windows scheduled tasks and management servers<\/li>\n<li>PowerShell repositories and deployment pipelines<\/li>\n<li>Power BI reporting processes<\/li>\n<li>Security monitoring and incident response tools<\/li>\n<li>Compliance exports and evidence archives<\/li>\n<li>Scripts maintained by your managed IT provider<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For each dependency, document its owner, purpose, schedule, filters, destination and acceptable delay. This turns an unclear technical retirement into a manageable business project.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2 Choose the right access model<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The API must know which user or application is requesting the data. Interactive tools can use delegated access, where an authorised employee signs in. Unattended jobs normally use application access, allowing an approved service to run without someone entering a password.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For production automation, avoid storing a normal administrator password or reusable application secret in a script. Certificate-based authentication or a managed identity, where supported by the hosting platform, is safer because it reduces the chance of credentials being copied or exposed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Apply least privilege as well. This means granting access only to the audit workloads the application genuinely needs. Microsoft provides permissions for specific services, including Exchange, SharePoint, OneDrive and Microsoft Entra ID, as well as a broader AuditLogsQuery.Read.All permission.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This access review supports the Essential Eight, the Australian government\u2019s cybersecurity framework that many organisations use to reduce common security risks. In particular, it helps limit administrative privileges and improves accountability for sensitive systems.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3 Map existing searches to API filters<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Do not begin by translating code line by line. First document what each search is trying to achieve.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Map the current date range, users, operations and record types to fields such as <code>filterStartDateTime<\/code>, <code>filterEndDateTime<\/code>, <code>userPrincipalNameFilters<\/code>, <code>operationFilters<\/code> and <code>recordTypeFilters<\/code>. The API can also filter by IP address, object identification number and Microsoft 365 service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use Coordinated Universal Time for date values and test boundary times carefully. A timezone mistake can exclude the first or last hours of an Australian business day, leaving an investigation with an unexplained evidence gap.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4 Build the asynchronous query workflow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The following simplified PowerShell example demonstrates the pattern. It uses an interactive connection for clarity; production automation should use a properly secured application identity.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Connect-MgGraph -Scopes &quot;AuditLogsQuery.Read.All&quot;\n\n$body = @{\n displayName = &quot;Daily administrator activity&quot;\n filterStartDateTime = (Get-Date).AddDays(-1).ToUniversalTime().ToString(&quot;o&quot;)\n filterEndDateTime = (Get-Date).ToUniversalTime().ToString(&quot;o&quot;)\n recordTypeFilters = @(&quot;exchangeAdmin&quot;, &quot;azureActiveDirectory&quot;)\n} | ConvertTo-Json\n\n$query = Invoke-MgGraphRequest `\n -Method POST `\n -Uri &quot;https:\/\/graph.microsoft.com\/v1.0\/security\/auditLog\/queries&quot; `\n -Body $body `\n -ContentType &quot;application\/json&quot;\n\n$queryId = $query.id\n\ndo {\n Start-Sleep -Seconds 15\n\n $status = Invoke-MgGraphRequest `\n -Method GET `\n -Uri &quot;https:\/\/graph.microsoft.com\/v1.0\/security\/auditLog\/queries\/$queryId&quot;\n\n} while ($status.status -in @(&quot;notStarted&quot;, &quot;running&quot;))\n\nif ($status.status -ne &quot;succeeded&quot;) {\n throw &quot;Audit query failed with status $($status.status)&quot;\n}\n\n$records = @()\n$nextPage = &quot;https:\/\/graph.microsoft.com\/v1.0\/security\/auditLog\/queries\/$queryId\/records&quot;\n\ndo {\n $page = Invoke-MgGraphRequest -Method GET -Uri $nextPage\n $records += $page.value\n $nextPage = $page.&#39;@odata.nextLink&#39;\n} while ($nextPage)\n\n$records | Export-Csv &quot;.\\AuditResults.csv&quot; -NoTypeInformation<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The API reports states including not started, running, succeeded, failed and cancelled. Result retrieval can return multiple pages, so the script must continue following the next-page address until none remains.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Production code should also include timeouts, retry handling, useful error messages and secure operational logs. Record the query identification number so your team can investigate a failed or incomplete run.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5 Test old and new results side by side<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Run both methods in parallel before switching off the existing script. Compare record counts, timestamps, operation names, user details and downstream reports.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An anonymised example based on a common 200-person environment illustrates the risk. The company had one visible weekly audit report, but the same PowerShell command also fed an administrator-change alert and a monthly compliance archive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Replacing only the weekly report would have left two hidden processes failing after retirement. Dependency mapping and parallel testing allowed all three workflows to move together, protecting the organisation\u2019s investigation capability without a last-minute project.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A practical migration timeline<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>By December 2026:<\/strong> inventory scripts, owners, reports and downstream dependencies.<\/li>\n<li><strong>January to March 2027:<\/strong> create the access model and build reusable API functions.<\/li>\n<li><strong>April to June 2027:<\/strong> run old and new searches in parallel and investigate differences.<\/li>\n<li><strong>July to September 2027:<\/strong> move production workflows, update documentation and train support staff.<\/li>\n<li><strong>Before 15 October 2027:<\/strong> remove remaining dependencies and confirm that alerting, reporting and evidence retention still work.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The business outcome is continuity. Your security team retains access to evidence, compliance reports keep running and the organisation avoids paying for an urgent migration during an incident.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Do not wait for the retirement date<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The hardest part of this change is unlikely to be the API code. It will be finding undocumented dependencies, assigning safe permissions and proving that the new process returns complete results.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CloudProInc is a Melbourne-based Microsoft Partner with more than 20 years of enterprise IT experience across Microsoft 365, Azure, Defender, Intune, cybersecurity and automation. Our work is practical and hands-on rather than a large, faceless managed service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you are not sure where Search-UnifiedAuditLog is being used or whether your audit evidence will remain available after October 2027, we are happy to review the environment and help you build a realistic migration plan \u2014 no strings attached.<\/p>\n\n\n","protected":false},"excerpt":{"rendered":"<p>A practical migration plan for replacing Search-UnifiedAuditLog before October 2027 while protecting security investigations, compliance reporting and audit evidence.<\/p>\n","protected":false},"author":1,"featured_media":59303,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[13,107,14,30],"tags":[],"class_list":["post-59301","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","category-cybersecurity","category-microsoft-365","category-microsoft-graph-api"],"jetpack-related-posts":[{"id":59268,"url":"https:\/\/www.cloudproinc.com.au\/index.php\/2026\/10\/20\/search-unifiedauditlog-retirement-and-migration-plan-for-2027\/","url_meta":{"origin":59301,"position":0},"title":"Search-UnifiedAuditLog Retirement and Migration Plan for 2027","author":"CPI Staff","date":"October 20, 2026","format":false,"excerpt":"Microsoft will retire Search-UnifiedAuditLog on 15 October 2027. Here is a practical migration plan that protects audit reporting, investigations and compliance workflows.","rel":"","context":"In &quot;Blog&quot;","block_context":{"text":"Blog","link":"https:\/\/www.cloudproinc.com.au\/index.php\/category\/blog\/"},"img":{"alt_text":"","src":"\/wp-content\/uploads\/2026\/10\/search-unifiedauditlog-retirement-and-migration-plan-for-2027.png","width":350,"height":200,"srcset":"\/wp-content\/uploads\/2026\/10\/search-unifiedauditlog-retirement-and-migration-plan-for-2027.png 1x, \/wp-content\/uploads\/2026\/10\/search-unifiedauditlog-retirement-and-migration-plan-for-2027.png 1.5x, \/wp-content\/uploads\/2026\/10\/search-unifiedauditlog-retirement-and-migration-plan-for-2027.png 2x, \/wp-content\/uploads\/2026\/10\/search-unifiedauditlog-retirement-and-migration-plan-for-2027.png 3x, \/wp-content\/uploads\/2026\/10\/search-unifiedauditlog-retirement-and-migration-plan-for-2027.png 4x"},"classes":[]},{"id":57791,"url":"https:\/\/www.cloudproinc.com.au\/index.php\/2026\/10\/12\/building-production-ai-agents-with-claude-api-and-agent-sdks\/","url_meta":{"origin":59301,"position":1},"title":"Building Production AI Agents With Claude API and Agent SDKs","author":"CPI Staff","date":"October 12, 2026","format":false,"excerpt":"AI agents can cut busywork, but only if they are built with guardrails. Here is how leaders should approach Claude API and Agent SDK production builds.","rel":"","context":"In &quot;Blog&quot;","block_context":{"text":"Blog","link":"https:\/\/www.cloudproinc.com.au\/index.php\/category\/blog\/"},"img":{"alt_text":"","src":"\/wp-content\/uploads\/2026\/07\/building-production-ai-agents-with-claude-api-and-agent-sdks.png","width":350,"height":200,"srcset":"\/wp-content\/uploads\/2026\/07\/building-production-ai-agents-with-claude-api-and-agent-sdks.png 1x, \/wp-content\/uploads\/2026\/07\/building-production-ai-agents-with-claude-api-and-agent-sdks.png 1.5x, \/wp-content\/uploads\/2026\/07\/building-production-ai-agents-with-claude-api-and-agent-sdks.png 2x, \/wp-content\/uploads\/2026\/07\/building-production-ai-agents-with-claude-api-and-agent-sdks.png 3x, \/wp-content\/uploads\/2026\/07\/building-production-ai-agents-with-claude-api-and-agent-sdks.png 4x"},"classes":[]},{"id":492,"url":"https:\/\/www.cloudproinc.com.au\/index.php\/2026\/10\/12\/automating-access-to-microsoft-graph-api-using-azure-pipelines\/","url_meta":{"origin":59301,"position":2},"title":"Automating Access to Microsoft Graph API Using Azure Pipelines","author":"CPI Staff","date":"October 12, 2026","format":false,"excerpt":"This Azure DevOps pipelines article will show how we automate access to Microsoft Graph API using Azure DevOps pipelines. Azure pipelines is an Azure DevOps service that allows us to automate the deployment of applications, services and changes to cloud environments. Microsoft Graph API is the underlining API service that\u2026","rel":"","context":"In &quot;Azure devOps&quot;","block_context":{"text":"Azure devOps","link":"https:\/\/www.cloudproinc.com.au\/index.php\/category\/azure-devops\/"},"img":{"alt_text":"","src":"\/wp-content\/uploads\/2024\/08\/Automating-Access-to-Microsoft-Graph-Using-Azure-DevOps-Pipelines.webp","width":350,"height":200,"srcset":"\/wp-content\/uploads\/2024\/08\/Automating-Access-to-Microsoft-Graph-Using-Azure-DevOps-Pipelines.webp 1x, \/wp-content\/uploads\/2024\/08\/Automating-Access-to-Microsoft-Graph-Using-Azure-DevOps-Pipelines.webp 1.5x, \/wp-content\/uploads\/2024\/08\/Automating-Access-to-Microsoft-Graph-Using-Azure-DevOps-Pipelines.webp 2x, \/wp-content\/uploads\/2024\/08\/Automating-Access-to-Microsoft-Graph-Using-Azure-DevOps-Pipelines.webp 3x, \/wp-content\/uploads\/2024\/08\/Automating-Access-to-Microsoft-Graph-Using-Azure-DevOps-Pipelines.webp 4x"},"classes":[]},{"id":59286,"url":"https:\/\/www.cloudproinc.com.au\/index.php\/2026\/10\/20\/office-ltsc-2021-end-of-support-migration-plan-for-australia\/","url_meta":{"origin":59301,"position":3},"title":"Office LTSC 2021 End of Support Migration Plan for Australia","author":"CPI Staff","date":"October 20, 2026","format":false,"excerpt":"Office LTSC 2021 is now unsupported. Here is a practical migration plan to reduce security risk, control costs and avoid disrupting employees.","rel":"","context":"In &quot;Blog&quot;","block_context":{"text":"Blog","link":"https:\/\/www.cloudproinc.com.au\/index.php\/category\/blog\/"},"img":{"alt_text":"","src":"\/wp-content\/uploads\/2026\/10\/office-ltsc-2021-end-of-support-migration-plan-for-australia.png","width":350,"height":200,"srcset":"\/wp-content\/uploads\/2026\/10\/office-ltsc-2021-end-of-support-migration-plan-for-australia.png 1x, \/wp-content\/uploads\/2026\/10\/office-ltsc-2021-end-of-support-migration-plan-for-australia.png 1.5x, \/wp-content\/uploads\/2026\/10\/office-ltsc-2021-end-of-support-migration-plan-for-australia.png 2x, \/wp-content\/uploads\/2026\/10\/office-ltsc-2021-end-of-support-migration-plan-for-australia.png 3x, \/wp-content\/uploads\/2026\/10\/office-ltsc-2021-end-of-support-migration-plan-for-australia.png 4x"},"classes":[]},{"id":57903,"url":"https:\/\/www.cloudproinc.com.au\/index.php\/2026\/10\/12\/how-to-govern-claude-enterprise-with-sso-and-the-compliance-api\/","url_meta":{"origin":59301,"position":4},"title":"How to Govern Claude Enterprise with SSO and the Compliance API","author":"CPI Staff","date":"October 12, 2026","format":false,"excerpt":"Control who can use Claude, remove access quickly and create an audit trail that supports security, privacy and compliance requirements.","rel":"","context":"In &quot;AI Governance &amp; Risk Management&quot;","block_context":{"text":"AI Governance &amp; Risk Management","link":"https:\/\/www.cloudproinc.com.au\/index.php\/category\/ai-governance-risk-management\/"},"img":{"alt_text":"","src":"\/wp-content\/uploads\/2026\/07\/how-to-govern-claude-enterprise-with-sso-and-the-compliance-api.png","width":350,"height":200,"srcset":"\/wp-content\/uploads\/2026\/07\/how-to-govern-claude-enterprise-with-sso-and-the-compliance-api.png 1x, \/wp-content\/uploads\/2026\/07\/how-to-govern-claude-enterprise-with-sso-and-the-compliance-api.png 1.5x, \/wp-content\/uploads\/2026\/07\/how-to-govern-claude-enterprise-with-sso-and-the-compliance-api.png 2x, \/wp-content\/uploads\/2026\/07\/how-to-govern-claude-enterprise-with-sso-and-the-compliance-api.png 3x, \/wp-content\/uploads\/2026\/07\/how-to-govern-claude-enterprise-with-sso-and-the-compliance-api.png 4x"},"classes":[]}],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"\/wp-content\/uploads\/2026\/10\/a-practical-search-unifiedauditlog-migration-to-auditlogquery-api.png","_links":{"self":[{"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/posts\/59301","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/comments?post=59301"}],"version-history":[{"count":1,"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/posts\/59301\/revisions"}],"predecessor-version":[{"id":59302,"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/posts\/59301\/revisions\/59302"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/media\/59303"}],"wp:attachment":[{"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/media?parent=59301"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/categories?post=59301"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudproinc.com.au\/index.php\/wp-json\/wp\/v2\/tags?post=59301"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}