Scaling software businesses through hyperscaler marketplaces: Strategies, actions, and resources
July 8, 2025Lessons Learned with CMMC: Perspective from Sonalyst
July 8, 2025Welcome back to the series of blogs covering search and purge in Microsoft Purview eDiscovery!
If you are new to this series, please first visit the blog post in our series that you can find here: Search and Purge workflow in the new modern eDiscovery experience
Also, please ensure you have fully read the Microsoft Learn documentation on this topic as I will not be covering some of the steps in full (permissions, releasing holds, all limitations): Find and delete Microsoft Teams chat messages in eDiscovery | Microsoft Learn
So as a reminder, for E5/G5 customers and cases with premium features enabled- you must use the Graph API to execute the purge operation. With the eDiscovery Graph API, you have the option to create the case, create a search, generate statistics, create an item report and issue the purge command all from the Graph API.
It is also possible to use the Purview Portal to create the case, create the search, generate statistics/samples and generate the item report. However, the final validation of the items that would be purged by rerunning the statistics operation and issuing the purge command must be run via the Graph API.
In this post, we will take a look at two examples, one involving an email message and one involving a Teams message. I will also look to show how to call the graph APIs.
Purging email messages via the Graph API
In this example, I want to purge the following email incorrectly sent to Debra Berger. I also want to remove it from the sender’s mailbox as well. Let’s assume in this example I do not know exactly who sent and received the email, but I do know the subject and date it was sent on.
In this example, I am going to use the Modern eDiscovery Purview experience to create a new case where I will undertake some initial searches to locate the item.
Once the case is created, I will Create a search and give it a name.
In this example, I do not know all the mailboxes where the email is present, so my initial search is going to be a tenant wide search of all Exchange mailboxes, using the subject and date range as conditions to see which locations have hits.
Note: For scenarios where you know the location of the items there is no requirement to do a tenant wide search. You can target the search to the know locations instead.
I will then select Run Query and trigger a Statistics job to see which locations in the tenant have hits. For our purposes, we do not need to select Include categories, Include query keywords report or Include partially indexed items.
This will trigger a Generate statistics job and take you to the Statistics tab of the search. Once the job completes it will display information on the total matches and number of locations with hits.
To find out exactly which locations have hits, I can use the improved process reports to review more granular detail on the locations with hits. The report for the Generate statistics job can be found by selecting Process manager and then selecting the job. Once displayed I can download the reports associated with this process by selecting Download report.
Once we have downloaded the report for the process, we get a ZIP file containing four different reports, to understand where I had hits I can review the Locations report within the zip file.
If I open the locations report and filter on the count column I can see in this instance I have two locations with hits, Admin and DebraB.
I will use this to make my original search more targeted. It also gives me an opportunity to check that I am not going to exceed the limits on the number of items I can target for the purge per execution.
Returning to our original search I will remove All people and groups from my Data Sources and replace it with the two locations I had hits from.
I will re-run my Generate Statistics job to ensure I am still getting the expected results.
As the numbers align and remain consistent, I will do a further check and generate samples from the search. This will allow me to review the items to confirm that they are the items I wish to purge. From the search query I select Run query and select Sample.
This will trigger a Generate sample job and take you to the Sample tab of the search. Once complete, I can review samples of the items returned by the search to confirm if these items are the items I want to purge.
Now that I have confirmed, based on the sampling, that I have the items I want to purge I want to generate a detailed item report of all items that are a match for my search. To do this I need to generate an export report for the search.
Note: Sampling alone may not return all the results impacted by the search, it only returns a sample of the items that match the query. To determine the full set of items that will be targeted we need to generate the export report.
From the Search I can select Export to perform a direct export without having to add the data to a review set (available when premium features are enabled). Ensure to configure the following options on the export:
- Indexed items that match your search query
- Unselect all the options under Messages and related items from mailboxes and Exchange Online
- Export Item report only
If you want to manually review the items that would be impacted by the purge operation you can optionally export the items alongside the items report for further review.
You can also add the search to a review set to review the items that you are targeting. The benefit of adding to the review set is that it enables to you review the items whilst still keeping the data within the M365 service boundary.
Note: If you add to a review set, a copy of the items will remain in the review set until the case is deleted.
I can review the progress of the export job and download the report via the Process Manager.
Once I have downloaded the report, I can review the Items.csv file to check the items targeted by the search.
It is at this stage I must switch to using the Graph APIs to validate the actions that will be taken by the purge command and to issue the purge command itself. Not undertaking these additional validation steps can result in un-intended purge of data.
There are two approaches you can use to interact with the Microsoft Graph eDiscovery APIs:
- Via Graph Explorer
- Via the MS.Graph PS module
For this example, I will show how to use the Graph Explorer to make the relevant Graph API calls. For the Teams example, I will use the MS.Graph PS Module.
We are going to use the APIs to complete the following steps:
- Trigger a statistics job via the API and review the results
- Trigger the purge command
The Graph Explorer can be accessed via the following link: Graph Explorer | Try Microsoft Graph APIs – Microsoft Graph
To start using the Graph Explorer to work with Microsoft Graph eDiscovery APIs you first need to sign in with your admin account.
You need to ensure that you consent to the required Microsoft Graph eDiscovery API permissions by selecting Consent to permissions.
From the Permissions flyout search for eDiscovery and select Consent for eDiscovery.ReadWrite.All.
When prompted to consent to the permissions for the Graph Explorer select Accept. Optionally you can consent on behalf of your organisation to suppress this step for others.
Once complete we can start making calls to the APIs via Graph Explorer. To undertake the next steps we need to capture some additional information, specifically the Case ID and the Search ID.
We can get the case ID from the Case Settings in the Purview Portal, recording the Id value shown on the Case details pane.
If we return to the Graph Explorer we can use this CaseID to see all the searches within an eDiscovery case. The structure of the HTTPS call is as follows:
GET https://graph.microsoft.com/v1.0/security/cases/ediscoveryCases//searches
List searches – Microsoft Graph v1.0 | Microsoft Learn
If we replace with the Id we captured from the case settings we can issue the API call to see all the searches within the case to find the required search ID. When you issue the GET request in Graph Explorer you can review the Response preview to find the search ID we are looking for.
Now that we have the case ID and the Search ID we can trigger an estimate by using the following Graph API call.
POST https://graph.microsoft.com/v1.0/security/cases/ediscoveryCases/{ediscoveryCaseId}/searches/{ediscoverySearchId}/estimateStatistics
ediscoverySearch: estimateStatistics – Microsoft Graph v1.0 | Microsoft Learn
Once you issue the POST command you will be returned with an Accepted – 202 message.
Now I need to use the following REST API call to review the status of the Estimate Statistics job in Graph Explorer.
GET https://graph.microsoft.com/v1.0/security/cases/ediscoveryCases/{ediscoveryCaseId}/searches/{ediscoverySearchId}/lastEstimateStatisticsOperation
List lastEstimateStatisticsOperation – Microsoft Graph v1.0 | Microsoft Learn
If the estimates job is not complete when you run the GET command the Response preview contents will show the status as running.
If the estimates job is complete when you run the GET command the Response preview contents will show you the results of the estimates job.
CRITICAL: Ensure that the indexedItemCount matches the items returned in the item report generated via the Portal. If this does not match do not proceed to issuing the purge command.
Now that I have validated everything, I am ready to issue the purge command via the Graph API. I will use the following Graph API call.
POST https://graph.microsoft.com/v1.0/security/cases/ediscoveryCases/{ediscoveryCaseId}/searches/{ediscoverySearchId}/purgeData
ediscoverySearch: purgeData – Microsoft Graph v1.0 | Microsoft Learn
With this POST command we also need to provide a Request Body to tell the API which areas we want to target (mailboxes or teamsMessages) and the purge type (recoverable, permantlyDelete).
As we are targeting email items I will use mailboxes as the PurgeAreas option. As I only want to remove the item from the user’s mailbox view I am going to use recoverable as the PurgeType.
{ “purgeType”: “recoverable”, “purgeAreas”: “mailboxes” }
Once you issue the POST command you will be returned with an Accepted – 202 message.
Once the command has been issued it will proceed to purge the items that match the search criteria from the locations targeted. If I go back to my original example, we can now see the item has been removed from the users mailbox.
As it has been soft deleted I can review the recoverable items folder from Outlook on the Web where I will see that for the user, it has now been deleted pending clean-up from their mailbox.
Purging Teams messages via the Graph API
In this example, I want to purge the following Teams conversation between Debra, Adele and the admin (CDX) from all participants Teams client.
I am going to reuse the “HK016 – Search and Purge” case to create a new search called “Teams conversation removal”.
I add three participants of the chat as Data sources to the search, I am then going to use the KeyQL condition to target the items I want to remove. In this example I am using the following KeyQL.
(Participants=AdeleV@M365x00001337.OnMicrosoft.com AND Participants=DebraB@M365x00001337.OnMicrosoft.com AND Participants=admin@M365x00001337.onmicrosoft.com) AND (Kind=im OR Kind=microsoftteams) AND (Date=2025-06-04)
This is looking for all Teams messages that contain all three participants sent on the 4th of June 2025.
It is critical when targeting Teams messages that I ensure my query targets exactly the items that I want to purge. With Teams messages (opposed to email items) there are less options available that enable us to granularly target the team items for purging.
Note: The use of the new Identifier condition is not supported for purge options. Use of this can lead to unintended data to be removed and should not be used as a condition in the search at this time.
If I was to be looking for a very specific phrase, I could further refine the query by using the Keyword condition to look for that specific Teams message.
Once I have created my search I am ready to generate both Statistics and Samples to enable me to validate I am targeting the right items for my search.
My statistics job has returned 21 items, 7 from each location targeted. This aligns with the number of items within the Teams conversation. However, I am going to also validate that the samples I have generated match the content I want to purge, ensuring that I haven’t inadvertently returned additional items I was not expecting.
Now that I have confirmed, based on the sampling, that the sample of items returned look to be correct I want to generate a detailed item report of all items that are a match for my search. To do this I need to generate an export report for the search.
From the Search I can select Export to perform a direct export without having to add the data to a review set (available when premium features are enabled). Ensure to configure the following options on the export:
- Indexed items that match your search query
- Unselect all the options under Messages and related items from mailboxes and Exchange Online
- Export Item report only
Once I select Export it will create a new export job, I can review the progress of the job and download the report via the Process Manager.
Once I have downloaded the report, I can review the Items.csv file to check the items targeted by the search and that would be purged when I issue the purge call.
Now that I have confirmed that the search is targeting the items I want to purge it is at this stage I must switch to using the Graph APIs. As discussed, there are two approaches you can use to interact with the Microsoft Graph eDiscovery APIs:
- Using Graph Explorer
- Using the MS.Graph PS module
For this example, I will show how to use the MS.Graph PS Module to make the relevant Graph API calls. To understand how to use the Graph Explorer to issue the purge command please refer to the previous example for purging email messages.
We are going to use the APIs to complete the following steps:
- Trigger a statistics job via the API and review the results
- Trigger the purge command
To install the MS.Graph PowerShell module please refer to the following article.
Install the Microsoft Graph PowerShell SDK | Microsoft Learn
To understand more about the MS.Graph PS module and how to get started you can review the following article.
Get started with the Microsoft Graph PowerShell SDK | Microsoft Learn
Once the PowerShell module is installed you can connect to the eDiscovery Graph APIs by running the following command.
connect-mgGraph -Scopes “ediscovery.ReadWrite.All”
You will be prompted to authenticate, once complete you will be presented with the following banner.
To undertake the next steps we need to capture some additional information, specifically the Case ID and the Search ID.
As before we can get the case ID from the Case Settings in the Purview Portal, recording the Id value shown on the Case details pane.
Alternatively we can use the following PowerShell command to find a list of cases and their ID.
get-MgSecurityCaseEdiscoveryCase | ft displayname,id
List ediscoveryCases – Microsoft Graph v1.0 | Microsoft Learn
Once we have the ID of the case we want to execute the purge command from, we can run the following command to find the IDs of all the search jobs in the case.
Get-MgSecurityCaseEdiscoveryCaseSearch -EdiscoveryCaseId | ft displayname,id,ContentQuery
List searches – Microsoft Graph v1.0 | Microsoft Learn
Now that we have both the Case ID and the Search ID we can trigger the generate statistics job using the following command.
Invoke-MgEstimateSecurityCaseEdiscoveryCaseSearchStatistics -EdiscoveryCaseId -EdiscoverySearchId
ediscoverySearch: estimateStatistics – Microsoft Graph v1.0 | Microsoft Learn
Now I need to use the following command to review the status of the Estimate Statistics job.
Get-MgSecurityCaseEdiscoveryCaseSearchLastEstimateStatisticsOperation -EdiscoveryCaseID -EdiscoverySearchId
List lastEstimateStatisticsOperation – Microsoft Graph v1.0 | Microsoft Learn
If the estimates job is not complete when you run the command the status will show as running.
If the estimates job is complete when you run the command status will show as succeeded and will also show the number of hits in the IndexItemCount.
CRITICAL: Ensure that the indexedItemCount matches the items returned in the item report generated via the Portal. If this does not match do not proceed to issuing the purge command.
Now that I have validated everything I am ready to issue the purge command via the Graph API.
With this command we need to provide a Request Body to tell the API which areas we want to target (mailboxes or teamsMessages) and the purge type (recoverable, permantlyDelete).
As we are targeting teams items I will use teamsMessages as the PurgeAreas option.
Note: If you specify mailboxes then only the compliance copy stored in the user mailbox will be purged and not the item from the teams services itself. This will mean the item will remain visible to the user in Teams and can no longer be purged.
When purgeType is set to either recoverable or permanentlyDelete and purgeAreas is set to teamsMessages, the Teams messages are permanently deleted. In other words either option will result in the permanent deletion of the items from Teams and they cannot be recovered.
$params = @{ purgeType = “recoverable” purgeAreas = “teamsMessages” }
Once I have prepared my request body I will issue the following command.
Clear-MgSecurityCaseEdiscoveryCaseSearchData -EdiscoveryCaseId $ediscoveryCaseId -EdiscoverySearchId $ediscoverySearchId -BodyParameter $params
ediscoverySearch: purgeData – Microsoft Graph v1.0 | Microsoft Learn
Once the command has been issued it will proceed to purge the items that match the search criteria from the locations targeted. If I go back to my original example, we can now see the items has been removed from Teams.
Congratulations, you have made it to the end of the blog post. Hopefully you found it useful and it assists you to build your own operational processes for using the Graph API to issue search and purge actions.