In Microsoft Graph wird seit Januar eine neue API für die Auswertung von Purview Audit Logs bereitgestellt.
Die Dokumentation beschreibt die AuditLogQuery API mit den Methoden List, Create, Get und List records.
Hinweis
Microsoft hat zwischen Januar und März das Format der API URL angepasst. Wurde es im Januar ausprobiert gab der Tenant einen Fehler zurück die Ressource sei nicht bekannt. Mit der mittlerweile angepassten API URL funktioniert es, siehe meinen Tests im Verlauf.
Folgende Methoden werden über die API bereitgestellt.
- List
Listet noch verfügbare Suchaufträge der letzten 30 Tage und deren Status. - Create
Erstellt einen neuen Auftrag zur Auswertung von Audit Logs, ähnlich einem Auftrag über das Compliance Center. In der Dokumentation erwähnt Microsoft die unterstützten Produkte OneDrive, SharePoint, Exchange, Intune, Dynamics CRM, Entra oder alle verfügbaren Dienste. Abhängig zum Produkt benötigt es unterschiedliche API-Berechtigungen. - Get
Zeigt den Status von einem ausgewählten Auftrag. - List audit log records
Inkludiert die gefundenen Ergebnisse aus einem abgeschlossenen Auftrag.
Die API unterstützt Delegation und Application Permissions. Applikationen und Konten können eingeschränkt sein nur für ausgewählte Produkte Audit Logs abzurufen, siehe Berechtigungen.
Für eine allgemeine Hilfe über Suche in Audit Logs solltest du die Dokumentation lesen.
Mich interessierte die API mit Delegated Permissions für SharePoint und Microsoft Entra auszuprobieren. Praktisch ist es Administratoren über die API möglich Suchaufträge für Audit Logs abzusenden und die Ergebnisse auszuwerten. Kennt jemand die Filter ist die Auswertung über PowerShell schneller als über das Compliance Center. Vor allem ist es stabiler. Das Compliance Center ist immer wieder sehr träge.
Content
Auswertung von Audit Logs für SharePoint Online
In meinem ersten Beispiel werte ich aus wann während der letzten 14 Tage Dokumente in den SharePoint Papierkorb verschoben wurden. Dafür benötigt es die Berechtigung AuditLogsQuery-SharePoint.Read.All.
In der Dokumentation für Create beschreibt Microsoft welche Typen unterstützt sind und welche Properties du in einer Anfrage mitsenden kannst. Wie bei Audit Logs üblich ist es empfehlenswert den Zeitraum und Inhalte einzugrenzen, um das Ergebnis weitgehend vorzufiltern.
Hinweis
Während meiner Tests ist mir aufgefallen die Dokumentation inkludiert für den Request Body noch Fehler.
– serviceFilter sollte serviceFilters sein
– serviceFilters ist kein Type string, es muss als String Collection behandelt werden
Mit einem inkorrekten Filter filtert es die Ergebnisse nicht nach Wunsch und inkludiert unerwünschte Daten. In meinen Beispielen wurde es berücksichtigt.
- In meinen Beispiel nutze ich einen ServiceFilter SharePoint.
- Zusätzlich einen RecordTypeFilter für SharePointFileOperation. In der Dokumentation sind die Filter hier und hier erwähnt.
- Zusätzlich einen OperationFilter FileRecycled. Die Filter beschreibt Microsoft in der Dokumentation für Audit Log Activities > File and page activities.
- Sind die Filter unbekannt rate ich über das Compliance Center einen Audit Log Job auszuführen. Im Ergebnis stehen jeweils die erforderlichen Filterwerte. Ausserdem kannst du einen über das Compliance Center erstellten Job über PowerShell auswerten und die Filterwerte kopieren (siehe Schritt 1). 😊
1) Abfrage von Audit Search Jobs
Die Ergebnisse aus einem Audit Search Job speichert das Compliance Center für 30 Tage. Im ersten Schritt frage ich über die API bereits laufende und abgeschlossene Jobs ab.
Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -Scopes AuditLogsQuery-SharePoint.Read.All
$Url = "https://graph.microsoft.com/beta/security/auditLog/queries"
$AuditLogQueryResults = Invoke-MgGraphRequest -Method Get -Uri $Url -ContentType "application/json"
$AuditLogQueryResults
0 bedeutet es sind aus den letzten 30 Tagen keine Jobs vorhanden.
2) Neuen Audit Search Job erstellen
Über die Methode Create erstelle ich einen neuen Search Job und wähle als Startdatum jetzt minus 14 Tage, als Enddatum die aktuelle Zeit.
- Achte beim Auftrag auf das korrekte Format für Datum/Zeit.
- Beachte die aktuelle Möglichkeit von maximal 180 Tage für das Startdatum, unabhängig zu einer E5 Lizenzierung.
$StartDate = (Get-Date).AddDays(-14).ToString("yyyy-MM-ddT00:00:00Z")
$EndDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssZ")
$Body =
@"
{
"displayName": "AuditlogQuery-SharePoint-Test1",
"filterStartDateTime": "$StartDate",
"filterEndDateTime": "$EndDate",
"serviceFilters": ["SharePoint"],
"recordTypeFilters": ["SharePointFileOperation"],
"operationFilters": ["FileRecycled"]
}
"@
$Url = "https://graph.microsoft.com/beta/security/auditLog/queries"
$AuditLogNewQuery = Invoke-MgGraphRequest -Method POST -Uri $Url -Body $Body -ContentType "application/json"
$$AuditLogNewQuery
Die API sendet Informationen über den Auftrag. Die ID wird für die Statusabfrage benötigt, den Status wie fortgeschritten der Auftrag ist.
Eine Kontrolle im Compliance Center bestätigt den Auftrag. Der über die API erstellte Auftrag ist dort ebenfalls ersichtlich.
3) Status von Audit Search Job auswerten
Über die Methode Get frage ich über die ID des Auftrags den Status ab. Abhängig zur Datenmenge kann der Job einige Zeit dauern.
$AuditLogNewQueryID = $AuditLogNewQuery.id
$Url = "https://graph.microsoft.com/beta/security/auditLog/queries/$AuditLogNewQueryID"
$AuditLogNewQueryResult = Invoke-MgGraphRequest -Method Get -Uri $Url -ContentType "application/json"
$AuditLogNewQueryResult
Mein Auftrag wurde nach kurzer Zeit abgeschlossen.
4) Ergebnisse von Audit Search Job auswerten
Ebenfalls mit der ID des Auftrags frage ich über die Methode List records ab wie viele Ergebnisse die Suche gefunden hat > 3 Stück.
$Url = "https://graph.microsoft.com/beta/security/auditLog/queries/$AuditLogNewQueryID/records"
$AuditLogNewQueryResultRecords = Invoke-MgGraphRequest -Method Get -Uri $Url -ContentType "application/json"
$AuditLogNewQueryResultRecords
Alle Ergebnisse listet es ebenfalls auf. Mit den Ergebnissen kann jemand einen Export durchführen oder weiterarbeiten.
Hinweis zur Kontrolle im Compliance Center. Im abgeschlossenen Auftrag findest du die oben erwähnten Filterwerte, falls sie initial unbekannt sind. Öffnen einen Auftrag und achte auf die Werte
- Workload im Auftrag ist ServiceFilter in der API
- RecordType im Auftrag ist RecordTypeFilter in der API
- Operation im Auftrag ist OperationFilter in der API
Auch am Ergebnis der API-Abfrage erkennbar.
Auswertung von Anmeldungen in Microsoft Entra
Nun führe ich über die API noch einen ähnlichen Tests für Audit Logs aus Microsoft Entra durch.
Das Purview Audit Log unterstützt für Entra folgende Filter:
- serviceFilter (Workload) AzureActiveDirectory
- recordTypeFilter azureActiveDirectory, azureActiveDirectoryAccountLogon und azureActiveDirectoryStsLogon
Copilot beschreibt die Unterschiede zwischen azureActiveDirectoryAccountLogon und azureActiveDirectoryStsLogon.
azureActiveDirectoryAccountLogon and azureActiveDirectoryStsLogon are both types of events that can be logged in the Azure Active Directory audit logs, and they can be used as filters when querying these logs through the Microsoft Graph API.
azureActiveDirectoryAccountLogon represents an account logon event in Azure Active Directory. This event is logged when a user or an application logs in to an Azure Active Directory account. This can be useful for tracking authentication events for security or auditing purposes.
On the other hand, azureActiveDirectoryStsLogon represents a Security Token Service (STS) logon event in Azure Active Directory. The STS is a component of identity providers like Azure Active Directory that issues security tokens, or more specifically, OAuth tokens. An STS logon event is logged when a user or an application logs in using these security tokens.
In meinem Beispiel werte ich die Anmeldungen von einem Konto über die letzten 60 Tage aus.
Connect-MgGraph -Scopes AuditLogsQuery-Entra.Read.All
$StartDate = (Get-Date).AddDays(-60).ToString("yyyy-MM-ddT00:00:00Z")
$EndDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssZ")
$Body =
@"
{
"displayName": "AuditlogQuery-EntraLogon-TanjaK-1",
"filterStartDateTime": "$StartDate",
"filterEndDateTime": "$EndDate",
"serviceFilters": ["AzureActiveDirectory"],
"recordTypeFilters": ["azureActiveDirectoryAccountLogon", "azureActiveDirectoryStsLogon"],
"userPrincipalNameFilters": ["[email protected]"]
}
"@
$Url = "https://graph.microsoft.com/beta/security/auditLog/queries"
$AuditLogNewQuery = Invoke-MgGraphRequest -Method POST -Uri $Url -Body $Body -ContentType "application/json"
Der Job ist nach wenigen Minuten abgeschlossen.
Während der letzten 60 Tage wurden 5 Anmeldungen gefunden.
Auswertung von Aktivitäten in Microsoft Entra
Mit dem Wissen welchen ServiceFilter es für die Suche benötigt ist es jetzt möglich Aufträge über Entra Aktivitäten der letzten 180 Tage auszuwerten. Zur Erinnerung, selbst mit E5 Lizenzen kannst du keine Auswertung über mehr als 180 Tage in Auftrag geben.
Ich führte drei verschiedene Tests durch.
- Ich fragte Aktivitäten vom Service AzureActiveDirectory ab.
- Ich fragte für AzureActiveDirectory die Aktivitäten von Alex W. ab.
- Ich fragte für AzureActiveDirectory die Aktivitäten von Tanja K. ab.
Beispiel für Aktivitäten vom Service AzureActiveDirectory.
Connect-MgGraph -Scopes AuditLogsQuery-Entra.Read.All
$StartDate = (Get-Date).AddDays(-180).ToString("yyyy-MM-ddT00:00:00Z")
$EndDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssZ")
$Body =
@"
{
"displayName": "AuditlogQuery-EntraActivities",
"filterStartDateTime": "$StartDate",
"filterEndDateTime": "$EndDate",
"serviceFilters": ["AzureActiveDirectory"]
}
"@
$Url = "https://graph.microsoft.com/beta/security/auditLog/queries"
$AuditLogNewQuery = Invoke-MgGraphRequest -Method POST -Uri $Url -Body $Body -ContentType "application/json"
# Check the job status
$AuditLogNewQueryID = $AuditLogNewQuery.id
$Url = "https://graph.microsoft.com/beta/security/auditLog/queries/$AuditLogNewQueryID"
$AuditLogNewQueryResult = Invoke-MgGraphRequest -Method Get -Uri $Url -ContentType "application/json"
$AuditLogNewQueryResult
# Get the job results after the job is completed
$Url = "https://graph.microsoft.com/beta/security/auditLog/queries/$AuditLogNewQueryID/records?`$top=1000"
$AuditLogNewQueryResultRecords = Invoke-MgGraphRequest -Method Get -Uri $Url -ContentType "application/json"
$AuditLogNewQueryResultRecords
Die Suche über 180 Tage wird ohne weitere Filter entsprechend lange benötigen.
Bei Ergebnissen ab 150 Einträgen führt die API ein Paging durch und gibt pro Abfrage maximal 1.000 Einträge zurück.
Mit einer Schleife frage ich alle Ergebnisse ab.
function Get-TAMgGraphAllData {
<#
.SYNOPSIS
This function retrieves all data from a specified Microsoft Graph API endpoint.
.DESCRIPTION
The Get-TAMgGraphAllData function sends a GET request to the provided Microsoft Graph API URL.
It handles pagination by checking for the '@odata.nextLink' property in the response,
which contains the URL for the next page of data.
The function continues to send requests to the next page URL until there are no more pages,
aggregating all the data into the $dataList array.
.PARAMETER Url
The URL of the Microsoft Graph API endpoint to retrieve data from. This parameter is mandatory.
.EXAMPLE
Get-TAMgGraphAllData -Url "https://graph.microsoft.com/v1.0/users"
This example retrieves all users from the Microsoft Graph API.
.OUTPUTS
Array. Returns an array of all data retrieved from the specified Microsoft Graph API endpoint.
#>
param( [Parameter(Mandatory = $true)][string]$Url )
$APIUrl = $Url
$GraphResultList = @()
While ( $null -ne $APIUrl ) {
$data = Invoke-MgGraphRequest -Method GET -Uri $APIUrl -ContentType "application/json"
$GraphResultList += $data.Value
$APIUrl = $data.'@Odata.NextLink'
}
return $GraphResultList
}
$Results = Get-TAMgGraphAllData -Url "https://graph.microsoft.com/beta/security/auditLog/queries/$AuditLogNewQueryID/records?`$top=1000"
$Results.Count
Das Ergebnis sind 5.786 Zeilen.
Im Compliance Center erkenne ich die Ergebnisse meiner Aufträge.
- Aktivitäten vom Service AzureActiveDirectory 8.000+.
- Aktivitäten von AlexW 801.
- Aktivitäten von TanjaK 41.
Es fällt auf, zwischen API und Compliance Center zeigt das System unterschiedliche Total Results.
Anfangs fragte ich mich warum es zwischen Compliance Center und API eine Differenz gibt. Alle Konten sind mit Microsoft 365 E5 lizenziert, es sollte beim Export keine Limitierung geben.
Export supports results up to 50 KB for Audit (Standard) and up to 500 KB (500,000 rows) for Audit (Premium).
Ich führte darum noch die Auswertung mit Tanja K. durch. Das Konto hat mit 41 sehr wenige Aktivitäten und lässt sich manuell kontrollieren/zählen.
Die API gibt mir 26 Ergebnisse zurück, gegenüber dem Compliance Center wieder eine Differenz.
Kontrolle des Auftrags im Audit Log des Compliance Centers.
Der Auftrag zeigt 41 Ergebnisse, der Filter 52 Items (es ist kein Filter aktiv und alle Zeilen geladen). Zählt man die Zeilen sind es 26 Ergebnisse. Die Anzahl der API über 26 gefundene Einträge stimmt. Export nach Excel inkludiert ebenfalls die 26 Zeilen. Die Angabe über Total Results im Compliance Center stimmt scheinbar nicht.
Auch bei meinen zwei anderen Tests ist es ein ähnliches Ergebnis.
- Aktivitäten vom Service AzureActiveDirectory inkludieren über die API 5.786 Zeilen, statt 8.000+.
- Aktivitäten von Alex W. inkludieren über die API 518 Zeilen, statt 801.
Ich probierte es noch in zwei anderen Tenants. Total Results ist immer höher als das Ergebnis im Export. Die API gibt die korrekten Ergebnisse zurück, ebenfalls ein Export.