Microsoft Graph REST API - Outlook Calendar with Powershell

Hallo zusammen,

Ich habe ja in der Vergangenheit viele Dinge über PowerShell und die Exchange Webservices Management API gemacht. Mit der Abschaltung von Basic Authentication wird das aber immer schwieriger. Früher gab es ja noch die Outlook REST API. Aber selbst die Outlook REST API V2.0 wird anscheinend nicht mehr weiterentwickelt.

https://developer.microsoft.com/en-us/office/blogs/migrating-from-outlook-rest-api-v1-0-to-microsoft-graph/
Version 1.0 of the
 Outlook REST API was launched in 2015 to provide API access to mail, calendar, contacts, and other data from Exchange Online, with support for Basic Authentication.  Over time, we’ve released major enhancements in Outlook REST API v2.0 and Microsoft Graph, both of which provide richer features, and better performance and reliability than Outlook REST API v1.0. Both Outlook REST API v2.0 and Microsoft Graph use OAuth 2.0 for authentication and authorization, which is a more secure and reliable way than Basic Authentication to access data.

With the planned deprecation of the Outlook REST API v1.0, you can update your app to Microsoft Graph and leverage all the new functionality available there.  This article will give you guidance on the process of upgrading from the Outlook v1.0 REST API to the Microsoft Graph REST API and well as pointing some of the key differences.

Microsoft Graph

Also habe ich mich mal mit der Microsoft Graph API und dem Zugriff auf die Outlook Kalender beschäftigt.

Microsoft Graph Auth Overview
https://docs.microsoft.com/en-us/graph/auth/

calendar resource type
https://docs.microsoft.com/en-us/graph/api/resources/calendar?view=graph-rest-1.0

Graph Explorer
https://developer.microsoft.com/en-us/graph/graph-explorer

Ein guter Einstieg ist auch immer der Graph Explorer um die Querys zu testen.

Der Graph Explorer ist als im Azure Active Directory als Enterprise Application eingetragen und benötigt je nach Zugriffe ebenfalls Berechtigungen mit Admin Consent.

Für den Zugriff via PowerShell braucht es eine registrierte App im Azure Active Directory. Für den Zugriff auf den Kalender brauche ich folgende Rechte:

Microsoft.Graph
Calendars.Read
Calendars.ReadWrite
Aber denkt daran, diese Rechte sind fast genau so mächtig wie Exchange Impersonation. Das heisst, damit habe ich die Berechtigungen auf alle Kalender in der Organisation zuzugreifen und dort zu schreiben und zu löschen.

Authentication und AccessToken

Das schwierigste ist jeweils sich zu Authentifizieren um einen Accesstoken zu bekommen. Mit folgendem Code klappt es.

#Variables
$ClientID = "9a8d72df-686a-496c-bc5e-a147d813abd1"
$ClientSecret = "ClientSecret"
$tenantID = "icewolfch.onmicrosoft.com"
$scope = "https://graph.microsoft.com/.default"
$authority = "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token"

$Body = @{
  "grant_type"    = "client_credentials";
  "client_id"     = "$ClientID";
  "client_secret" = "$ClientSecret";
  "scope"      = "$scope";
}

#Get AccessToken
$result = Invoke-RestMethod -Method POST -uri $authority -Body $body
$AccessToken = $result.access_token

Get Calendar

Get calendar
https://docs.microsoft.com/en-us/graph/api/calendar-get?view=graph-rest-1.0&tabs=http

Ich lasse mir mal die Kalenderfolder von meinem Benutzer anzeigen.

Beim Aufruf muss ein Header mit dem AccessToken mitgegeben werden.

$mailbox = "a.bohren@icewolf.ch"
$headers = @{"Authorization" = "Bearer "+ $AccessToken}
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/Calendars"
$Calendars = Invoke-RestMethod -Method GET -uri $uri -headers $headers
$Calendars.Value | fl name,id

List Events

List Events
Mit dem folgenden Codebeispiel, kann man sich die Kalendereinträge einer Mailbox anzeigen.

$mailbox = "a.bohren@icewolf.ch"
$headers = @{"Authorization" = "Bearer "+ $AccessToken}
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events"
Invoke-RestMethod -Method GET -uri $uri -headers $headers
$Events = Invoke-RestMethod -Method GET -uri $uri -headers $headers
$Events | Get-Member

Wie man sieht, gib es

$Events.Value | ft subject,start,end,location

TimeZone

Für Termine braucht man immer auch noch die TimeZone. Die Liste kann man sich mit folgendem Befehl anschauen:

Get-TimeZone -ListAvailable | ft id, Displayname

Create Event

Dann machen wir doch mal einen Kalender Eintrag.

Create Event
https://docs.microsoft.com/en-us/graph/api/user-post-events?view=graph-rest-1.0&tabs=http

$mailbox = "a.bohren@icewolf.ch"
$headers = @{
 "Authorization" = "Bearer "+ $AccessToken;
 "Prefer" = 'outlook.timezone="W. Europe Standard Time"';
 "Content-type"  = "application/json"
}

#Create JSON Object
$json = @"
{
  "subject":"Graph API Example",
  "body": {
    "contentType" : "HTML",
    "content" : "Write Graph API Powershell Script"
  },
  "start": {
      "dateTime" : "2020-04-30T07:00:00",
      "timeZone" : "W. Europe Standard Time"
  },
  "end": {
      "dateTime" : "2020-04-30T08:00:00",
      "timeZone" : "W. Europe Standard Time"
  },
  "location":{
      "displayName" : "HomeOffice"
  }
}
"@

$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events"
Invoke-RestMethod -Method POST -Uri $uri -Headers $headers -Body $json

Der Termin wurde im Kalender eingetragen

Get Event

Get event
https://docs.microsoft.com/en-us/graph/api/event-get?view=graph-rest-1.0&tabs=http

Beim Erstellen des Eintrags habe ich mir die ID gemerkt. Damit kann man direkt auf den Eintrag zugreifen

$id = "AQMkADU4NGU4M2ViLWM5NjctNGI0YS05ZmJhLTIyADdmYWI0MjRkYmQARgAAAzqJ2GWaRBxKv-EJWOBGbRAHAEZu88iLm85MjHqnrJ10b8oAAAIXkwAAAcb9AhgmYESSPal9iQNu6wAB0zikmgAAAA=="
$mailbox = "a.bohren@icewolf.ch"
$headers = @{"Authorization" = "Bearer "+ $AccessToken}
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events/$id"
Invoke-RestMethod -Method GET -uri $uri -headers $headers
$Events = Invoke-RestMethod -Method GET -uri $uri -headers $headers

Update Event

Update event
https://docs.microsoft.com/en-us/graph/api/group-update-event?view=graph-rest-1.0&tabs=http

Auch hier nutze ich wieder die ID um auf das Event zuzugreifen und dieses zu aktualisieren.

$id = "AQMkADU4NGU4M2ViLWM5NjctNGI0YS05ZmJhLTIyADdmYWI0MjRkYmQARgAAAzqJ2GWaRBxKv-EJWOBGbRAHAEZu88iLm85MjHqnrJ10b8oAAAIXkwAAAcb9AhgmYESSPal9iQNu6wAB0zikmgAAAA=="
$mailbox = "a.bohren@icewolf.ch"
$headers = @{
 "Authorization" = "Bearer "+ $AccessToken;
 "Content-type"  = "application/json"
}

$json = @"
 {
  "subject" : "Graph API Example Update",
 },
 {
   "location":{
    "displayName" : "Office Bern"
   }
 }
"@

$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events/$id"
Invoke-RestMethod -Method PATCH -Uri $uri -Headers $headers -Body $json

Das Subject wurde geändert, jedoch die Location wurde nicht angepasst... Vielleicht ist da noch was an meinem JSON falsch.

Delete Event

Delete event
https://docs.microsoft.com/en-us/graph/api/event-delete?view=graph-rest-1.0&tabs=http

Auch hier nutze ich wieder die ID um den Termin zu löschen

$id = "AQMkADU4NGU4M2ViLWM5NjctNGI0YS05ZmJhLTIyADdmYWI0MjRkYmQARgAAAzqJ2GWaRBxKv-EJWOBGbRAHAEZu88iLm85MjHqnrJ10b8oAAAIXkwAAAcb9AhgmYESSPal9iQNu6wAB0zikmgAAAA=="
$mailbox = "a.bohren@icewolf.ch"
$headers = @{"Authorization" = "Bearer "+ $AccessToken}
$uri = "https://graph.microsoft.com/v1.0/users/$Mailbox/calendar/events/$id"
Invoke-RestMethod -Method DELETE -uri $uri -headers $headers

Et voila, der Termin ist wieder weg.

Fazit: Ich hoffe das hat euch einen kleinen Überblick gegeben und hilft auch andern beim Einsteigen in den Umgang mit Microsoft Graph mit PowerShell.

Grüsse
Andres Bohren