11 juillet 2026 5 min de lecture

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
Explication des options
OptionEffet
Microsoft.Graph.Authentication, Microsoft.Graph.Mail, Microsoft.Graph.Users.ActionsLes trois sous-modules nécessaires comme argument positionnel -Name : authentification, cmdlets de messagerie et actions telles que Send-MgUserMail
-Scope AllUsersInstalle les modules pour l’ensemble de la machine sous Program Files; nécessaire afin qu’ils soient également disponibles pour le compte de service de la tâche planifiée configuré ultérieurement (droits administrateur requis)

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
Explication des options
OptionEffet
New-SelfSignedCertificate -SubjectNom du sujet du certificat ; sert uniquement à l’identifier dans le magasin de certificats
-CertStoreLocation "Cert:\LocalMachine\My"Enregistre le certificat dans le magasin de l’ordinateur, et non dans celui de l’utilisateur ; il est ainsi disponible indépendamment de l’utilisateur connecté
-KeyExportPolicy NonExportableEmpêche l’exportation de la clé privée ; elle ne quitte pas le serveur
-KeySpec SignatureCrée une clé de signature ; l’authentification de l’application l’utilise pour signer l’assertion de demande de jeton
-KeyLength 2048Longueur de clé RSA de 2048 bits
-NotAfter (Get-Date).AddYears(2)Expiration dans deux ans ; le certificat devra alors être renouvelé et téléversé à nouveau
Export-Certificate -CertObjet certificat à exporter
-FilePathFichier cible ; il contient, sous la forme .cer, uniquement la partie publique

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"
Explication des options
OptionEffet
New-ApplicationAccessPolicy -AppIdApplication (Client) ID de l’enregistrement d’application auquel s’applique la stratégie
-PolicyScopeGroupIdGroupe de sécurité à extension messagerie dont les membres définissent le périmètre
-AccessRight RestrictAccessLimite l’application aux boîtes aux lettres du groupe ; l’alternative DenyAccess bloquerait précisément ces boîtes aux lettres
-DescriptionTexte libre destiné à documenter la stratégie
Test-ApplicationAccessPolicy -IdentityVérifie, pour une boîte aux lettres précise, si l’application peut y accéder (AccessCheckResult: Granted ou Denied)

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
Explication des options
OptionEffet
Connect-MgGraph -TenantIdTenant auprès duquel l’application s’authentifie
-ClientIdApplication (Client) ID de l’enregistrement d’application
-CertificateThumbprintSélectionne le certificat d’authentification dans le magasin local de certificats via son empreinte ; la combinaison de -ClientId et du certificat permet une authentification App-Only sans utilisateur
-NoWelcomeSupprime le message de bienvenue après l’authentification ; utile pour les sorties de scripts et les journaux

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
}
Explication des options
OptionEffet
Add-Type -AssemblyName System.IO.Compression.FileSystemCharge l’assembly .NET avec la classe ZipFile pour l’extraction
Get-MgUserMessage -UserIdBoîte aux lettres dont les messages sont lus ; cette indication est obligatoire avec l’authentification App-Only
-Top 100Limite la requête à 100 messages au maximum par appel
-Property id, subject, hasAttachmentsDemande uniquement les champs nécessaires ; cela réduit la réponse et accélère l’appel
Get-MgUserMessageAttachment -MessageIdMessage dont les pièces jointes sont listées
Invoke-MgGraphRequest -Method GETMéthode HTTP de l’appel direct à l’API Graph
-UriPoint de terminaison appelé ; le /$value ajouté renvoie le contenu brut du fichier joint au lieu d’un objet JSON
-OutputFilePathÉcrit la réponse directement dans le fichier cible sans conserver la pièce jointe complète en mémoire
Move-MgUserMessage -DestinationId "deleteditems"Déplace le message traité vers le dossier cible ; deleteditems est le nom de dossier connu pour « Éléments supprimés »

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
Explication des options
OptionEffet
-UserIdBoîte aux lettres au nom de laquelle l’e-mail est envoyé ; elle doit être couverte par le périmètre de l’Application Access Policy
-BodyParameterLe message complet sous forme de table de hachage dans le schéma Graph : message avec objet, corps, destinataires et pièces jointes, ainsi que saveToSentItems pour l’enregistrement dans « Éléments envoyés »

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")
Explication des options
OptionEffet
New-ScheduledTaskAction -ExecuteProgramme à exécuter, ici powershell.exe
-ArgumentLigne de commande du programme : -NoProfile ignore les scripts de profil, -ExecutionPolicy Bypass contourne la stratégie d’exécution pour cet appel et -File désigne le script
New-ScheduledTaskTrigger -Daily -At 06:00Déclencheur quotidien à 06:00
Register-ScheduledTask -TaskNameNom de la tâche dans le planificateur de tâches
-Action / -TriggerAssocie à la tâche l’action et le déclencheur créés précédemment
-UserCompte sous lequel la tâche est exécutée ; la clé privée doit être lisible dans son magasin de certificats
-Password (Read-Host "Passwort")Demande le mot de passe du compte de manière interactive afin que la tâche puisse démarrer même sans utilisateur connecté ; il ne se retrouve ainsi ni dans le script ni dans le fichier d’historique

L’exemple complet avec journalisation et gestion des erreurs est disponible sur GitHub : pfstr/eCall-Log-Analyzer.

Sources

  1. Microsoft – « Retrait d’Exchange Web Services dans Exchange Online »

    annonce et date butoir (1er octobre 2026) de la fin d’EWS dans Exchange Online.

    https://techcommunity.microsoft.com/blog/exchange/retirement-of-exchange-web-services-in-exchange-online/3924440
  2. Microsoft Learn – « Obtenir un accès sans utilisateur (App-only) »

    authentification App-Only auprès de Microsoft Graph avec certificat.

    https://learn.microsoft.com/en-us/graph/auth-v2-service
  3. Microsoft Learn – « Limiter les autorisations d’application à des boîtes aux lettres spécifiques »

    Application Access Policy pour restreindre l’application à certaines boîtes aux lettres.

    https://learn.microsoft.com/en-us/graph/auth-limit-mailbox-access

Commentaires

Les commentaires sont chargés depuis GitHub / Giscus.