Get Graph Token
Zuletzt geändert: 14.04.2026 10:23

Übersicht

Get-GraphToken #

ÜBERSICHT #

Holt ein Microsoft Graph API Access-Token (Service- oder User-Flow).

SYNTAX #

Get-GraphToken -ServiceFlow [-Conn] <__ComObject> [-TenantId] <string> [[-ClientId] <string>]
    [-ClientSecret] <string> [[-Scope] <string>] [[-UserScope] <string>] [[-RedirectUri] <string>]
    [[-TokenPath] <string>]

BESCHREIBUNG #

Zentrale Token-Funktion für alle Graph-API-Operationen. Unterstützt zwei Flows:

Service-Flow (Client Credentials): Direkter Token-Abruf ohne Benutzerinteraktion. Geeignet für Server, Cronjobs und Hintergrundprozesse. Hat Zugriff auf alle Postfächer im Tenant. Benötigt TenantId, ClientId und ClientSecret.

User-Flow (OAuth2 PKCE): Interaktive Anmeldung über den Browser. Beim ersten Aufruf öffnet sich der Browser zur Anmeldung, danach läuft alles automatisch per Refresh-Token. Zugriff nur auf das eigene Postfach (/me). Benötigt nur die ClientId.

EINRICHTUNG IM AZURE PORTAL (https://portal.azure.com) #

SCHRITT 1: App registrieren Azure Portal -> “Microsoft Entra ID” -> “App-Registrierungen” -> “Neue Registrierung” - Name: z.B. “EULANDA Graph” - Kontotypen: “Nur Konten in diesem Organisationsverzeichnis” - Registrieren -> Die “Anwendungs-ID (Client)” auf der Übersichtsseite ist die ClientId -> Die “Verzeichnis-ID (Mandant)” ist die TenantId

SCHRITT 2: API-Berechtigungen hinzufügen App -> “API-Berechtigungen” -> “Berechtigung hinzufügen” -> “Microsoft Graph”

Für den SERVICE-FLOW (“Anwendungsberechtigungen” wählen):

  • Mail.Send (zum E-Mail-Versand)
  • Contacts.ReadWrite (zum Kontakt-Sync) -> Danach “Administratorzustimmung erteilen” klicken (Pflicht!)

Für den USER-FLOW (“Delegierte Berechtigungen” wählen):

  • Mail.Send
  • Contacts.ReadWrite
  • offline_access (für automatische Token-Erneuerung) -> Administratorzustimmung ist optional, Benutzer kann selbst zustimmen

SCHRITT 3a: Client Secret erstellen (nur für Service-Flow)

App -> “Zertifikate und Geheimnisse” -> “Neuer geheimer Clientschlüssel”

  • Beschreibung und Ablaufdatum wählen
  • “Hinzufügen” -> Den “Wert” sofort kopieren (wird nur einmal angezeigt!) = ClientSecret

SCHRITT 3b: Redirect-URI einrichten (nur für User-Flow)

App -> “Authentifizierung” -> “Plattform hinzufügen”

  • “Mobilgerät- und Desktopanwendungen” wählen (NICHT “Web”!)
  • Benutzerdefinierte Redirect-URI eingeben: http://localhost:8080/ -> Unter “Erweiterte Einstellungen”: “Öffentliche Clientflows zulassen” auf JA setzen
  • Speichern
Beide Flows können parallel in derselben App eingerichtet werden. Die App braucht dann sowohl das Client Secret (Schritt 3a) als auch die Redirect-URI (Schritt 3b).

VERWENDUNG #

Die Funktion ist symmetrisch aufgebaut: zwei Achsen legen den Modus fest.

  • -ServiceFlow gesetzt -> Service-Flow (Client Credentials). Fehlt der Switch -> User-Flow (OAuth2 PKCE).
  • -Conn gesetzt -> Credentials aus SQL-Registry. Fehlt -Conn -> alle nötigen Werte als Parameter übergeben.

Service-Flow aus Registry (empfohlen für Server, Cronjob, ABO-Lauf): $token = Get-GraphToken -ServiceFlow -Conn $conn

Service-Flow explizit (Ad-hoc-Skript ohne EULANDA-DB): $token = Get-GraphToken -ServiceFlow ` -TenantId ‘54197dd8-…’ -ClientId ‘c081dca9-…’ -ClientSecret ‘…’

User-Flow aus Registry (Arbeitsplatz mit EULANDA-Setup): $token = Get-GraphToken -Conn $conn

User-Flow explizit (Test, externes Skript): $token = Get-GraphToken -UserScope ‘Mail.Send offline_access’

PARAMETER #

-ServiceFlow #

Type: switch

Schalter, der zwischen Service-Flow (Client Credentials) und User-Flow (OAuth2 PKCE) unterscheidet. Ist der Switch gesetzt, wird der Service-Flow ausgeführt; fehlt er, läuft der User-Flow. In Kombination mit -Conn werden die Credentials aus der SQL-Registry gelesen (Set ServiceRegistry), ohne -Conn müssen -TenantId, -ClientId und -ClientSecret als Parameter übergeben werden (Set ServiceExplicit).

Der Service-Flow aus Registry (-ServiceFlow -Conn $conn) ist der empfohlene Weg für automatisierten Server-Versand (ABO-Läufe, Scheduled Tasks, Cronjobs): Credentials bleiben zentral in der EULANDA-Registry, das PowerShell-Skript braucht keine Secrets im Klartext.

-Conn #

Type: __ComObject

ADODB-Verbindungsobjekt zur EULANDA-Datenbank. Steuert, ob Credentials aus der Registry gelesen werden:

  • Zusammen mit -ServiceFlow -> liest ClientId, ClientSecret, TenantId und optional Scope aus \SYSTEM\Devices\EMail\GraphAPI\ServiceFlow.
  • Ohne -ServiceFlow (User-Flow) -> liest ClientId, TenantId und UserScope aus \SYSTEM\Devices\EMail\GraphAPI\UserFlow als Overrides.
  • Explizit per Parameter übergebene Werte haben Vorrang vor Registry-Werten, leere Registry-Werte lassen den Default stehen.
Beim Service-Flow aus Registry müssen ClientId, ClientSecret und TenantId vorhanden sein – fehlen Werte, wird ein klarer Fehler mit der Liste der fehlenden Felder geworfen.

-TenantId #

Type: string

Azure Verzeichnis-ID (Mandanten-ID). Zu finden im Azure Portal unter “Microsoft Entra ID” -> “Übersicht” oder auf der Übersichtsseite der App. Nur im Set ServiceExplicit erforderlich (Service-Flow ohne -Conn).

-ClientId #

Type: string
Default: 'c081dca9-2f08-475a-8691-5339e99ab42c'

Anwendungs-ID (Client-ID) der registrierten Azure-App. Zu finden im Azure Portal unter App-Registrierungen -> [App-Name] -> “Übersicht”. Im ServiceExplicit-Set Pflicht, im User-Flow optional mit Default auf die EULANDA-Standard-App. Im UserRegistry-Set überschreibt ein expliziter Parameter den Registry-Wert.

-ClientSecret #

Type: string

Geheimer Clientschlüssel der Azure-App. Wird unter “Zertifikate und Geheimnisse” erstellt. Der Wert wird nur einmal angezeigt – sofort kopieren! Nur im Set ServiceExplicit erforderlich.

-Scope #

Type: string
Default: 'https://graph.microsoft.com/.default'

OAuth2 Scope für den Service-Flow. Default: “https://graph.microsoft.com/.default" (alle konfigurierten Application Permissions). Muss normalerweise nicht geändert werden. Im ServiceRegistry-Set kann der Scope auch aus der Registry (Scope) gelesen werden; ein expliziter Parameter überschreibt den Registry-Wert.

-UserScope #

Type: string

OAuth2 Scope für den User-Flow. Leerzeichen-getrennte Liste der benötigten Berechtigungen. “offline_access” sollte immer dabei sein (für Refresh-Token). Im Set UserExplicit Pflicht, im Set UserRegistry optional – dort fällt die Funktion zurück auf den Registry-Wert (UserScope unter \GraphAPI\UserFlow) und bei leerem Registry-Eintrag auf den EULANDA-Standard “Mail.Send Contacts.ReadWrite offline_access”.

Beispiele: “Contacts.ReadWrite offline_access” (Kontakt-Sync) “Mail.Send offline_access” (E-Mail-Versand) “User.Read Mail.Send offline_access” (E-Mail mit Absender-Abfrage) “Contacts.ReadWrite Mail.Send offline_access” (beides)

-RedirectUri #

Type: string
Default: 'http://localhost:8080/'

Redirect-URI für den User-Flow. Default: “http://localhost:8080/”. Muss exakt mit der im Azure Portal konfigurierten URI übereinstimmen.

-TokenPath #

Type: string

Pfad zur Token-Datei für den User-Flow. Default: automatisch aus Scope abgeleitet ($env:APPDATA\Eulanda\graph-{scope-hash}.json). Verschiedene Scopes verwenden automatisch verschiedene Token-Dateien.

AUSGABEN #

string

Der access_token (Bearer-Token) als String. Kann direkt als Authorization-Header verwendet werden: “Bearer $token”

BEISPIELE #

# Service-Flow aus SQL-Registry (empfohlen für Server-/Batch-Betrieb).
# ClientId, ClientSecret und TenantId liegen zentral in der EULANDA-Registry
# unter \SYSTEM\Devices\EMail\GraphAPI\ServiceFlow -- kein Secret im Skript.
$conn = New-Object -ComObject ADODB.Connection
$conn.Open('File Name=C:\Eulanda\EULANDA_1 Mustermann.udl')
$token = Get-GraphToken -ServiceFlow -Conn $conn

Send-GraphMail -Token $token -AuthFlow Service -Conn $conn `
  -To 'kunde@beispiel.de' -Subject 'Monats-Rechnung' `
  -HtmlBody '<b>Siehe Anhang</b>' -Attachments 'C:\Temp\rechnung.pdf'
# -From entfällt -- wird aus \GraphAPI\ServiceFlow\From gezogen
# Service-Flow explizit (Ad-hoc-Skript ohne EULANDA-DB)
$token = Get-GraphToken -ServiceFlow `
  -TenantId '54197dd8-9c79-46ca-9d1f-a6c260a7cfab' `
  -ClientId 'c081dca9-2f08-475a-8691-5339e99ab42c' `
  -ClientSecret 'Ihr~ClientSecret-hier'

# Damit auf ein bestimmtes Postfach zugreifen (z.B. Kontakt-Sync):
Export-ContactToOutlook -Token $token -Conn $conn `
  -AddressMatch 'MUSTERKUNDE' -FolderName 'EULANDA' -CreateFolder `
  -UserEmail 'benutzer@firma.de'
# User-Flow aus Registry: alle Werte aus \GraphAPI\UserFlow
# (ClientId, TenantId, UserScope). Nützlich am EULANDA-Arbeitsplatz --
# zentrale Konfiguration, kein Scope im Skript.
$conn = New-Object -ComObject ADODB.Connection
$conn.Open('File Name=C:\Eulanda\EULANDA_1 Mustermann.udl')
$token = Get-GraphToken -Conn $conn
# User-Flow aus Registry mit Scope-Override: für einen Spezial-Scope
# den Registry-Scope übersteuern, ClientId/TenantId bleiben aus Registry.
$token = Get-GraphToken -Conn $conn -UserScope 'Calendars.ReadWrite'
# User-Flow explizit: Interaktive Anmeldung ohne EULANDA-DB
$token = Get-GraphToken -UserScope 'Contacts.ReadWrite offline_access'
# -> Browser öffnet sich, als eigener Benutzer anmelden
# -> Token wird gespeichert, nächster Aufruf braucht keinen Browser mehr
# -> ClientId fällt auf EULANDA-Standard-App zurück

# Damit auf das eigene Postfach zugreifen (kein -UserEmail nötig):
Export-ContactToOutlook -Token $token -Conn $conn `
  -AddressMatch 'MUSTERKUNDE' -FolderName 'EULANDA' -CreateFolder
# Token-Cache löschen (z.B. bei Benutzer-Wechsel) und neu anmelden
Remove-Item "$env:APPDATA\Eulanda\graph-*" -Force
$token = Get-GraphToken -UserScope 'Contacts.ReadWrite offline_access'
# -> Browser öffnet sich erneut zur Anmeldung

HINWEISE #

Übersicht der vier ParameterSets:

MerkmalServiceRegistryServiceExplicitUserRegistryUserExplicit
Switch/Conn-ServiceFlow + -Conn-ServiceFlow-Conn(keins von beiden)
Pflicht-Parameter-TenantId+ClientId+Secret-UserScope
Credentials-Quelle\GraphAPI\ServiceFlowParameter\GraphAPI\UserFlow + DefaultsParameter + Defaults
InteraktionKeineKeineBrowser (einmalig)Browser (einmalig)
Token-CacheKeiner (jedes Mal neu)Keiner (jedes Mal neu)Datei mit Refresh-TokenDatei mit Refresh-Token
API-Pfad/users/{email}/…/users/{email}/…/me/…/me/…
From nötigJa (aus Registry)JaNein (eigene Mailbox)Nein (eigene Mailbox)
Azure PermissionAnwendungsberechtigungAnwendungsberechtigungDelegierte BerechtigungDelegierte Berechtigung
Admin-Consent nötigJaJaNeinNein
Postfach-ZugriffAlle im TenantAlle im TenantNur eigenes + SharedNur eigenes + Shared
Typischer EinsatzServer, ABO-Lauf, CronAd-hoc SkriptArbeitsplatz, EULANDA-PCTest, externes Skript

Registry-Schema (EULANDA-SQL-Registry):

\SYSTEM\Devices\EMail\GraphAPI
AuthFlow = "User" | "Service"    # Default für UI-Versand (Delphi-Seite)
\SYSTEM\Devices\EMail\GraphAPI\UserFlow
ClientId, TenantId, UserScope, From   # alle optional (Fallbacks greifen)
\SYSTEM\Devices\EMail\GraphAPI\ServiceFlow
ClientId, ClientSecret, TenantId, From   # Credentials-Felder Pflicht
Scope                                    # optional

Die alten Root-Level-Values unter \GraphAPI werden nicht mehr gelesen.