Entra / Microsoft 365 · Compliance & audit
Find Copilot interactions with Graph
Find Copilot interactions for a user between two dates using the Graph aiInteractionHistory API with app-only authentication.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -AppId $AppId -TenantId $TenantId -CertificateThumbprint $Thumbprint -NoWelcome
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $TenantId = "",[string] $AppId = "",[int] $LookbackDays = 30,[string] $StartDate = (Get-Date).AddDays(-$LookbackDays).toString('yyyy-MM-ddT00:00:00Z'),[string] $EndDate = (Get-Date).AddDays(1).toString('yyyy-MM-ddT00:00:00Z'))Disconnect-MgGraph | Out-Null$Thumbprint = '32C9529B1FFD08BCD483A5D98807E47A472C5318'Connect-MgGraph -AppId $AppId -TenantId $TenantId -CertificateThumbprint $Thumbprint -NoWelcome$StartDateForReport = Get-Date $StartDate -format 'dd-MMM-yyyy'$EndDateForReport = Get-Date $EndDate -format 'dd-MMM-yyyy'$UserPrincipalName = Read-Host "Enter the user principal name for the user to search for"$User = Get-MgUser -UserId $UserPrincipalName.trim() -ErrorAction SilentlyContinueIf (!$User) {Write-Host ("User {0} not found" -f $UserPrincipalName)Break}# Has the account got a Copilot license?[array]$UserLicenses = Get-MgUserLicenseDetail -UserId $User.Id | Select-Object -ExpandProperty SkuIdIf ("639dec6b-bb19-468b-871c-c5c441c4b0cb" -notin $UserLicenses) {Write-Host ("User {0} does not have a Copilot license, so we can't check their Copilot interactions" -f $User.DisplayName)Break}$Uri = ("https://graph.microsoft.com/beta/copilot/users/{0}/interactionHistory/getAllEnterpriseInteractions?`$top=100&`$filter=createdDateTime gt {1} and createdDateTime lt {2}" `-f $User.Id, $StartDate, $EndDate)Write-Host ("Searching for Copilot interactions for {0} between {1} and {2}" -f $User.DisplayName, $StartDateForReport, $EndDateForReport)[array]$CopilotData = $null# Get the first set of records[array]$Data = Invoke-MgGraphRequest -Uri $Uri -Method GET$CopilotData = $Data.ValueIf (!($CopilotData)) {Write-Host ("No Copilot interactions found for {0} between {1} and {2}" -f $User.DisplayName, $StartDateForReport, $EndDateForReport)Break}$Nextlink = $Data.'@odata.nextLink'While ($null -ne $Nextlink) {Write-Host ("Fetching more records - currently at {0}" -f $CopilotData.count)[array]$Data = Invoke-MgGraphRequest -Uri $Nextlink -Method Get$CopilotData += $Data.Value$Nextlink = $Data.'@odata.nextLink'}# Remove any null records$CopilotData = $CopilotData | Where-Object { $_ -ne $null }$CopilotData = $CopilotData | Sort-Object {$_.createdDateTime -as [datetime]}Write-Host ("{0} Copilot interactions for {1} between {2} and {3} have been retrieved" -f $CopilotData.count, $User.DisplayName, $StartDateForReport, $EndDateForReport)$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($Record in $CopilotData) {If ($Record.createdDateTime) {$Timestamp = Get-Date $Record.createdDateTime -format 'dd-MMM-yyyy HH:mm:ss'} else {$Timestamp = $null}Switch ($Record.interactionType) {"userPrompt" {$AppName = $User.displayname}"aiResponse" {$AppName = $Record.from.application.displayname}Default {$AppName = $Record.interfrom.application.displayname}}If ($Record.body.content.length -gt 100) {$Body = $Record.body.content.ToString().Substring(0,100)} else {$Body = $Record.body.content.ToString()}$AutoGeneratedFlag = $False# This section checks for some of the fingerprints that indicate that the interaction is automatic rather than user-generatedSwitch ($AppName) {"Copilot in Outlook" {$AppName = "Outlook"If ($Body -like "*VisualTheming*" -or $Body -like "*data:image;base64*") {$AutoGeneratedFlag = $True}}"Copilot in Word" {If ($Body -like "*[AutoGenerated]*") {$AutoGeneratedFlag = $True}}}$ReportLine = [pscustomobject]@{User = $User.UserPrincipalNameTimestamp = $Timestamp'Copilot App' = $AppNameAppId = $AppIdContexts = ($Record.contexts.displayName -join ", ")InteractionType = $Record.interactionTypeThreadId = $Record.sessionidBody = $BodyAttachments = ($Record.attachments.name -join ", ")Mentions = ($Record.mentions.name -join ", ")Links = ($Record.Links.LinkUrl -join ", ")AutoGenerated = $AutoGeneratedFlag}$Report.Add($ReportLine)}$Report | Out-GridView -Title 'Copilot Interactions for $User'# Some basic computations$NumberOfAutomaticInteractions = $Report | Where-Object { $_.AutoGenerated -eq $True } | Measure-Object | Select-Object -ExpandProperty Count$UserInteractions = $Report | Where-Object {$_.InteractionType -eq "userPrompt"} | Measure-Object | Select-Object -ExpandProperty Count$CopilotResponses = $Report.Count - ($UserInteractions + $NumberOfAutomaticInteractions)$PercentCopilotResponses = ($CopilotResponses/$Report.Count).ToString("P")$PercentAutomaticInteractions = ($NumberOfAutomaticInteractions/$Report.Count).ToString("P")$PerecentUserInteractions = ($UserInteractions/$Report.Count).ToString("P")Write-Host ""Write-Host ("Copilot interactions for {0} betweeen {1} and {2}" -f $User.DisplayName, $StartDateForReport, $EndDateForReport)$Report | Group-Object 'Copilot App' | Select-Object Name, Count | Sort-Object Count -Descending | Format-TableWrite-Host ("{0} of the {1} interactions are automatic ({2})" -f $NumberOfAutomaticInteractions, $Report.Count, $PercentAutomaticInteractions)Write-Host ("{0} of the interactions are user prompts ({1})" -f $UserInteractions, $PerecentUserInteractions)Write-Host ("{0} of the interactions are Copilot responses to user prompts" -f $PercentCopilotResponses)# Generate reportsIf (Get-Module ImportExcel -ListAvailable) {$ExcelGenerated = $True$ExcelTitle = ("Copilot interactions for {0} between {1} and {2}" -f $User.DisplayName, $StartDateForReport, $EndDateForReport)Import-Module ImportExcel -ErrorAction SilentlyContinue$OutputXLSXFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\CopilotInteractions.xlsx"If (Test-Path $OutputXLSXFile) {Remove-Item $OutputXLSXFile -ErrorAction SilentlyContinue}$Report | Export-Excel -Path $OutputXLSXFile -WorksheetName "Copilot Interactions" -Title $ExcelTitle -TitleBold -TableName "CopilotInteractions"} Else {$OutputCSVFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\CopilotInteractions.csv"$Report | Export-Csv -Path $OutputCSVFile -NoTypeInformation -Encoding Utf8}If ($ExcelGenerated) {Write-Host ("An Excel worksheet containing the report data is available in {0}" -f $OutputXLSXFile)} Else {Write-Host ("A CSV file containing the report data is available in {0}" -f $OutputCSVFile)}
Parameters
ParameterDefaultNotes
-TenantId""Microsoft Entra tenant ID for app-only Graph authentication.-AppId""Application (client) ID for the app registration used to connect.-LookbackDays30Number of days back to search Copilot interaction history.-StartDate(Get-Date).AddDays(-30).toString('yyyy-MM-ddT00:00:00Z')Start of the Copilot interaction search window.-EndDate(Get-Date).AddDays(1).toString('yyyy-MM-ddT00:00:00Z')End of the Copilot interaction search window.Attribution
Author
Office365itpros