Exchange Online Microsoft Graph APIs for permanent deletion

Hi All,
A few Weeks ago Microsoft has announced the Permanent Deletion of mailbox items.
It’s relatively simple. Instead of the “DELETE” HTTP Method you use the “POST” Method and add “/permanentDelete” to the URI.
###############################################################################
#Delete
#https://learn.microsoft.com/en-us/graph/api/message-delete?view=graph-rest-1.0&tabs=http
###############################################################################
DELETE /users/{UserId}/messages/{MessageId}
DELETE /users/{UserId}/mailFolders/{mailFolderId}/messages/{MessageId}
###############################################################################
#Permanently Delete
#https://learn.microsoft.com/en-us/graph/api/message-permanentdelete?view=graph-rest-1.0&tabs=http
###############################################################################
POST /users/{UserId}/messages/{MessageId}/permanentDelete
POST /users/{UserId}/mailFolders/{mailFolderId}/messages/{MessageId}/permanentDelete
Time for me to test the Functionality.
Entra Application
I’ve created an Entra App
with Application and Delegated Permissions
Note: In production Environement you should not mix Application and Delegated Permissions
I am using Application Access Policy
Connect-ExchangeOnline -ShowBanner:$false
Get-ApplicationAccessPolicy | Where-Object {$_.Appid -eq "c1a5903b-cd73-48fe-ac1f-e71bde968412"}
The Application Permission is limited to the Members of the Distribution Group
Get-DistributionGroupMember -Identity 05c4f6cf-e3e7-40a1-b3b0-f1eb680f78c9
Application Permissions
Getting the AccessToken with the PowerShell Module PSMSALNet that requires PowerShell 7.4.
###############################################################################
#Setting up the Variables for all Examples
###############################################################################
Import-Module PSMSALNet #Need PowerShell 7.4
$TenantId = "46bbad84-29f0-4e03-8d34-f6841a5071ad"
$AppID = "c1a5903b-cd73-48fe-ac1f-e71bde968412" #DelegatedMail
$RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
###############################################################################
#Authenticate with Certificate
###############################################################################
$CertificateThumbprint = "A3A07A3C2C109303CCCB011B10141A020C8AFDA3" #O365Powershell4.cer
$Certificate = Get-ChildItem -Path cert:\CurrentUser\my\$CertificateThumbprint
$HashArguments = @{
ClientId = $AppID
ClientCertificate = $Certificate
TenantId = $TenantId
Resource = "GraphAPI"
}
$Token = Get-EntraToken -ClientCredentialFlowWithCertificate @HashArguments
$AccessToken = $Token.AccessToken
Let’s check the AccessToken with JWTDetails
#Install-Module JWTDetails
Get-JWTDetails $AccessToken
Mailbox Folders
In the Postmaster Mailbox there is a Mail with the Subject “Claim your Exclusive AAVE Airdrop”.
List the Mailbox Folders of the Postmaster Mailbox
###############################################################################
# List Mailbox Folders
###############################################################################
$Mailbox = "Postmaster@icewolf.ch"
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/mailFolders"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Result = Invoke-RestMethod -Method "GET" -Uri $uri -Headers $Headers -ContentType $ContentType
$Result.value | Format-Table displayName, id
$Result.value | Where-Object {$_.displayName -eq "Posteingang"} | fl
There is a Subfolder with the Name “SubfolderPostmaster”
List the Subfolders of the Inbox Folder
###############################################################################
# List Child Mailbox Folders
# https://learn.microsoft.com/en-us/graph/api/mailfolder-list-childfolders?view=graph-rest-1.0&tabs=http
###############################################################################
$Mailbox = "Postmaster@icewolf.ch"
$FolderID = "AAMkADExY2U2ZWY2LTI0YzEtNGQ3Mi1iODY0LTZmNzQ2MWQxOWJlYQAuAAAAAADI11bk3aFKQJXy4z2GgQYRAQD4k93uZqwxSo0-0gbfaWPWAAAAr8HVAAA=" #Posteingang
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/mailFolders/$FolderId/ChildFolders"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Result = Invoke-RestMethod -Method "GET" -Uri $uri -Headers $Headers -ContentType $ContentType
$Result.value | Format-List displayName, id
Let’s delete the Subfolder “Posteingang/SubfolderPostmaster”
###############################################################################
# Permanently delete Child Mailbox Folder
###############################################################################
$Mailbox = "Postmaster@icewolf.ch"
$FolderID = "AAMkADExY2U2ZWY2LTI0YzEtNGQ3Mi1iODY0LTZmNzQ2MWQxOWJlYQAuAAAAAADI11bk3aFKQJXy4z2GgQYRAQD4k93uZqwxSo0-0gbfaWPWAAAAr8HVAAA=" #Posteingang
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/mailFolders/$FolderID/permanentDelete"
$ChildFolderID = "AAMkADExY2U2ZWY2LTI0YzEtNGQ3Mi1iODY0LTZmNzQ2MWQxOWJlYQAuAAAAAADI11bk3aFKQJXy4z2GgQYRAQD9DAdvUOIbRK2TMu1gBCF9AAaGE3zBAAA=" #Posteingang/Subfolder
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/mailFolders/$FolderID/childFolders/$ChildFolderID/permanentDelete"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Result = Invoke-RestMethod -Method "POST" -Uri $uri -Headers $Headers -ContentType $ContentType
$Result
The Subfolder is deleted and nothing appears in the “Deleted Items” Folder
Emails
List Mailbox Message
###############################################################################
# List Mailbox Message
# https://docs.microsoft.com/en-us/graph/api/user-list-messages?view=graph-rest-1.0&tabs=http
###############################################################################
$Mailbox = "Postmaster@icewolf.ch"
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/messages"
$FolderID = "AAMkADExY2U2ZWY2LTI0YzEtNGQ3Mi1iODY0LTZmNzQ2MWQxOWJlYQAuAAAAAADI11bk3aFKQJXy4z2GgQYRAQD4k93uZqwxSo0-0gbfaWPWAAAAr8HVAAA=" #Posteingang
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/mailFolders/$FolderID/messages"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Result = Invoke-RestMethod -Method "GET" -Uri $uri -Headers $Headers -ContentType $ContentType
$Result.value[0] | Format-List
#List Messages
#$Result.value | Format-List id,receivedDateTime, subject, hasAttachments, importance, internetMessageId,isRead
Let’s permanently delete that Message
###############################################################################
# Permanent Delete Mailbox Message
# https://learn.microsoft.com/en-us/graph/api/message-permanentdelete?view=graph-rest-1.0&tabs=http
###############################################################################
$Mailbox = "Postmaster@icewolf.ch"
$MessageID = "AAMkADExY2U2ZWY2LTI0YzEtNGQ3Mi1iODY0LTZmNzQ2MWQxOWJlYQBGAAAAAADI11bk3aFKQJXy4z2GgQYRBwD4k93uZqwxSo0-0gbfaWPWAAAAr8HVAAD9DAdvUOIbRK2TMu1gBCF9AAaBvvhvAAA="
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/messages/$MessageID/permanentDelete"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Result = Invoke-RestMethod -Method "POST" -Uri $uri -Headers $Headers -ContentType $ContentType
$Result
The Email with the Subject “Claim your Exclusive AAVE Airdrop” has been deletet
And its not in the “Deleted Items” Folder
And it’s not in the “Recoverable Items” Folder
Calendar
Let’s have a look into the Calendar
Attendee
Let’s have a look at the Meeting with the Subject “Lunch” where Postmaster is an Attendee
###############################################################################
#List Events
#https://docs.microsoft.com/en-us/graph/api/user-list-events?view=graph-rest-1.0&tabs=http
###############################################################################
$Mailbox = "postmaster@icewolf.ch"
$headers = @{"Authorization" = "Bearer "+ $AccessToken}
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events"
$Events = Invoke-RestMethod -Method GET -uri $uri -headers $headers
$Event = $Events.Value | Where-Object {$_.Subject -eq "Lunch"}
$Event | Format-List id,subject,start,end,location
$Event.attendees
$Event.organizer
The Meeting with the Subject “Lunch” ist organized by a.bohren@icewolf.ch and has been accepted
Tracking Status of the Organizer
###############################################################################
# permanentDelete Event
# https://learn.microsoft.com/en-us/graph/api/event-permanentdelete?view=graph-rest-1.0&tabs=http
###############################################################################
$Mailbox = "postmaster@icewolf.ch"
$EventId = "AAMkADExY2U2ZWY2LTI0YzEtNGQ3Mi1iODY0LTZmNzQ2MWQxOWJlYQBGAAAAAADI11bk3aFKQJXy4z2GgQYRBwD4k93uZqwxSo0-0gbfaWPWAAAAr8HeAAD9DAdvUOIbRK2TMu1gBCF9AAaEx9GSAAA=" #Lunch
$headers = @{"Authorization" = "Bearer "+ $AccessToken}
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events/$EventID/permanentDelete"
$Result = Invoke-RestMethod -Method "POST" -uri $uri -headers $headers
The Tracking Status now shows “Declined”
Organizer
Let’s have a look at the Meeting “Important Meeting” where a.bohren is the Organizer
###############################################################################
#List Events
#https://docs.microsoft.com/en-us/graph/api/user-list-events?view=graph-rest-1.0&tabs=http
###############################################################################
$mailbox = "a.bohren@icewolf.ch"
$headers = @{"Authorization" = "Bearer "+ $AccessToken}
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events"
$Events = Invoke-RestMethod -Method GET -uri $uri -headers $headers
$Event = $Events.Value | Where-Object {$_.Subject -eq "Important Meeting"}
$Event | Format-List id,subject,start,end,location
$Event.attendees
$Event.organizer
Let’s permanently delete the Meeting as Organizer
###############################################################################
# permanentDelete Event
# https://learn.microsoft.com/en-us/graph/api/event-permanentdelete?view=graph-rest-1.0&tabs=http
###############################################################################
$mailbox = "a.bohren@icewolf.ch"
$EventId = "AQMkADU4NGU4M2ViLWM5NjctNGI0YS05ZmJhLTIyADdmYWI0MjRkYmQARgAAAzqJ2GWaRBxKv-EJWOBGbRAHAEZu88iLm85MjHqnrJ10b8oAAAIXkwAAAcb9AhgmYESSPal9iQNu6wADI9gFawAAAA==" #Important Meeting
$headers = @{"Authorization" = "Bearer "+ $AccessToken}
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events/$EventID/permanentDelete"
$Result = Invoke-RestMethod -Method "POST" -uri $uri -headers $headers
A cancelation Email has been sent out.
Regards
Andres Bohren