Test-EWS

Die Exchange Web Services (Siehe EWS) sind quasi der Nachfolger der früheren MAPI/CDO-Schnittstelle, die aber anstelle von RPC/TCP auf HTTP bzw. besser auf HTTPS aufsetzen. Damit sind sie "Cloud" und "Internet-Tauglich". Nun bietet jeder Exchange 2007 (oder neuer) Server die EWS-Schnittstelle an, aber nicht immer kann ein Administrator sicher sein, dass Sie korrekt funktioniert oder über den Reverse Proxy korrekt veröffentlicht wird. Daher habe ich mit mir Test-EWS ein PowerShell-Beispiel geschrieben, mit dem ich die meisten Fälle einfach testen kann.

Download und Einsatz

Um ihre eigene Umgebung mit ein paar EWS-Anfragen zu testen, können sie das folgende PowerShell-Script herunterladen und auf ihre Anforderungen anpassen. Sie werden es aber anpassen müssen. Insbesondere wenn z.B. Autodiscover nicht korrekt implementiert ist und Sie dann besser die URL für die Webservices angeben.

Umgekehrt ist aber genau das auch das Ziel dieses Scripts: Man kann verschiedene Dinge manuell vorgeben um zu sehen, welche Teilkomponente ein Problem hat und über die optionale "Trace"-Funktion sind Fehler sehr schnell auszumachen.

test-ews.1.0.ps1

Das Skript trägt absichtlich die Version 1.0, da es wirklich der erste Wurf ist. Es half mir bislang bei Problemen mit einen Kunden und ist nie für den Dauereinsatz oder mehr gedacht gewesen. Es fehlen also alle Funktionen der Fehlerbehandlung, Logging etc. Es ist ein Test-Skript. Entsprechend finden Sie auch einige auskommentierte Zeilen, die ich als Vorlage im Skript belassen habe, um nicht immer danach suchen zu müssen.

Das Basisskript verbindet sich einfach mit dem angegebenen Postfach und zeigt die Anzahl der ungelesenen Mails im Posteingang.

Aufruf und Parameter

Für die Ausführung des Skripts reicht eine normale PowerShell als normaler Benutzer. Es ist weder die Exchange PowerShell noch eine privilegiert (Als Admin) gestartete PowerShell. Allerdings müssen Sie auf dem System die Exchange Web Services installiert haben. Ggfls. gibt es schon neuere Versionen.

Microsoft Exchange Web Services Managed API
Version 2.2. https://www.microsoft.com/en-us/download/details.aspx?id=42951
Version 2.1: http://www.microsoft.com/en-us/download/details.aspx?id=42022

Aktuell wird die Entwicklung auf GitHub weiter geführt und auf Nuget bereitgestellt
https://GitHub.com/officedev/ews-managed-api
https://www.nuget.org/packages/Microsoft.Exchange.WebServices/

Im Kopf des Skripts sind die Parameter aufgeführt:

param(
   [string]$MailboxSMTP = "User@msxfaq.local",
   [string]$Username    = "",
   [string]$Domain      = "",
   [string]$Password    = "",
   [string]$ServiceURL  = "",
   [switch]$useImpersonation,
   [string]$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll",
   [switch]$EWSTrace,
   [switch]$Verbose
)

Die Bedeutung erschließt sich schnell:

Parameter Bedeutung

MailboxSMTP

Das ist die SMTP-Adresse des Postfachs, welches per EWS geöffnet werden soll. Achten Sie darauf, das Sie hier die "Primäre SMTP-Adresse" verwenden. Sekundäre SMTP-Adressen funktionieren nicht zuverlässig

Username

Optional können Sie hier einen Benutzernamen hinterlegen. Wird kein Benutzer angegeben, nutzt das Skript den aktuell angemeldeten Anwender

Domain

Wenn Sie beim Feld "Benutzername" keinen UPN eingebend, dann sollten Sie hier die Domäne spezifizieren.

Password

Wenn Sie einen Benutzernamen angeben, sollten Sie auch ein Kennwort hinterlegen. Wer Kennworte nicht im Klartext abspeichern will, kann Sie z.B. mit einem "(read-host -Prompt "Password für $Domain\$Username")" einlesen oder verschlüsselt speichern. Siehe PS Passworte

ServiceURL

Das Skript versucht eine automatische Erkennung mittels "Autodiscover". Wenn dies nicht funktioniert, können Sie hier eine Exchange EWS-URL manuell angeben, z.B.

[string]$ServiceURL  = "https://exchange.msxfaq.local/EWS/Exchange.asmx",

dllpath

Dieser Parameter gibt den Pfad zur erforderlichen WebService DLL an, die sie auf dem Computer installiert haben müssen. z.B.

"C:\Program Files (x86)\Microsoft\Exchange\Web Services\2.1\Microsoft.Exchange.WebServices.dll"
"C:\Program Files\Microsoft\Exchange\Web Services\2.1\Microsoft.Exchange.WebServices.dll"

Den Pfad müssen Sie ggfls. an die bei ihnen installierte Version anpassen. 

useImpersonation

Setzen Sie diesen Parameter auf "$true", wenn Sie über EWS Impersonation mit dem angegebenen Benutzernamen auf das in "MailboxSMTP" angegebene Postfach per Impersonation zugreifen wollen.

EWSTrace

Wenn dieser Schaler aktiviert ist, liefert das Skript im Fehlerfall sehr ausführliche Informationen des Exchange Server sichtbar zurück.

Verbose

Dieser Schalter wird 1:1 an die aufgerufenen Commandlets weiter gegeben und das Skript selbst gibt einen Fortschritt mittels "Write-Verbose" aus.

Die Komplexität der Parameter ist also überschaubar.

Beispiel mit Tracing

Hier ein Beispielabruf eines Postfachs mit expliziter Angabe der meisten Parametern und aktiviertem EWSTrace. Durch den Trace sehen Sie sowohl die abgesetzten Anfragen als auch die Rückantwort als XML/SOAP-Information

PS C:\test-ews> .\test-ews.1.0.ps1 `
 -MailboxSMTP User1@msxfaq.local `
 -Username User1 `
 -Domain msxfaq `
 -Password Password1 `
 -EWSTrace `
 -ServiceURL https://ews.msxfaq.local/ews/exchange.asmx

<Trace Tag="EwsRequestHttpHeaders" Tid="6" Time="2014-10-27 07:28:02Z">
POST /ews/exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml User-Agent: ExchangeServicesClient/14.03.0032.000
Accept-Encoding: gzip,deflate


</Trace>
<Trace Tag="EwsRequest" Tid="6" Time="2014-10-27 07:28:02Z" Version="14.03.0032.
000">
  <?xml version="1.0" encoding="utf-8"?>
  <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="
http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://sc
hemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xml
soap.org/soap/envelope/">
    <soap:Header>
      <t:RequestServerVersion Version="Exchange2007_SP1" />
      <t:TimeZoneContext>
        <t:TimeZoneDefinition Id="W. Europe Standard Time" />
      </t:TimeZoneContext>
    </soap:Header>
    <soap:Body>
      <m:GetFolder>
        <m:FolderShape>
          <t:BaseShape>AllProperties</t:BaseShape>
        </m:FolderShape>
        <m:FolderIds>
          <t:DistinguishedFolderId Id="inbox" />
        </m:FolderIds>
      </m:GetFolder>
    </soap:Body>
  </soap:Envelope>
</Trace>


<Trace Tag="EwsResponseHttpHeaders" Tid="6" Time="2014-10-27 07:32:19Z">
200 OK
Connection: Keep-Alive
Transfer-Encoding: chunked
request-id: 2240404d-4a71-4b79-b064-0a126cb7da2b
X-CalculatedBETarget: exchange.msxfaq.local
Strict-Transport-Security: max-age=10886400; includeSubDomains,max-age=10886400;
 includeSubDomains
X-DiagInfo: EX01
X-BEServer: EX01
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Date: Mon, 27 Oct 2014 07:32:21 GMT
Set-Cookie: exchangecookie=c6adbb3c4b974498b7b64dd05fbe548f; expires=Tue, 27-Oct
-2015 07:32:22 GMT; path=/; HttpOnly,X-BackEndCookie=S-1-5-21-11949449-30417519-
71842111-1009=u56Lnp2e; expires=Mon, 27-Oct-2014 07:42:22 GMT; path=/ews; secure
; HttpOnly
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
Persistent-Auth: true
X-Powered-By: ASP.NET
X-FEServer: EX01


</Trace>
<Trace Tag="EwsResponse" Tid="6" Time="2014-10-27 07:32:19Z" Version="14.03.0032
.000">
  <?xml version="1.0" encoding="utf-8"?>
  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header>
      <h:ServerVersionInfo MajorVersion="15" MinorVersion="0" MajorBuildNumber="
775" MinorBuildNumber="35" Version="V2_4" xmlns:h="http://schemas.microsoft.com/
exchange/services/2006/types" xmlns="http://schemas.microsoft.com/exchange/servi
ces/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://w
ww.w3.org/2001/XMLSchema-instance" />
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="htt
p://www.w3.org/2001/XMLSchema">
      <m:GetFolderResponse xmlns:m="http://schemas.microsoft.com/exchange/servic
es/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/t
ypes">
        <m:ResponseMessages>
          <m:GetFolderResponseMessage ResponseClass="Success">
            <m:ResponseCode>NoError</m:ResponseCode>
            <m:Folders>
              <t:Folder>
                <t:FolderId Id="AAMkAGAl8uw==" />
                <t:ParentFolderId Id="AxqBdxPwfQEa+eAIApY4A=" ChangeKey="AQAAAA==" />
                <t:FolderClass>IPF.Note</t:FolderClass>
                <t:DisplayName>Posteingang</t:DisplayName>
                <t:TotalCount>3740</t:TotalCount>
                <t:ChildFolderCount>14</t:ChildFolderCount>
                <t:EffectiveRights>
                  <t:CreateAssociated>true</t:CreateAssociated>
                  <t:CreateContents>true</t:CreateContents>
                  <t:CreateHierarchy>true</t:CreateHierarchy>
                  <t:Delete>true</t:Delete>
                  <t:Modify>true</t:Modify>
                  <t:Read>true</t:Read>
                </t:EffectiveRights>
                <t:UnreadCount>11</t:UnreadCount>
              </t:Folder>
            </m:Folders>
          </m:GetFolderResponseMessage>
        </m:ResponseMessages>
      </m:GetFolderResponse>
    </s:Body>
  </s:Envelope>
</Trace>
Number or unread Messages :  11

Wenn die Daten nicht stimmen, dann sind die Fehlermeldungen meist aussagekräftig genug, um die Ursache zu beheben oder zu umschiffen.

Weitere Links