Tracer & supprimer un email Exchange par Message‑ID avec PowerShell (Purview eDiscovery)

Besoin de retirer en urgence un courriel malveillant ou envoyé par erreur ? Voici une méthode fiable pour le tracer via son Message‑ID (RFC 5322) et le supprimer de toutes les boîtes aux lettres Exchange Online, en s’appuyant uniquement sur PowerShell et Microsoft Purview.

Sommaire

Vue d’ensemble

L’objectif est double : (1) identifier un message précis au moyen de son Message‑ID — l’identifiant unique présent dans les en‑têtes RFC 5322 —, puis (2) le retirer de toutes les boîtes aux lettres de l’organisation sans recourir à des commandes obsolètes. La solution moderne, supportée et traçable, consiste à utiliser Security & Compliance PowerShell (Microsoft Purview eDiscovery) : on crée une recherche ciblée par InternetMessageId, on vérifie les résultats, puis on exécute une action Purge à l’échelle du tenant.

Réponse & solution résumée

ÉtapeCommande (PowerShell)Points d’attention
Tracer le messageGet-MessageTrace -MessageId "<ID>"Traçage côté service cloud uniquement. Selon la fenêtre de rétention effective : recherche standard (souvent 10 jours) et recherche historique (jusqu’à 90 jours). En environnement hybride, complétez par Get-MessageTrackingLog sur les serveurs on‑premises.
Configurer la recherche Purview# Connexion à Security & Compliance PowerShell Connect-IPPSSession # Création d'une recherche ciblée par InternetMessageId New-ComplianceSearch -Name "DeleteByID" -ExchangeLocation All ` -ContentMatchQuery 'InternetMessageId:""'Le champ KQL exploitable est InternetMessageId (pas message-id ni MessageID). C’est aussi la propriété utilisée par Purview pour la déduplication.
Exécuter la rechercheStart-ComplianceSearch -Identity "DeleteByID"Surveillez l’état avec Get-ComplianceSearch jusqu’à Completed.
Vérifier les résultatsGet-ComplianceSearch -Identity "DeleteByID" | FL ItemsFound,StatusExportez éventuellement un rapport de vérification avant purge.
PurgerNew-ComplianceSearchAction -SearchName "DeleteByID" -Purge -PurgeType SoftDeleteSoftDelete déplace vers Éléments récupérables (réversible). HardDelete pour suppression irréversible. Maximum : 10 actions Purge simultanées et ~50 000 boîtes par recherche. Rôles requis dans le Portail Purview : Compliance Search + Search And Purge (ou Organization Management).

Pourquoi ne pas utiliser Search‑Mailbox ?

  • Cmdlet dépréciée et non recommandée dans les environnements modernes.
  • Traitement boîte par boîte (non scalable et long).
  • Limitations sévères (seuil sur le nombre de boîtes, pas d’action HardDelete supportée dans les scénarios actuels, audit et journalisation moindres).

Pré‑requis et préparation

  • Module PowerShell : installez/chargez ExchangeOnlineManagement. Install-Module ExchangeOnlineManagement -Scope CurrentUser -Force Import-Module ExchangeOnlineManagement # Pour le traçage côté EXO Connect-ExchangeOnline # Pour Purview eDiscovery Connect-IPPSSession
  • Autorisations (Microsoft Purview) : appartenance à un rôle ou groupe contenant Compliance Search et Search And Purge (ou Organization Management).
  • Licences : Microsoft 365 E5 / Purview (ou équivalent) pour l’eDiscovery et l’action Purge.
  • Contexte hybride : si Exchange on‑premises est impliqué, combinez le traçage EXO (Get-MessageTrace) et on‑prem (Get-MessageTrackingLog) pour une visibilité complète.

Message‑ID vs InternetMessageId : bien comprendre

Le Message‑ID est un identifiant unique défini par la norme RFC 5322 et inséré par le MUA/MTA dans l’en‑tête du message, généralement sous la forme : <GUID@domaine>. Dans le pipeline Microsoft 365, cette valeur est stockée sous la propriété InternetMessageId, qui est celle exploitée par les moteurs de recherche eDiscovery (KQL). D’où les points clés suivants :

  • Dans vos requêtes, utilisez toujours InternetMessageId:"<ID>" avec les chevrons et les guillemets.
  • Les alias historiques (MessageId:, message-id:) peuvent ne plus être reconnus selon les versions ; privilégiez systématiquement InternetMessageId.
  • Purview déduplique sur cette propriété : plusieurs copies du même message (boîtes partagées, boîtes primaires/archives) sont correctement identifiées.

Comment récupérer le Message‑ID ?

  • Outlook (bureau) : ouvrez le message > Fichier > Propriétés > copiez la valeur de Identificateur du message.
  • Outlook sur le web : affichez la source du message (actions avancées) et repérez l’en‑tête Message-ID:.
  • Graph/PowerShell : si besoin, recherchez côté API (voir plus bas).

Procédure détaillée pas à pas

1) Tracer le message

Commencez par confirmer que l’ID correspond bien au message que vous ciblez et qu’il a bien transité par Exchange Online :

# Connexion Exchange Online (si pas déjà fait)
Connect-ExchangeOnline

# Traçage direct par Message-ID

Get-MessageTrace -MessageId ""

Si rien ne remonte (fenêtre trop courte, message ancien), lancez une recherche historique dans EOP ou vérifiez côté on‑premises :

# Sur un serveur Exchange on‑premises
Get-MessageTrackingLog -MessageId "<ID>" | 
  Select-Object Timestamp,EventId,Source,Sender,Recipients,ServerHostname

2) Créer la recherche Purview ciblée

Une recherche eDiscovery (New-ComplianceSearch) ciblée par InternetMessageId s’applique à toutes les boîtes (-ExchangeLocation All couvre boîtes primaires et archives). Exemple :

Connect-IPPSSession

$searchName = "DeleteByID_" + (Get-Date -Format 'yyyyMMdd_HHmmss')
New-ComplianceSearch -Name $searchName -ExchangeLocation All `
-ContentMatchQuery 'InternetMessageId:""'

3) Lancer et suivre la recherche

Start-ComplianceSearch -Identity $searchName

# Suivi jusqu’à l’état Completed

do {
Start-Sleep -Seconds 5
$s = Get-ComplianceSearch -Identity $searchName
Write-Host ("Statut: {0} | ItemsFound: {1}" -f $s.Status, $s.ItemsFound)
} while ($s.Status -ne 'Completed')

4) Vérifier les résultats

Avant toute purge, vérifiez le volume et, si besoin, exportez un rapport de contrôle :

Get-ComplianceSearch -Identity $searchName | 
  Format-List Name,Status,ItemsFound,LastModifiedTime

Pour une prévisualisation (sans suppression), vous pouvez créer une action Preview et ouvrir le rapport associé.

5) Purger (SoftDelete ou HardDelete)

Choisissez le type de purge en fonction de votre modèle de rétention :

  • SoftDelete : déplace vers Éléments récupérables (dossier Recoverable Items) — réversible via eDiscovery/restore.
  • HardDelete : suppression irréversible — à n’utiliser qu’après validation et conformité avec vos politiques.
# SoftDelete (recommandé d'abord)
New-ComplianceSearchAction -SearchName $searchName -Purge -PurgeType SoftDelete

# ...ou HardDelete (définitif)

# New-ComplianceSearchAction -SearchName $searchName -Purge -PurgeType HardDelete

Limites de service : maximum 10 actions Purge simultanées ; ~50 000 boîtes par recherche. Patientez jusqu’à l’état Completed de l’action de purge avant de relancer une itération.

Script prêt à l’emploi : de la recherche à la purge

Le script ci‑dessous encapsule l’ensemble de la séquence. Il prend en entrée un InternetMessageId et un indicateur -HardDelete optionnel, gère le suivi d’état et journalise les étapes clés.

function Invoke-PurgeByInternetMessageId {
  [CmdletBinding(SupportsShouldProcess)]
  param(
    [Parameter(Mandatory=$true)]
    [ValidatePattern('<.*@.*>')]
    [string]$InternetMessageId,

```
[switch]$HardDelete,

[string]$ExchangeScope = 'All',     # Boîtes ciblées (All ou liste)
[int]$PollSeconds = 5,
[int]$TimeoutMinutes = 90
```

)

$purgeType = if ($HardDelete) { 'HardDelete' } else { 'SoftDelete' }
$searchName = "DeleteByID_{0}" -f (Get-Date -Format 'yyyyMMdd_HHmmss')

Write-Host "Connexion à Security & Compliance PowerShell..." -ForegroundColor Cyan
if (-not (Get-Module ExchangeOnlineManagement -ListAvailable)) {
throw "Module ExchangeOnlineManagement requis."
}

try {
if (-not (Get-PSSession | Where-Object {$*.ConfigurationName -eq 'Microsoft.Exchange'})) {
Connect-IPPSSession -ErrorAction Stop
}
} catch {
throw "Échec de connexion à IPPS: $($*.Exception.Message)"
}

$query = 'InternetMessageId:"{0}"' -f $InternetMessageId
Write-Host "Création de la recherche: $searchName" -ForegroundColor Cyan
New-ComplianceSearch -Name $searchName -ExchangeLocation $ExchangeScope -ContentMatchQuery $query -ErrorAction Stop | Out-Null

Write-Host "Démarrage de la recherche..." -ForegroundColor Cyan
Start-ComplianceSearch -Identity $searchName -ErrorAction Stop | Out-Null

$deadline = (Get-Date).AddMinutes($TimeoutMinutes)
do {
Start-Sleep -Seconds $PollSeconds
$s = Get-ComplianceSearch -Identity $searchName
Write-Host ("Statut: {0} | ItemsFound: {1}" -f $s.Status, $s.ItemsFound)
if ((Get-Date) -gt $deadline) { throw "Timeout recherche dépassé." }
} while ($s.Status -ne 'Completed')

if ($s.ItemsFound -eq 0) {
Write-Warning "Aucun élément trouvé pour $InternetMessageId. Abandon."
return
}

Write-Host ("{0} éléments trouvés. Lancement de la purge ({1})..." -f $s.ItemsFound, $purgeType) -ForegroundColor Yellow
$action = New-ComplianceSearchAction -SearchName $searchName -Purge -PurgeType $purgeType -ErrorAction Stop

do {
Start-Sleep -Seconds $PollSeconds
$a = Get-ComplianceSearchAction -Identity $action.Identity
Write-Host ("Action: {0} | Statut: {1}" -f $a.Name, $a.Status)
if ((Get-Date) -gt $deadline) { throw "Timeout purge dépassé." }
} while ($a.Status -ne 'Completed')

Write-Host "Purge terminée." -ForegroundColor Green
}

Affiner la recherche KQL (si besoin)

Si plusieurs messages partagent un même InternetMessageId (rare mais possible en cas d’altérations), vous pouvez croiser d’autres critères :

# InternetMessageId + date de réception
New-ComplianceSearch -Name "DeleteByID" -ExchangeLocation All `
  -ContentMatchQuery '(InternetMessageId:"<ID>") AND (Received>=2025-09-01 AND Received<=2025-10-07)'

# InternetMessageId + expéditeur

New-ComplianceSearch -Name "DeleteByID" -ExchangeLocation All `
-ContentMatchQuery '(InternetMessageId:"") AND (From:"[attaquant@exemple.com](mailto:attaquant@exemple.com)")'

Cas particuliers et bonnes pratiques

  1. Rétention des traces : la recherche temps réel couvre généralement 10 jours ; la recherche historique étend jusqu’à 90 jours. Certaines documentations internes évoquent 30 jours : vérifiez les capacités actuelles de votre tenant.
  2. Réversibilité : privilégiez SoftDelete pour commencer ; basculez en HardDelete seulement après validation (conservation, obligations légales, audit).
  3. Licences et rôles : assurez-vous que les rôles eDiscovery et l’action Purge sont autorisés pour votre compte d’administration.
  4. GUI alternative : l’Explorateur de menaces dans Defender for Office 365 (Plan 2) permet aussi un retrait par InternetMessageId avec supervision et rapports.
  5. Très grands tenants : si vous n’avez pas le rôle Search And Purge ou si vous souhaitez un contrôle programmatique par utilisateur, utilisez le SDK Graph : $filter = "internetMessageId eq '<ID>'" $msg = Get-MgUserMessage -UserId $userUpn -Filter $filter if ($msg) { Remove-MgUserMessage -UserId $userUpn -MessageId $msg.Id } C’est plus lent et soumis aux quotas de l’API, mais utile en dernier recours.

Hybridation et portée de la purge

  • Hybrid : la purge via Purview n’impacte que les boîtes hébergées dans Exchange Online. Les boîtes on‑premises doivent être traitées avec les outils locaux (par ex. Search-Mailbox on‑prem ou export/PST selon votre politique).
  • Boîtes archivées et partagées : -ExchangeLocation All couvre boîtes primaires et archives en ligne, y compris boîtes partagées et ressources.
  • Quarantaine et transports : si le message n’a pas atteint les boîtes (bloqué en quarantaine), la purge de boîte n’est pas nécessaire ; traitez la quarantaine via les commandes/quasi‑temps réel de Defender.

Audit, reporting et conformité

Conservez les preuves d’exécution : exports des résultats de recherche, logs d’actions de purge, captures d’écran du statut, identifiants de corrélation. Quelques commandes utiles :

# Détails de la recherche
Get-ComplianceSearch -Identity $searchName | FL *

# Détails de l'action de purge

Get-ComplianceSearchAction -SearchName $searchName |
Select-Object Name,Action,Status,CreatedBy,CreatedTime,LastModifiedTime

Intégrez ces éléments à votre dossier d’incident (IR) pour répondre aux exigences d’audit et de gouvernance.

Erreurs courantes et dépannage

SymptômeCause probableCorrectif
Aucun résultat alors que l’ID est correctID saisi sans chevrons ou guillemets ; fenêtre de temps inadaptéeUtilisez exactement InternetMessageId:"<ID>" ; élargissez les dates ou basculez sur une recherche historique
Connect-IPPSSession introuvableModule non installé ou version trop ancienneInstall-Module ExchangeOnlineManagement -Force puis réessayez
Purge bloquée à l’état Starting/InProgressQuota d’actions simultanées atteint ou surcharge côté serviceAttendez la finalisation des actions en cours ; relancez ensuite. Fractionnez par sous‑ensembles si nécessaire
Besoin de cibler un sous‑ensemble d’utilisateursPortée trop largeRemplacez -ExchangeLocation All par une liste ("user1@...", "user2@...") ou un groupe dynamique de sécurité (si pris en charge)

Variants utiles

# Cibler un groupe d'utilisateurs (liste explicite)
$users = @("alice@contoso.com","bob@contoso.com")
New-ComplianceSearch -Name "DeleteByID_Scope" -ExchangeLocation $users `
  -ContentMatchQuery 'InternetMessageId:"<ID>"'

# Restreindre par date ET expéditeur pour éviter les faux positifs

New-ComplianceSearch -Name "DeleteByID_Tight" -ExchangeLocation All `
-ContentMatchQuery '(InternetMessageId:"") AND (From:"[expediteur@contoso.com](mailto:expediteur@contoso.com)") AND (Received>=2025-10-01)'

Sécurité, risques et gouvernance

  • Séparation des rôles : l’action de suppression à l’échelle du tenant doit être strictement contrôlée (principe du moindre privilège, double validation si possible).
  • Conservation légale : si des boîtes sont en Litigation Hold / conservation, SoftDelete peut déplacer les éléments vers des dossiers de conservation (DiscoveryHolds) ; validez l’impact avec vos juristes.
  • Journalisation : activez l’audit unifié et archivez les rapports pour toute purge massive.

Résumé opérationnel

  1. Tracer le message et confirmer l’InternetMessageId.
  2. Créer une recherche Purview ciblée (InternetMessageId).
  3. Lancer la recherche et contrôler l’état.
  4. Vérifier le périmètre et la volumétrie (ItemsFound).
  5. Purger en SoftDelete (puis HardDelete si nécessaire et approuvé).
  6. Auditer : consigner rapports et identifiants d’actions, réexécuter jusqu’à disparition complète.

FAQ

La purge affecte‑t‑elle les éléments « Envoyés » ? Oui : la recherche se base sur InternetMessageId et couvre tous les dossiers des boîtes ciblées (boîte principale et archive).

Puis‑je annuler une purge ? SoftDelete est réversible via eDiscovery/restauration. HardDelete est définitive : à n’utiliser qu’après validation formelle.

Et les boîtes déléguées/partagées ? Incluses si vous utilisez -ExchangeLocation All. Pour limiter la portée, listez explicitement les cibles.

Que faire si l’ID contient des caractères non standard ? Respectez la forme exacte avec chevrons ; si nécessaire, échappez les guillemets dans la chaîne KQL.

Conclusion

En s’appuyant sur InternetMessageId et les cmdlets Compliance Search/Purge, vous disposez d’un processus fiable, auditable et supporté pour retirer un message à l’échelle d’Exchange Online. Cette approche remplace avantageusement les méthodes historiques et s’intègre proprement aux exigences de gouvernance et de conformité de Microsoft Purview.


Annexe : modèle de plan d’exécution

  • Valider l’ID (chevrons, exactitude, date d’envoi).
  • Identifier la surface touchée (volumétrie, boîtes partagées, archives).
  • Choisir la stratégie (SoftDelete d’abord, HardDelete si nécessaire).
  • Exécuter : recherche → vérification → purge → audit.
  • Documenter : journal d’incident, captures, rapports, approbations.
Sommaire