Frontrow Technology
← All insights & guides
Guide

Data & Governance

Copilot audit logs and eDiscovery: the investigation runbook

The unified audit log records that a Copilot interaction happened, not what was said. Where each piece of evidence actually lives, and the KQL to pull it.

Simon Aspinall · 28 August 2026 · 11 min read

The request usually arrives from HR or legal, and it sounds simple: show us what Copilot told this person. The IT lead opens the Microsoft Purview audit log, searches for Copilot activity, finds the events, opens one, and hits the wall that derails most first investigations. The record shows that an interaction happened. It does not show what was typed or what came back. At this point plenty of teams conclude Copilot logging is broken, or worse, that Microsoft doesn't capture prompts at all.

Neither is true. Microsoft 365 splits Copilot evidence across two systems on purpose. The unified audit log holds the interaction event: who, when, in which app, and which files Copilot touched to build its answer. The actual prompt and response text is stored as a compliance copy in the user's mailbox, and it is retrieved with eDiscovery, under eDiscovery permissions. Investigating a Copilot interaction properly means knowing which tool answers which question. This runbook covers both, plus the retention settings that decide how long any of it exists.

What the audit log captures, and what it deliberately leaves out

Every time a user interacts with Microsoft 365 Copilot, an event lands in the unified audit log with the record type CopilotInteraction. That event carries a useful amount of metadata:

  • Who ran the interaction, and when.
  • The app host: whether the interaction happened in Teams, Word, Outlook, Copilot Chat, and so on.
  • The context the user was working in, such as the file that was open in the app at the time.
  • AccessedResources: the list of files, emails and meetings Copilot read to ground its answer, including each resource's sensitivity label ID and site URL where populated.
  • Thread and message identifiers that let an investigator line the event up with the stored conversation later.

What the event does not carry is the prompt text or the response text. That is a design decision, not a gap. The audit log is readable by a fairly wide set of operational roles, and Copilot conversations routinely contain draft contracts, salary discussions and legal questions. Microsoft keeps that content behind eDiscovery, where access is separately permissioned and itself audited. The metadata split matters for a second reason: AccessedResources is frequently the most valuable field in the whole record, because it answers the question a permissions incident always raises, which is what, exactly, Copilot read on this user's behalf.

Searching the audit log in Purview

For a one-off question, the portal search is enough:

  1. 1Open the Microsoft Purview portal and go to the Audit solution. Auditing must already be enabled for the tenant; on most tenants it is on by default, but a tenant where it was never switched on has no history to search.
  2. 2Set the date range. Start narrow; audit searches over long ranges on busy tenants are slow.
  3. 3Under Activities, search for Copilot and select the Copilot interaction activities, or filter by the CopilotInteraction record type directly.
  4. 4Optionally scope to specific users, then run the search and export the results to CSV for anything more than a handful of events.

The same search scripted from Exchange Online PowerShell, which is the more repeatable option for a standing weekly review:

"Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) -RecordType CopilotInteraction -ResultSize 5000 | Export-Csv CopilotAudit.csv -NoTypeInformation"

The exported AuditData column is JSON, and the interesting material sits under CopilotEventData. That is workable in a spreadsheet for a single user over a week. It stops being workable the moment the question becomes a pattern question, which is where KQL earns its place.

The KQL that answers real investigation questions

Tenants running Microsoft Defender for Cloud Apps with Microsoft 365 activities connected get Copilot interaction events in the CloudAppEvents table, queryable through advanced hunting in the Microsoft Defender portal. If the Defender XDR tables are streamed into Microsoft Sentinel, the same queries run there unchanged. The event lands with ActionType CopilotInteraction, and the detail sits in RawEventData.CopilotEventData as a dynamic field.

First query: who is using Copilot, where, over the last 30 days. This is the baseline view, and it doubles as a licence-utilisation sanity check.

"CloudAppEvents | where Timestamp > ago(30d) | where ActionType == "CopilotInteraction" | extend Copilot = todynamic(RawEventData.CopilotEventData) | summarize Interactions = count() by UserId = tostring(RawEventData.UserId), AppHost = tostring(Copilot.AppHost) | sort by Interactions desc"

Second query: everything Copilot read on behalf of one user. This is the query to run in an oversharing incident, because it expands AccessedResources into one row per file, with the site URL and sensitivity label ID alongside.

"CloudAppEvents | where Timestamp > ago(7d) | where ActionType == "CopilotInteraction" | extend Copilot = todynamic(RawEventData.CopilotEventData) | where tostring(RawEventData.UserId) =~ "user@contoso.com.au" | mv-expand Resource = Copilot.AccessedResources | project Timestamp, ResourceName = tostring(Resource.Name), SiteUrl = tostring(Resource.SiteUrl), SensitivityLabelId = tostring(Resource.SensitivityLabelId)"

Third query: how often Copilot answers are grounded in labelled content at all. A tenant six months into a sensitivity label rollout should see this number climbing; a flat zero usually means labels exist on paper and not on files.

"CloudAppEvents | where Timestamp > ago(30d) | where ActionType == "CopilotInteraction" | extend Copilot = todynamic(RawEventData.CopilotEventData) | mv-expand Resource = Copilot.AccessedResources | extend LabelId = tostring(Resource.SensitivityLabelId) | summarize Touches = count() by Labelled = isnotempty(LabelId)"

Two practical notes. The CloudAppEvents route only works where Defender for Cloud Apps is licensed and the Microsoft 365 connector is on; without it, the portal search and PowerShell above still work against the same underlying log. And AccessedResources fields are populated when the interaction actually grounded on tenant content; a general-knowledge question that touched nothing returns an empty list, which is itself a useful signal.

Getting the actual prompts and responses: eDiscovery

When the question moves from what did Copilot touch to what was actually said, the audit log is the wrong tool. Microsoft 365 stores a compliance copy of each Copilot prompt and response in a hidden folder of the user's Exchange Online mailbox, alongside the same mechanism used for Teams chat compliance records. Those copies are retrieved through Microsoft Purview eDiscovery:

  1. 1Create an eDiscovery case and add the relevant person's mailbox as a data source. This requires an eDiscovery role rather than a general admin role, which is the point: reading someone's Copilot conversations should sit behind a deliberate, audited permission.
  2. 2In the query builder, add a condition of Type and select Copilot activity. Without this condition, Copilot items simply appear mixed through the wider mailbox results, because they live in the same mailbox as email and chat records.
  3. 3Add date and keyword conditions as needed, run the search, and review the returned items. Each item pairs the prompt with the response.
  4. 4Export in the usual way if the matter needs material handed to legal or an external party.

The thread and message identifiers from the audit event line up with what eDiscovery returns, so a tight investigation runs both: the audit log to establish scope and the files touched, eDiscovery to establish content. Frontrow's standing advice is to rehearse this once before there is an incident, on a test user, end to end. The first live run of an eDiscovery workflow should not be during a dismissal dispute.

Retention: how long any of this exists

Compliance copies of Copilot interactions are governed by Microsoft Purview retention policies, and Copilot now has its own retention location. Newer tenants configure a policy against the Microsoft Copilot Experiences location; older tenants may still carry a combined Teams chats and Copilot interactions policy, which keeps working but can no longer be edited once the separated locations are available, so changes mean recreating the policy against the new locations.

The practical implication runs in both directions. Without a deliberate policy, an organisation may be keeping Copilot conversations far longer than its records schedule intends, or deleting them sooner than a future investigation will want. Setting the Copilot location explicitly, to a period that matches how the organisation treats chat records, is a 30-minute job that determines whether the eDiscovery step above returns evidence or an empty result. Audit log retention runs on a separate clock from the mailbox compliance copies, and that clock varies by licensing, so the safe assumption for anything that might matter later is to export audit results at the time rather than trusting a later search.

Common questions

Frequently asked

Does the Microsoft 365 audit log show what users typed into Copilot?
No. The unified audit log records the interaction event: who, when, which app, and which resources Copilot accessed to ground its answer. The prompt and response text is stored separately as a compliance copy in the user's mailbox and is retrieved through Microsoft Purview eDiscovery, under eDiscovery permissions. That split is deliberate, so conversation content sits behind a tighter, audited permission than general audit search.
How do I see which files Copilot read on a user's behalf?
The AccessedResources field inside the CopilotInteraction audit event lists the files, emails and meetings Copilot used, with sensitivity label IDs and site URLs where populated. In tenants with Defender for Cloud Apps connected, the cleanest way to work with it is a KQL query against CloudAppEvents in advanced hunting, expanding AccessedResources into one row per resource.
Can a Microsoft 365 admin read Copilot conversations?
Not through the audit log, and not through general admin roles. Retrieving prompt and response content requires an eDiscovery role in Microsoft Purview and a search against the user's mailbox with a Copilot activity condition. Access through that path is itself logged, which is exactly what HR and legal teams want to be able to demonstrate later.
How long are Copilot prompts and responses kept?
As long as the retention policy covering the Microsoft Copilot Experiences location says, which is a setting each organisation controls. Tenants that never configured one are relying on defaults rather than a decision. Older combined Teams chats and Copilot interactions policies continue to work but can't be edited once the separated locations are available, so changes mean recreating the policy against the new location.
Do these audit events cover Copilot Chat and agents as well?
Interactions across Microsoft 365 Copilot experiences generate audit events with the interaction metadata, and the app host field in the event shows which surface the interaction came from. Coverage details differ by experience and evolve as Microsoft ships new Copilot surfaces, so a tenant relying on this for compliance should verify the specific surfaces it cares about against the current Microsoft documentation, which is one of the checks Frontrow runs in a governance review.
What licensing do I need to run the KQL queries in this guide?
The CloudAppEvents route requires Microsoft Defender for Cloud Apps with Microsoft 365 activities connected, which most E5-licensed tenants have and many Business Premium tenants don't. Without it, the Purview audit search and the Search-UnifiedAuditLog PowerShell route work against the same underlying log; you lose the convenience of KQL, not the evidence itself.

The matched next step

Find out where your own tenant would have failed

Most incidents start with a control Frontrow checks in week one: MFA coverage, legacy authentication, admin sprawl, unpatched servers. A security baseline review scores your Microsoft 365 tenant against the Essential Eight and hands you a prioritised fix list — whether or not Frontrow does the fixing.

Want Frontrow to run this with your team?

A 30-minute call with a senior consultant. No deck. Frontrow walks through your tenant, your priorities and the next sensible move.