Teams und Exchange On-Premises

Teams legt einige Daten im Exchange Postfach ab, z.B. 1:1 Chats und natürlich Termine. Das funktioniert auch optimal, wenn alle Daten ebenfalls in der Cloud sind. Auf dieser Seite dokumentiere ich, wie im Dezember 2019 die Funktion mit einem On-Premises-Postfach und einem "Teams Only" User ohne lokale Skype for Business Konfiguration funktioniert. Schließlich legt Teams einige Daten auch im eigenen Exchange-Postfach ab, wie sie auf Teams Datenablage nachlesen können.

Hier gib es auch eine Tabelle der Funktionen die vorhanden sind und welche Einschränkungen es gibt:

Alle Aussagen sind aber eh nur eine Momentaufnahme, da Microsoft kontinuierlich sowohl die Koexistenz und Migration verbessert aber auch neue Funktionen in der Cloud addiert, die es nicht sofort oder vielleicht auch nie mit On-Premises geben wird.

MEC session, Exchange Server and Microsoft Teams Integration
https://youtu.be/Uo_yOiQrolk

Voraussetzungen

Technisch greift der Teams Client auf das Teams Backend zu, welches sich dann auf die Suche nach dem Exchange Postfach des Anwender macht. Solange das Postfach in Exchange Online liegt, gibt es kein Problem mit dem Zugriff darauf, da Teams ja das aus seiner Sicht "lokale" Postfach kennt.

Anscheinend nutzt Teams aber nicht plump "Autodiscover" sondern prüft erst den Eintrag in der Cloud um den Verweis auf das On-Premises-Postfach zu erhalten. Ich bin nicht mal sicher, ob Teams dann selbst per Autodiscover und EWS/REST auf das lokale Postfach zugreift oder die Exchange Online Services als Proxy nutzt.

Wenn das Postfach aber auf ihrem Exchange On-Premises Server liegt, dann sind einige Voraussetzungen zu erfüllen:

Voraussetzung Erfüllt

Exchange 2016 CU3 oder neuer

Eine Koexistenz mit älteren Versionen und Exchange 2013/2010 ist nicht mit Teams möglich. Erst Exchange 2016 CU3 unterstützt REST und AutoDV2

Exchange Hybrid Mode: ADSync

Für den Exchange Hybrid Mode ist es erforderlich, dass auch Exchange Online den Standort ihres Postfachs kennt. ADSync muss daher diese Informationen ins AzureAD und Exchange Online synchronisieren und auch die Checkbox die "Exchange Hybrid Mode" muss gesetzt sein. Sie können das einfach testen mit folgenden Aufruf:

Invoke-WebRequest "https://outlook.office365.com/autodiscover/autodiscover.json/v1.0/<smtpadresse>?Protocol=Rest"

Sie sollten auch anonym immer eine Antwort bekommen und im Content steht die URL zur Zielumgebung drin

Exchange AutodiscoverV2

Sie sehen schon beim der Kontrolle beim Prüfpunkt von ADSync, dass AutodiscoverV2 zum Einsatz kommt. Das muss ihr On-Premises Exchange Server natürlich unterstützen. Das "alte" Autodiscover mit XML-Dateien ist nicht ausreichend.

Exchange REST

Anscheinend ruft Teams die On-Premises Daten nicht per EWS sondern per REST über den Pfad "/API" ab. Seit Exchange 2016 CU3 ist es möglich, dass Sie per Exchange Online als Proxy auch Daten eines lokalen Postfachs abfragen, wenn der Hybrid-Mode richtig eingestellt ist. Wenn Teams das kann, dann können Sie das natürlich auch selbst testen.

Exchange OAUTH / Partnerapp

Damit sich Exchange Online natürlich gegenüber Exchange On-Premises legitimieren kann, richtet der Exchange Hybrid Assistent ja auch OAUTH ein. Prüfen Sie, ob die Einträge vorhanden sind.

Exchange Online Plan

Ich habe noch nicht geprüft, ob ein On-Premises Benutzer dennoch eine Exchange Online Lizenz benötigt.

Präsenz

Die Präsenzfunktion von Teams ist nicht von dem Ort ihrer Exchange Mailbox abhängig sondern allein von Teams Upgrade Mode. Wenn Sie "Teams Only" sind, dann ist ihre Präsenz in Teams und ansonsten eben in Skype for Business.

1:1 Chats

Interessant werden bei Teams die 1:1 Chats. Im Gegensatz zu Skype for Business, wo diese Konversationen vom Skype Client ggfls. im Postfach per Outlook-Schnittstelle gespeichert werden, entspricht das Teams Modell eher dem "Persistent Chat". Eine Konversation bleibt auch erhalten, wenn Sie Teams beenden und sie können die Konversation auch auf jedem anderen Gerät weiterführen. Also muss das Teams Backend die Informationen irgendwo ablegen. Anhand meiner Beschreibung auf Teams Datenablage wissen sie, dass diese Informationen in einem versteckten Ordner im Postfach abgelegt werden. Dazu muss aber das Teams Backend an das Postfach kommen, was mit Exchange Online problemlos ist.

Ich habe daher einen Chat zwischen zwei "Teams Only"-Benutzern durchgeführt und der Exchange On-Premise Anwender hat nur einen Browser genutzt. Damit fällt eine Interaktion mit Outlook flach und jeder Zugriff auf Exchange Postfächer kann per Fiddler analysiert werden.

Zuerst ist festzuhalten, dass die Partner miteinander kommunizieren können. Das war erst mal auch erwartet aber es stellt sich schon die Frage wo nun der Benutzer mit einem Exchange On-Premises-Postfach diese Konversationen ablegt.

Der Client hat zumindest nicht direkt auf den Exchange Server zugegriffen und auf dem Exchange Server habe ich auf die Schnelle auch keine Zugriffe vom Teams Backend gesehen. Ich habe von Gerüchten gehört, dass in dem Fall einer "On-Premises Mailbox" dennoch für den Benutzer ein kleines Rumpf-Postfach in der Cloud angelegt wird, in dem die Teams-Daten landen. Sobald das primäre Postfach dann in die Cloud verschoben werden, sollen die Daten zusammengeführt werden. Ein Hinweis dazu findet sich auf:


Quelle: https://docs.microsoft.com/en-us/microsoftteams/exchange-teams-interact

Termine

Eine zweite Komponente ist natürlich die Arbeit mit Terminen und Besprechungen. Die Daten hierzu liegen im Kalender des Exchange Postfach und natürlich kann der Anwender einfach per Outlook Termine planen. Das ging schon immer sowohl mit einem Exchange Online-Postfach als auch einem Exchange On-Premises Postfach und war unabhängig von der Exchange Server Version und Veröffentlichungen

Mit Exchange 2016 CU3 hat sich aber hier etwas geändert. Nun kann das Teams Backend auch einen On-Premises Exchange Server erreichen und der kann auch darauf antworten. Die Authentifizierung erfolgt als "Partner-App" und erfordert die Einrichtung des Exchange Classic Hybrid Mode mit dem HCW. Modern Hybrid oder MinHybrid geht nicht.

Wenn das Setup dann aber funktioniert, sehen Sie im Teams Client nicht nur den Kalender sondern auch alle Termine ihrer aktiven Mailbox. Hier sehen Sie das Postfach mit OWA des On-Premises Server mit zwei Terminen am 11./12 Dez 2019

Die gleichen Termine sehen Sie in Teams:

Sollte in ihrem Teams Client das Kalender-Symbol" nicht sichtbar sein, dann prüfen Sie bitte folgendes:

Prüfpunkt Erledigt

Korrekte Konfiguration Exchange Hybrid

Siehe Checkliste am Anfang der Seite hinsichtlich ADSync, AutoDV2, Hybrid-REST, OAUTH

Korrekter Teams Mode

Mit "SfbOnly" oder "SfBWith TeamsCollab" sehen Sie keinen Kalender. Mit dem den Teams Einstellungen "Island", "SfbWithTeamsCollabdAndMeeting" oder "TeamsOnly"

App Policy

Prüfen Sie, ob nicht eine Teams Richtlinie das "Termin"-Icon ausblendet. Wenn Sie früher z.B. Exchange 2013 genutzt haben, dann haben die Anwender das Symbol gesehen und eine Fehlermeldung bekommen. Per Policy haben Administratoren dann das Termin-Icon einfach ausgeblendet.

Ich habe mit Fiddler natürlich nachgeschaut, womit sich mein Client beim Klick auf "Kalender" verbindet und nur die folgenden Requests gesehen

Der Client spricht nicht mit dem Exchange Server direkt sondern in dem Fall mit dem Teams Backend. Bei einem Blick auf die Firewall-Logs sind dort auch die eingehenden Verbindungen von Office 365 (52er IP-Adressen) zu sehen. Teams nutzt EWS als Zugriff.

2019:12:11-23:55:24 utm httpd: id="0299" srcip="52.114.75.155" localip="80.66.20.20" size="1603" user="-"
   host="52.114.75.155" method="POST" statuscode="200" reason="-" extra="-" exceptions="" time="102809"
   url="/ews/exchange.asmx" server="owa.netatwork.de" port="443" query="" referer="-" cookie="-" set-cookie="exchangecookie=xxx;
   expires=Fri, 11-Dec-2020 22:55:24 GMT; path=/; HttpOnly, X-BackEndCookie=On-Premisesuser1xx@netatwork.de=xxx/xxx/xxx;
   expires=Fri, 10-Jan-2020 22:55:24 GMT; path=/ews; secure; HttpOnly" websocket_scheme="-" websocket_protocol="-"
   websocket_key="-" websocket_version="-" uid="xxx"
2019:12:11-23:56:24 utm httpd: id="0299" srcip="52.114.75.155" localip="80.66.20.20" size="1603" user="-"
   host="52.114.75.155" method="POST" statuscode="200" reason="-" extra="-" exceptions="" time="100231"
   url="/ews/exchange.asmx" server="owa.netatwork.de" port="443" query="" referer="-" cookie="-" set-cookie="exchangecookie=xxx;
   expires=Fri, 11-Dec-2020 22:56:24 GMT; path=/; HttpOnly, X-BackEndCookie=On-Premisesuser1xx@netatwork.de=xxx/xx/xxx;
   expires=Fri, 10-Jan-2020 22:56:24 GMT; path=/ews; secure; HttpOnly" websocket_scheme="-" websocket_protocol="-"
   websocket_key="-" websocket_version="-" uid="xxx"
2019:12:11-23:57:24 utm httpd: id="0299" srcip="52.114.75.9" localip="80.66.20.20" size="1603" user="-"
   host="52.114.75.9" method="POST" statuscode="200" reason="-" extra="-" exceptions="" time="107981"
   url="/ews/exchange.asmx" server="owa.netatwork.de" port="443" query="" referer="-" cookie="-" set-cookie="exchangecookie=xxx;
   expires=Fri, 11-Dec-2020 22:57:24 GMT; path=/; HttpOnly, X-BackEndCookie=On-Premisesuser1xx@netatwork.de=xxx/xxx/xxx;
   expires=Fri, 10-Jan-2020 22:57:24 GMT; path=/ews; secure; HttpOnly" websocket_scheme="-" websocket_protocol="-"
   websocket_key="-" websocket_version="-" uid="xxx"
2019:12:11-23:58:24 utm httpd: id="0299" srcip="52.114.75.31" localip="80.66.20.20" size="1603" user="-"
   host="52.114.75.31" method="POST" statuscode="200" reason="-" extra="-" exceptions="" time="243257"
   url="/ews/exchange.asmx" server="owa.netatwork.de" port="443" query="" referer="-" cookie="-" set-cookie="exchangecookie=xxx;
   expires=Fri, 11-Dec-2020 22:58:24 GMT; path=/; HttpOnly, X-BackEndCookie=On-Premisesuser1xx@netatwork.de=xxx/xxx/xxx;
   expires=Fri, 10-Jan-2020 22:58:24 GMT; path=/ews; secure; HttpOnly" websocket_scheme="-" websocket_protocol="-"
   websocket_key="-" websocket_version="-" uid="xxx"
2019:12:11-23:59:24 utm httpd: id="0299" srcip="52.114.75.9" localip="80.66.20.20" size="1601" user="-"
   host="52.114.75.9" method="POST" statuscode="200" reason="-" extra="-" exceptions="" time="99586"
   url="/ews/exchange.asmx" server="owa.netatwork.de" port="443" query="" referer="-" cookie="-" set-cookie="exchangecookie=xxx;
   expires=Fri, 11-Dec-2020 22:59:24 GMT; path=/; HttpOnly, X-BackEndCookie=On-Premisesuser1xx@netatwork.de=xxx/xxx/xxx;
   expires=Fri, 10-Jan-2020 22:59:24 GMT; path=/ews; secure; HttpOnly" websocket_scheme="-" websocket_protocol="-"
   websocket_key="-" websocket_version="-" uid="xxx"

Damit ist bestätigt, dass Teams die Kalender von Postfächern nutzt, die On-Premises liegen und die korrekt konfiguriert sind.

Voicemail

Eine weitere Komponente mit Exchange Beteiligung ist die Voicemail. Früher haben Teams und Skype for Business verpasste Anrufe auf ExchangeUM geroutet, welches dann die Mails per SMTP ins Postfach gesendet hat. Mit der Umstellung auf Cloud Voice Mail (CVM) übernimmt ein Azure-Service diese Funktion und liefert die Mails ebenfalls per SMTP an das Postfach aus. Teams kann hier allerdings noch nicht mithalten (Stand Dec 2019)

Auch hier habe ich mit Fiddler nachgeschaut und erkannt, dass der Zugriff auf Voicemail nicht über das Teams Backend geht, sondern Teams direkt versucht ein Exchange Online Postfach über die REST-API zu öffnen.

Der Request im Detail:

Die Fehlermeldung "REST API is not yet supported for this mailbox" ist natürlich in sofern irreführend, dass die Mailbox gar nicht in dem Zielsystem ist und Exchange Online nicht als Reverse Proxy auf eine Exchange On-Premises Umgebung fungiert.

Würde Teams dazu die Graph-API nutzen, dann wäre ein Zugriff möglich. Ich bin aber zuversichtlich, dass dieses Problem vielleicht auch noch mal von Microsoft angegangen wird. Es sollte ja sehr einfach sein im Teams Client auf Graph umzustellen.

Status nach Meetings

Das Teams Backend holst sich über EWS die Information über Besprechungen und kann so auch in Teams geplante Meetings in einem On-Premises-Postfach ablegen aber ob ich im Moment ein Meeting habe, wird anscheinend über Graph abgerufen:


Quelle: https://learn.microsoft.com/en-us/microsoftteams/troubleshoot/exchange-integration/teams-exchange-interaction-issue#step-1-verify-that-the-url-for-the-On-Premises-exchange-rest-api-has-been-published-on-the-public-network

Es reicht also nicht das virtuelle Verzeichnis "/EWS" freizugeben. Dass Teams diese Anfragen tatsächlich nutzt, sehen Sie dann im Exchange On-Premises IIS-Log anhand der Zugriffe. Wenn Sie noch etwas tiefer in die API schauen wollen, dann können Sie mit dem mit dem "Failed Request Tracing (FREB)" (Siehe  IIS - Webserver Troubleshooting) die API-Aufrufe erkennen. Dies ist insbesondere bei Fehlern interessant, z.B.

In der Antwort ist dann aber der Fehler zu sehen:

Weiter oben finde ich dann das Token, welches ich per https://jwt.io oder https://jwt.ms decodieren kann. Es ist gut am Start "ey" zu erkennen.

Allerdings sind das Tokens in Tokens. Das erste Token decodiert sich wie folgt (gekürzt):

"at": "eyJ0eXAiOiJKV1QiLCJu....",
  "ts": 1676897519,
  "m": "GET",
  "p#S256": "6oi4PlidDadjUPifDane4bm4aAVRK9zankZrOb1wS7I",
  "q#S256": "xPynp7vl7pJlVkP31k68HdunAUBC8m4rf8VA6eTl18w",
  "pft": "eyJ0eXAiOiJKV1QiLCJ..."
}

Hier finden sich die Felder "at" und "pft", die ihrerseits mit "ey" beginnen und einzeln decodiert werden können. Hier der Auszug (ebenfalls gekürzt)

# Partiell decodiertes Token aus dem Feld "at"

{
  "aud": "https://outlook.office.com",
  "iss": "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",
  "app_displayname": "Microsoft Teams Services",
  "appid": "cc15fd57-2c6c-4117-a88c-83b1d56b4bbe",
  "appidacr": "2",
  "idp": "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",
  "ver": "1.0",
}

Beim ersten Token scheint sich der Teams Service zu authentifizieren. Das zweite Token ist dann aber ein "Impersonate"-Token mit der Zielmailbox.

# Partiell decodiertes Token aus dem Feld "pft"

  "aud": "https://api.spaces.skype.com",
  "iss": "https://sts.windows.net/de21c301-a4ae-4292-aa09-6db710a590a6/",
  "appid": "5e3ce6c0-2b1f-4285-8d4b-75ee78787346",
  "family_name": "Carius Demo 4",
  "given_name": "Frank",
  "ipaddr": "217.91.247.140",
  "name": "Frank Carius Demo 4",
  "oid": "cc26eeec-eaae-4226-9ba6-0f9f68199db9",
  "onprem_sid": "S-1-5-21-11949449-30417519-71842111-14827",
  "puid": "100320004B1CE80D",
  "scp": "user_impersonation",
  "tid": "<uid des tenant>",
  "unique_name": "On-Premisesuser1@msxfaq.de",
  "upn": "On-Premisesuser1@msxfaq.de",
}

Wenn der lokale Exchange Server darauf allerdings nicht antwortet, dann kann es an einer fehlenden "Partner Application" sein.

Weitere Exchange On-Premises Einschränkungen

Ich habe natürlich nicht alle Funktionen von Teams und insbesondere die integrierbaren Dienste durchgetestet. Die Liste wäre sehr lange und die Aktualität sowieso sehr schnell in Frage gestellt. Einige Aussagen haben auch nicht wirklich was explizit mit Microsoft Teams zu tun, sondern beziehen sich generell auf die Einschränkungen von Exchange Online. Wer sein Postfach nicht in der Cloud hat, kann diverse andere Dienste natürlich auch nicht nutzen, z.B.:

  • Planner
    Kommentare zu Aufgaben sollten in der Group Mailbox landen aber anscheinend gibt es keine Benachrichtigungen, wenn jemand einen Task kommentiert
  • Microsoft To Do
    Funktioniert wohl nur mit Exchange Online
  • Microsoft Flow
    Kann nicht auf Trigger in Exchange/Outlook reagieren, wenn das Postfach On-Premises liegt.
  • SharePoint Online
    Auf der linken Seite gibt es einen Link zu "Konversationen", der anscheinend nur mit Exchange Online funktioniert
  • "Shared with Outlook"
    Mittlerweile kann ich eine Nachricht in Teams über "Share with Outlook" weiter reichen ,Teams nutzt dazu "Outlook on the Web" von Exchange Online. Bislang ist es mir nicht gelungen diese Funktion mit einem lokalen Exchange Postfach bereit zu stellen
    Share to Outlook from Teams
    https://support.microsoft.com/en-us/office/share-to-outlook-from-teams-f9dabbe9-9e9b-4e35-99dd-2eeeb67c4f6d 

Weitere Links