Accéder à Exchange Online avec PowerShell : remplacer EWS par Microsoft Graph
EWS prendra fin dans Exchange Online le 1er octobre 2026. Voici comment enregistrer une application, authentifier un script PowerShell par certificat, limiter l’accès à certaines boîtes aux lettres et traiter les messages et pièces jointes via Microsoft Graph.
Microsoft mettra fin à Exchange Web Services (EWS) dans Exchange Online le 1er octobre 2026. Les scripts qui récupèrent des messages ou des pièces jointes depuis une boîte aux lettres doivent donc migrer vers Microsoft Graph.
L’exemple présenté dans cet article fonctionne sans connexion utilisateur : il télécharge les pièces jointes ZIP depuis une boîte aux lettres, les extrait, déplace les messages traités puis envoie un rapport. Il nécessite pour cela un enregistrement d’application, un certificat et deux autorisations Graph. Des valeurs comme example.com, l’ID du tenant et l’ID de l’application sont des espaces réservés.
1. Modules PowerShell requis
Trois modules du SDK Microsoft Graph suffisent, sans installer le méta-module complet Microsoft.Graph :
Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Mail, Microsoft.Graph.Users.Actions -Scope AllUsers
2. Enregistrement de l’application dans Entra ID
Un script non supervisé s’authentifie en tant qu’application avec ses propres droits. Dans le centre d’administration Entra, créez un nouvel enregistrement sous App registrations et attribuez les deux autorisations suivantes sous API permissions → Microsoft Graph → Application permissions :
-
Mail.ReadWrite: lire les e-mails et les déplacer après traitement -
Mail.Send: envoyer l’e-mail de rapport
Accordez ensuite le consentement administrateur et notez l’ID du tenant ainsi que l’Application (Client) ID.
3. Certificat plutôt que secret client
Une authentification App-Only fonctionne avec un secret client ou un certificat. Pour les tâches planifiées, un certificat est le meilleur choix : la clé privée reste dans le magasin de certificats et aucun mot de passe ne figure dans le script. Créez le certificat sur le serveur qui exécutera le script et n’exportez que la partie publique :
$cert = New-SelfSignedCertificate -Subject "CN=eCall-Graph" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-KeyExportPolicy NonExportable -KeySpec Signature `
-KeyLength 2048 -NotAfter (Get-Date).AddYears(2)
Export-Certificate -Cert $cert -FilePath .\eCall-Graph.cer
$cert.Thumbprint # -> im Skript als Thumbprint verwenden
Téléversez le fichier .cer-exporté dans l’enregistrement de l’application, sous Certificates & secrets. Le compte de la tâche planifiée doit disposer d’un droit de lecture sur la clé privée (certlm.msc → certificat → All Tasks → Manage Private Keys).
4. Limiter l’accès à certaines boîtes aux lettres
Les autorisations d’application s’appliquent initialement à toutes les boîtes aux lettres du tenant. Limitez donc l’application, à l’aide d’une Application Access Policy, à un groupe de sécurité à extension messagerie. Cette étape est exécutée une seule fois dans Exchange Online PowerShell :
New-ApplicationAccessPolicy -AppId "<App-ID>" `
-PolicyScopeGroupId "graph-mailboxes@example.com" `
-AccessRight RestrictAccess `
-Description "eCall Graph: nur Log-Postfach"
# Vérifier l’efficacité
Test-ApplicationAccessPolicy -AppId "<App-ID>" -Identity "ecall-logs@example.com"
5. Établir la connexion
L’authentification utilise l’ID du tenant, l’ID de l’application et l’empreinte du certificat, sans aucune interaction utilisateur :
$TenantId = "00000000-0000-0000-0000-000000000000"
$ClientId = "00000000-0000-0000-0000-000000000000"
$Thumbprint = "0000000000000000000000000000000000000000"
$Mailbox = "ecall-logs@example.com"
Import-Module Microsoft.Graph.Authentication, Microsoft.Graph.Mail, Microsoft.Graph.Users.Actions
Connect-MgGraph -TenantId $TenantId -ClientId $ClientId `
-CertificateThumbprint $Thumbprint -NoWelcome
6. Lire les messages et télécharger les pièces jointes ZIP
Le script peut à présent parcourir la boîte de réception, enregistrer et extraire les pièces jointes ZIP, puis déplacer les messages traités vers « Éléments supprimés ». Le téléchargement s’effectue via le point de terminaison /$value et Invoke-MgGraphRequest -OutputFilePath. Le contenu brut est ainsi écrit directement dans un fichier, sans conserver une pièce jointe volumineuse entièrement en mémoire :
Add-Type -AssemblyName System.IO.Compression.FileSystem
$Zielordner = "D:\Import\{0:yyyyMMdd_HHmmss}" -f (Get-Date)
$messages = Get-MgUserMessage -UserId $Mailbox -Top 100 `
-Property id, subject, hasAttachments
foreach ($msg in $messages) {
$ordner = Join-Path $Zielordner $msg.Id
New-Item -Path $ordner -ItemType Directory -Force | Out-Null
$anhaenge = Get-MgUserMessageAttachment -UserId $Mailbox -MessageId $msg.Id |
Where-Object {
$_.AdditionalProperties['@odata.type'] -eq '#microsoft.graph.fileAttachment' -and
$_.Name -like '*.zip'
}
foreach ($att in $anhaenge) {
$zip = Join-Path $ordner $att.Name
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/messages/$($msg.Id)/attachments/$($att.Id)/`$value"
Invoke-MgGraphRequest -Method GET -Uri $uri -OutputFilePath $zip
[System.IO.Compression.ZipFile]::ExtractToDirectory($zip, $ordner)
}
# déplacer l’e-mail traité vers « Éléments supprimés »
Move-MgUserMessage -UserId $Mailbox -MessageId $msg.Id -DestinationId "deleteditems" | Out-Null
}
Pour plus de 100 e-mails, utilisez Get-MgUserMessage -All ou la pagination ; pour une exécution mensuelle, un lot suffit généralement.
7. Envoyer l’e-mail de rapport via Graph
Send-MailMessage est également obsolète. Avec le même enregistrement d’application (autorisation Mail.Send), l’e-mail est envoyé directement via Graph, ici avec un fichier joint encodé en base64 :
$pfad = "D:\Reports\report.csv"
$body = @{
message = @{
subject = "eCall Report"
body = @{ contentType = "HTML"; content = "<b>Lauf erfolgreich</b>" }
toRecipients = @(@{ emailAddress = @{ address = "empfaenger@example.com" } })
attachments = @(@{
"@odata.type" = "#microsoft.graph.fileAttachment"
name = Split-Path $pfad -Leaf
contentBytes = [Convert]::ToBase64String([IO.File]::ReadAllBytes($pfad))
})
}
saveToSentItems = $true
}
Send-MgUserMail -UserId "reporting@example.com" -BodyParameter $body
8. Exécuter sans supervision
En tant que tâche planifiée, le script s’exécute sans connexion, car le certificat se trouve dans le magasin du compte :
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument '-NoProfile -ExecutionPolicy Bypass -File "D:\Scripts\graph-import.ps1"'
$trigger = New-ScheduledTaskTrigger -Daily -At 06:00
Register-ScheduledTask -TaskName "eCall-Graph-Import" -Action $action -Trigger $trigger `
-User "DOMAIN\svc-ecall" -Password (Read-Host "Passwort")
L’exemple complet avec journalisation et gestion des erreurs est disponible sur GitHub : pfstr/eCall-Log-Analyzer.

Commentaires
Les commentaires sont chargés depuis GitHub / Giscus.