Wie Microsoft Purview eDiscovery alleen via de portal gebruikt, merkt vrij snel waar handwerk begint te schuren. Cases aanmaken, searches controleren, operations volgen, exports registreren en dezelfde stappen voor meerdere onderzoeken herhalen is prima voor een incident of juridisch verzoek per maand. Zodra het volume stijgt, wil je voorspelbaarheid, logging en een reproduceerbare workflow. Microsoft Graph is daar een logische bouwsteen voor.
Ik zie dit vaak bij klanten: de eerste automatisering begint als een PowerShell-script dat ‘even’ alle cases uitleest. Daarna komt de vraag om app-only authenticatie, least privilege, foutafhandeling, auditlogging en een koppeling met het bestaande SOC- of legal-operationsproces. Op dat moment is het geen scriptje meer, maar een integratie die je als security- en compliancecomponent moet ontwerpen.
In deze deep dive bouw ik het onderwerp daarom van concept naar praktijk op. We kijken naar het Graph objectmodel, de dubbele autorisatielaag, delegated versus app-only access, licentie-impact, een concreet Graph- en PowerShellvoorbeeld, operation polling, foutafhandeling en de ontwerpkeuzes die bepalen of je automation later beheersbaar blijft.
Waarom dit onderwerp nu speelt
Microsoft heeft de eDiscovery-mogelijkheden in Microsoft Graph verder geconsolideerd onder het security-objectmodel. De v1.0 API ondersteunt onder andere cases, searches, holds, custodians, non-custodial data sources, review sets, tags en operations. Microsoft positioneert deze API expliciet voor het automatiseren van herhaalbare eDiscovery-workflows en integraties met bestaande investigation- en legal-tooling. De documentatie is in 2026 opnieuw bijgewerkt, waardoor het belangrijk is om oude voorbeelden met legacy compliance cmdlets niet klakkeloos als referentie te blijven gebruiken. [1][2]
Daarnaast is de licentielaag belangrijker geworden. Standard- en premiumfunctionaliteit lopen niet één-op-één gelijk met authentication mode. Voor E3-scenario’s is delegated access bruikbaar voor kernoperaties en kan Graph-gebruik rond bepaalde eDiscovery-functies aan pay-as-you-go billing gekoppeld zijn. Premiumfeatures en app-only scenario’s vragen om de juiste premium enablement en/of licenties. Dat moet je vóór de technische implementatie valideren, niet nadat de app registration al in productie staat. [2][7]
Wat je eerst moet begrijpen: eDiscovery is een objectmodel
Een goede Graph-integratie begint niet bij een endpoint, maar bij het objectmodel. Een eDiscovery case is de container. Daaronder hangen de onderdelen die je in de portal ook terugziet: custodians, data sources, holds, searches, review sets, tags en operations. Dat klinkt logisch, maar in automation gaat het vaak mis doordat scripts alleen display names kennen en niet de stabiele object-id’s bewaren.
| Object | Rol in de workflow | Praktijkpunt |
| ediscoveryCase | Container voor onderzoek en onderliggende objecten | Bewaar case ID; displayName is niet je primaire sleutel. |
| ediscoverySearch | Zoekdefinitie over gekoppelde bronnen | Content query en bronnen moeten traceerbaar zijn. |
| caseOperation | Asynchrone taak/status | Poll status; ga niet uit van directe completion. |
| ediscoveryHoldPolicy | Legal hold binnen de case | Niet verwarren met retention holds. |
| ediscoveryReviewSet | Statische dataset voor verdere review | Premiumfunctionaliteit; ontwerp licentie en toegang vooraf. |
Mijn advies is om in elke integratie minimaal de case ID, search ID, operation ID, timestamp, request correlation en de uitvoerende app/user identity te loggen. Als een jurist of auditor drie maanden later vraagt welke zoekactie exact is uitgevoerd, wil je niet afhankelijk zijn van een consolevenster of een losse CSV op iemands desktop.
Architectuur: twee autorisatielagen, niet één

Een veelgemaakte fout is denken dat een app registration met eDiscovery.ReadWrite.All automatisch alles mag. Dat is te simpel. Je hebt in de praktijk twee autorisatielagen: Microsoft Graph application/delegated permissions én Microsoft Purview RBAC/case access. Microsoft documenteert voor app-only toegang expliciet dat Graph-permissions en Purview-level rollen samen moeten kloppen. [3][4]
Voor een menselijke operator met delegated access geldt hetzelfde principe in een andere vorm. De gebruiker krijgt via OAuth een token met de vereiste scope, maar moet daarnaast een ondersteunde Purview-rol hebben en, afhankelijk van de rol en caseconfiguratie, toegang tot de case. Een eDiscovery Manager kan zijn eigen cases beheren; een eDiscovery Administrator heeft bredere toegang tot cases in de organisatie. Juist omdat die laatste rol potentieel toegang geeft tot zeer gevoelige onderzoeksdata, adviseert Microsoft het aantal administrators beperkt te houden. [3]
Delegated of app-only?
Delegated access past goed bij beheeracties waarbij een analist of eDiscovery-specialist bewust een workflow start. Je behoudt dan de context van de signed-in user en kunt de menselijke autorisatie goed laten aansluiten op bestaande rollen. App-only is interessanter als een workflow zonder interactieve gebruiker moet draaien, bijvoorbeeld vanuit Azure Automation, een Function App of een geplande integratie.
In de praktijk gaat dit vaak mis bij app-only omdat teams alleen de Entra-kant configureren. De service principal heeft dan eDiscovery.Read.All of eDiscovery.ReadWrite.All met admin consent, maar is niet goed gekoppeld aan de Purview RBAC-context. Andersom zie je ook scripts die een zwaar Purview-role group membership krijgen terwijl ze functioneel alleen read-only inventarisatie uitvoeren. Beide zijn vermijdbaar met least privilege.
Licenties en featurestatus: bouw dit niet blind
De eDiscovery API is beschikbaar voor organisaties met E3- en E5-scenario’s, maar de beschikbare operations en het billingmodel verschillen. Microsoft geeft aan dat cases, searches en holds in een E3/Standard-context met delegated authentication ondersteund kunnen worden, terwijl premiumfuncties zoals review sets, tagging en analytics een premiumcontext vereisen. Voor tenants met E3 eDiscovery-licenties kan Graph API-gebruik aan pay-as-you-go billing gekoppeld zijn. [2][7]
Gebruik je een Microsoft 365 E5 demo tenant voor je lab, dan kun je de premiumflow goed testen. Toch zou ik in documentatie en automation niet hardcoderen dat ‘E5 alles oplost’. Controleer of premium eDiscovery features daadwerkelijk voor de case zijn ingeschakeld en welke add-ons of billingconfiguratie in de tenant gelden. De Purview portal heeft hiervoor onder eDiscovery Settings een instelling voor premiumfeatures. [8]
Lab: een veilige Graph-integratie opzetten
Voor het lab ga ik uit van een Microsoft 365 E5 demo tenant en een automation-app die cases mag uitlezen en, in een tweede stap, searches kan aanmaken. Begin read-only. Pas nadat de inventoryflow goed werkt en de audittrail klopt, voeg je write-permissions toe.
Stap 1 – App registration in Microsoft Entra
- Open Microsoft Entra admin center > Identity > Applications > App registrations.
- Selecteer New registration en maak bijvoorbeeld ‘Purview-eDiscovery-Automation’.
- Noteer Application (client) ID en Directory (tenant) ID.
- Gebruik voor productie bij voorkeur certificate-based authentication in plaats van een langlevend client secret.
- Open API permissions > Add a permission > Microsoft Graph > Application permissions en voeg alleen de eDiscovery-permission toe die je echt nodig hebt.
- Geef admin consent via je gecontroleerde change-proces.
Voor alleen inventory is eDiscovery.Read.All het logische uitgangspunt. Voor acties die cases/searches wijzigen is eDiscovery.ReadWrite.All nodig. Een app met ReadWrite.All is krachtig: combineer die permission daarom met Conditional Access for workload identities waar beschikbaar, certificaatrotatie, strakke ownership en monitoring van service principal sign-ins.
Stap 2 – Purview RBAC en case access
Graph-permissions zijn niet het volledige autorisatiemodel. Microsoft beschrijft voor eDiscovery app-only toegang een service principal die ook in de Purview-context wordt geregistreerd en aan een passende role group wordt gekoppeld. Voor app-only eDiscovery noemt Microsoft eDiscovery Manager als gevalideerde least-privileged roltoewijzing in de relevante configuratie. [3]
Maak hier geen generieke ‘compliance automation’-service principal van die later ook DLP, Audit en Insider Risk rechten krijgt. Splits workload identities per functie. Dat maakt incident response rond een gecompromitteerde credential veel eenvoudiger.
Graph voorbeeld 1 – cases uitlezen met REST
De basiscall is verrassend eenvoudig. De complexiteit zit niet in de GET, maar in token acquisition, autorisatie, foutafhandeling en logging.
GET https://graph.microsoft.com/v1.0/security/cases/ediscoveryCases
Authorization: Bearer <access_token>
Accept: application/json
Een succesvolle call retourneert een collectie ediscoveryCase-objecten. Bewaar minimaal id, displayName, status en relevante timestamps in je eigen automation-log. Microsoft ondersteunt voor deze resource ook OData query parameters, maar controleer per endpoint welke queryopties daadwerkelijk ondersteund zijn. [5]
Graph voorbeeld 2 – PowerShell met app-only token
Onderstaand voorbeeld gebruikt een certificaat en de Microsoft Graph PowerShell SDK. Het leest cases uit en schrijft een compacte inventory naar de console. Vervang de placeholders door je eigen tenant-, app- en certificatewaarden. Gebruik in productie een certificaat uit een gecontroleerde store en voorkom exportable private keys waar dat niet nodig is.
# Vereist: Microsoft.Graph PowerShell SDK
$TenantId = “<tenant-id>”
$ClientId = “<application-client-id>”
$Thumbprint = “<certificate-thumbprint>”
Connect-MgGraph `
-TenantId $TenantId `
-ClientId $ClientId `
-CertificateThumbprint $Thumbprint `
-NoWelcome
$uri = “https://graph.microsoft.com/v1.0/security/cases/ediscoveryCases”
try {
$response = Invoke-MgGraphRequest `
-Method GET `
-Uri $uri `
-OutputType PSObject
foreach ($case in $response.value) {
[pscustomobject]@{
Id = $case.id
DisplayName = $case.displayName
Status = $case.status
Created = $case.createdDateTime
}
}
}
catch {
Write-Error (“Purview eDiscovery Graph call failed: {0}” -f $_.Exception.Message)
throw
}
finally {
Disconnect-MgGraph
}
Dit voorbeeld is bewust klein. In productie wil je retry-logica voor tijdelijke 429/5xx-fouten, gestructureerde logging, correlation IDs en een duidelijke scheiding tussen authentication errors, authorization errors en resource errors. Een HTTP 403 is bijvoorbeeld geen reden om automatisch meer rechten toe te kennen; het is een signaal om Graph permissions, Purview RBAC én case access gericht te controleren.
Graph voorbeeld 3 – een eDiscovery search aanmaken
Na inventory komt meestal de eerste write-actie: een search aanmaken binnen een bestaande case. Microsoft Graph gebruikt hiervoor een POST op de searches-collectie van de case. Het search-object kan onder andere een display name, description, contentQuery en gekoppelde data sources bevatten. [6]
POST https://graph.microsoft.com/v1.0/security/cases/ediscoveryCases/{case-id}/searches
Content-Type: application/json
Authorization: Bearer <access_token>
{
“displayName”: “ITCowboys – Investigation Search 01”,
“description”: “Gecontroleerde zoekactie voor onderzoek INC-2026-0042”,
“contentQuery”: “(kind:email) AND (subject:\”password reset\”)”
}
De exacte bruikbaarheid van een query hangt af van het soort bron en de eDiscovery searchsyntax. Valideer content queries eerst in een lab en laat gevoelige production queries waar nodig door legal/compliance goedkeuren. Een search die technisch valide is, is niet automatisch organisatorisch toegestaan.
Dit klinkt klein, maar heeft impact op je SOC proces. Als een incident response-team via automation eDiscovery-searches kan starten, vervaagt de grens tussen security investigation en formele compliance/legal investigation. Leg daarom vast welke use cases via SOC-automation mogen, wanneer legal betrokken wordt en wie eigenaar is van data export of purge-acties.
Asynchrone operations: ontwerp voor status, niet voor snelheid
Verschillende eDiscovery-acties leveren een operation op die niet direct klaar is. Microsoft Graph exposeert case operations via het case-object. Je kunt bijvoorbeeld de operations van een case opvragen met GET /security/cases/ediscoveryCases/{caseId}/operations. [9]
GET https://graph.microsoft.com/v1.0/security/cases/ediscoveryCases/{case-id}/operations
Authorization: Bearer <access_token>
Bouw hiervoor een state machine of ten minste gecontroleerde polling. Poll niet iedere seconde. Gebruik een begrensd interval, maximum runtime en duidelijke terminal states. Sla operation ID en laatste status op. Als je runbook crasht, moet een volgende run kunnen hervatten zonder dezelfde actie opnieuw te starten.
Een bruikbaar automation-patroon
- Create of trigger: start de operation één keer en registreer operation ID.
- Observe: poll met back-off en log elke statuswijziging, niet iedere identieke response.
- Timeout: stop gecontroleerd na een vooraf afgesproken maximumduur.
- Reconcile: controleer na een restart eerst of een bestaande operation nog loopt.
- Escalate: maak onderscheid tussen transient errors en authorization/configuration errors.
- Audit: log wie of welke workload identity de actie initieerde en welk business/incident-ID eraan gekoppeld is.
Foutafhandeling en troubleshooting
De meeste Graph-integraties falen niet op JSON, maar op identity en context. Mijn advies is om troubleshooting altijd in dezelfde volgorde te doen. Begin bij het token: klopt tenant, audience en permission? Controleer daarna Graph API permissions en admin consent. Ga vervolgens naar Purview RBAC, service principal registration en case membership. Pas daarna kijk je naar het specifieke endpoint en payload.
| Symptoom | Waarschijnlijke oorzaak | Controle |
| 401 Unauthorized | Token/authentication fout | Tenant, certificate, token audience, expiry. |
| 403 Forbidden | Graph permission, Purview RBAC of case access ontbreekt | Controleer beide autorisatielagen. |
| 404 Not Found | Verkeerde object-id of resource-context | Gebruik IDs uit actuele case/search-response. |
| 429 Too Many Requests | Te agressieve polling of volume | Respecteer Retry-After en back-off. |
| Operation blijft lang running | Backend job duurt of bronvolume groot | Poll gecontroleerd en hanteer timeout/escalatie. |
Purge en andere risicovolle acties
Microsoft Graph ondersteunt ook purge-acties op eDiscovery searches. Dat is functioneel krachtig en operationeel risicovol. Microsoft waarschuwt dat permanente verwijdering niet herstelbaar kan zijn en koppelt aanvullende Purview-rollen aan purge-scenario’s. [10]
Ik zou purge nooit in dezelfde service principal stoppen als read-only inventory of normale search automation. Gebruik een aparte identity, aparte approvalflow en expliciete human-in-the-loop bevestiging. Log de search ID, query, locaties, aangevraagde purge type, approver en operation result. Dit is precies het soort actie waar ‘het script werkte’ geen voldoende auditbewijs is.
Praktijkvoorbeeld: van SOC-case naar eDiscovery-case
Stel dat een Defender XDR-incident wijst op mogelijke data-exfiltratie via een gecompromitteerd account. Het SOC wil snel veiligstellen welke mailbox- en Teams-data relevant zijn, maar legal bepaalt of er een formele eDiscovery-case nodig is. Een volwassen proces kan er als volgt uitzien.
- SOC triageert het incident en bepaalt scope: gebruiker, tijdvenster, relevante workloads.
- Een goedgekeurde workflow maakt of selecteert een eDiscovery-case en koppelt het interne incident-ID.
- Automation legt de relevante custodian/data source-context vast.
- Een vooraf gereviewde searchtemplate wordt gevuld met tijdvenster en onderzoekstermen.
- De search wordt gestart en operation status wordt gemonitord.
- Resultaten worden niet automatisch breed geëxporteerd; export vereist expliciete bevoegdheid en businessreden.
- Alle IDs en statuswijzigingen gaan naar een centraal auditlog of case-managementsysteem.
De winst zit hier niet alleen in snelheid. Je maakt het proces reproduceerbaar. Twee analisten voeren dezelfde juridische of compliance-stap niet meer op twee verschillende manieren uit. En je kunt achteraf aantonen wat technisch is gebeurd.
Security hardening voor de automation identity
- Gebruik certificate-based authentication voor unattended workloads en roteer certificaten aantoonbaar.
- Ken eDiscovery.Read.All toe waar write niet nodig is; upgrade permissions alleen per concrete use case.
- Splits read, write en destructive actions over aparte workload identities.
- Beperk owners van app registrations en review ze periodiek.
- Monitor service principal sign-ins en afwijkende tokenactiviteit.
- Bewaar secrets/certificaatmateriaal niet in scripts, repositories of lokale profielmappen.
- Koppel automation requests aan een ticket-, incident- of case-ID.
- Test authorization-failures bewust: een veilige integratie moet correct falen wanneer rechten worden ingetrokken.
Veelgemaakte fouten
1. Alleen naar Graph permissions kijken
eDiscovery heeft naast Microsoft Graph permissions ook Purview RBAC en casecontext. Een 403 los je daarom niet automatisch op met nóg een application permission.
2. Display names als sleutel gebruiken
Cases en searches kunnen namen hebben die veranderen of sterk op elkaar lijken. Bewaar object IDs en toon display names alleen als menselijke context.
3. Polling zonder back-off
Een loop die iedere seconde operations opvraagt is onnodig en vergroot de kans op throttling. Ontwerp asynchronous processing als normaal gedrag.
4. Te vroeg ReadWrite.All geven
Start inventory read-only. Je ontdekt dan authentication, pagination, logging en objectmodelproblemen zonder meteen muterende rechten nodig te hebben.
5. Portal en automation los van elkaar beheren
Als mensen cases handmatig wijzigen terwijl automation op aannames draait, krijg je drift. Lees actuele state uit vóór een write en bouw idempotente controles in.
6. Beta gebruiken terwijl v1.0 volstaat
Preview-API’s kunnen wijzigen en zijn niet bedoeld als standaard productiepad als dezelfde capability in v1.0 beschikbaar is. Voor de flow in deze blog is v1.0 voldoende.
Mijn advies vanuit de praktijk
Begin niet met de meest indrukwekkende automation. Begin met een read-only inventory die je identity-, permission- en loggingmodel bewijst. Breid daarna uit naar het aanmaken van searches en operation monitoring. Voeg pas als laatste exports, review-set acties of purge toe. Zo dwing je jezelf om eerst het fundament goed te zetten.
Ik zie dit vaak bij klanten: automation wordt beoordeeld op hoeveel handwerk het wegneemt, maar te weinig op hoe goed het faalt. Voor Purview is gecontroleerd falen minstens zo belangrijk. Een workflow die bij een 403 stopt met een duidelijke melding is veiliger dan een workflow die steeds meer rechten vraagt totdat de call slaagt.
De kern is daarom simpel: Microsoft Graph maakt eDiscovery goed automatiseerbaar, maar behandel die API als toegang tot onderzoeks- en compliancegegevens, niet als een generieke Microsoft 365 API. Identity, RBAC, case scope, audit en lifecycle horen vanaf het eerste ontwerp in dezelfde tekening.
Conclusie
Microsoft Purview eDiscovery en Microsoft Graph vormen samen een sterke basis voor reproduceerbare investigations en legal/compliance workflows. De v1.0 API geeft je voldoende bouwstenen om cases te inventariseren, searches te beheren en operations te volgen, zonder meteen afhankelijk te zijn van preview-endpoints. De echte technische diepgang zit in het autorisatiemodel en de operationele engineering eromheen.
Wie dit goed neerzet, krijgt niet alleen minder handwerk maar ook een beter aantoonbaar proces: vaste identities, least privilege, traceerbare object IDs, gecontroleerde asynchrone verwerking en een audittrail die aansluit op incident- of legal-case management. Dat is uiteindelijk waar Purview automation waarde toevoegt.
Volg ITCowboys voor de volgende technische deep dive. In de komende blogs pak ik meer Microsoft Security, XDR, Sentinel, Identity en Purview onderwerpen op vanuit de praktijk.
Bronnen
[1] Microsoft Learn – Use the Microsoft Purview eDiscovery API in Microsoft Graph (v1.0), bijgewerkt 7 mei 2026. https://learn.microsoft.com/en-us/graph/api/resources/security-ediscovery-apioverview?view=graph-rest-1.0
[2] Microsoft Learn – Use Microsoft Purview APIs for eDiscovery. https://learn.microsoft.com/en-us/purview/edisc-ref-api-guide
[3] Microsoft Learn – Assign permissions in eDiscovery. https://learn.microsoft.com/en-us/purview/edisc-permissions
[4] Microsoft Learn – Set up app-only access for Microsoft Purview eDiscovery by using Microsoft Graph APIs. https://learn.microsoft.com/graph/security-ediscovery-appauthsetup
[5] Microsoft Learn – List ediscoveryCases. https://learn.microsoft.com/en-us/graph/api/security-casesroot-list-ediscoverycases?view=graph-rest-1.0
[6] Microsoft Learn – Create searches. https://learn.microsoft.com/en-us/graph/api/security-ediscoverycase-post-searches?view=graph-rest-1.0
[7] Microsoft Learn – Billing in eDiscovery. https://learn.microsoft.com/en-us/purview/edisc-billing
[8] Microsoft Learn – Configure general settings in eDiscovery. https://learn.microsoft.com/en-us/purview/edisc-settings-general
[9] Microsoft Learn – List caseOperations. https://learn.microsoft.com/en-us/graph/api/security-ediscoverycase-list-operations?view=graph-rest-1.0
[10] Microsoft Learn – ediscoverySearch: purgeData. https://learn.microsoft.com/en-us/graph/api/security-ediscoverysearch-purgedata?view=graph-rest-1.0
[11] Microsoft Learn – Microsoft Graph what’s new, september 2026. https://learn.microsoft.com/nl-nl/graph/whats-new-overview