Åtkomst till Exchange Online med PowerShell: ersätt EWS med Microsoft Graph
EWS upphör i Exchange Online den 1 oktober 2026. Så registrerar du en app, autentiserar ett PowerShell-skript med ett certifikat, begränsar åtkomsten till enskilda postlådor och hanterar meddelanden och bilagor via Microsoft Graph.
Microsoft avvecklar Exchange Web Services (EWS) i Exchange Online den 1 oktober 2026. Skript som hämtar meddelanden eller bilagor från en postlåda måste därför övergå till Microsoft Graph.
Exemplet i den här artikeln körs utan användarinloggning: det laddar ned ZIP-bilagor från en postlåda, packar upp dem, flyttar bearbetade meddelanden och skickar sedan en rapport. För detta behövs en appregistrering, ett certifikat och två Graph-behörigheter. Värden som example.com, klient-ID och app-ID är platshållare.
1. Nödvändiga PowerShell-moduler
Det räcker med tre moduler från Microsoft Graph SDK, inte hela metamodulen Microsoft.Graph:
Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Mail, Microsoft.Graph.Users.Actions -Scope AllUsers
2. Appregistrering i Entra ID
Ett obevakat skript loggar in som en applikation med egna behörigheter. Skapa en ny registrering i Entra Admin Center under App registrations och tilldela dessa två behörigheter under API permissions → Microsoft Graph → Application permissions:
-
Mail.ReadWrite: läsa e-post och flytta den efter bearbetning -
Mail.Send: skicka rapportmeddelandet
Bevilja sedan administratörsgodkännande och notera klient-ID samt Application (Client) ID.
3. Certifikat i stället för Client Secret
En app-only-inloggning fungerar med Client Secret eller certifikat. För schemalagda uppgifter är ett certifikat det bättre valet: den privata nyckeln stannar i certifikatarkivet och skriptet innehåller inget lösenord. Skapa certifikatet på servern som kör skriptet och exportera endast den offentliga delen:
$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
Ladda upp den exporterade .cer-filen i appregistreringen under Certificates & secrets. Kontot för Scheduled Task behöver läsbehörighet till den privata nyckeln (certlm.msc → certifikat → All Tasks → Manage Private Keys).
4. Begränsa åtkomsten till enskilda postlådor
Application Permissions gäller inledningsvis för alla postlådor i klientorganisationen. Begränsa därför appen med en Application Access Policy till en e-postaktiverad säkerhetsgrupp. Detta steg körs en gång i Exchange Online PowerShell:
New-ApplicationAccessPolicy -AppId "<App-ID>" `
-PolicyScopeGroupId "graph-mailboxes@example.com" `
-AccessRight RestrictAccess `
-Description "eCall Graph: nur Log-Postfach"
# Kontrollera att den gäller
Test-ApplicationAccessPolicy -AppId "<App-ID>" -Identity "ecall-logs@example.com"
5. Upprätta anslutningen
Inloggningen använder klient-ID, app-ID och certifikatets tumavtryck, helt utan användarinteraktion:
$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. Läs meddelanden och ladda ned ZIP-bilagor
Nu kan skriptet gå igenom inkorgen, spara och packa upp ZIP-bilagor samt flytta bearbetade meddelanden till «Borttagna objekt». Nedladdningen sker via slutpunkten /$value och Invoke-MgGraphRequest -OutputFilePath. Därmed hamnar råinnehållet direkt i en fil utan att en stor bilaga behöver hållas helt i arbetsminnet:
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)
}
# flytta bearbetat e-postmeddelande till "Borttagna objekt"
Move-MgUserMessage -UserId $Mailbox -MessageId $msg.Id -DestinationId "deleteditems" | Out-Null
}
Vid fler än 100 e-postmeddelanden: arbeta med Get-MgUserMessage -All eller sidindelning; för en månadskörning räcker vanligtvis en batch.
7. Skicka rapportmeddelande via Graph
Även Send-MailMessage är föråldrat. Via samma appregistrering (behörigheten Mail.Send) skickas e-postmeddelandet direkt via Graph, här med en fil som base64-kodad bilaga:
$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. Kör obevakat
Som en schemalagd uppgift körs skriptet utan inloggning eftersom certifikatet finns i kontots arkiv:
$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")
Det fullständiga exemplet med loggning och felhantering finns på GitHub: pfstr/eCall-Log-Analyzer.
Kommentarer
Kommentarerna hämtas från GitHub / Giscus.