update, upgrade, board

Exchange Control Panel und OWA nach CU Installation defekt

Vor einigen Tagen hatte ich ein seltsames Exchange Phänomen. Wegen Hafnium installierte ich das aktuelle CU mit allen CVs. Danach waren ECP und OWA nicht mehr zugreifbar.

Die Updates wurden so installiert, wie Microsoft vorschreibt und die Community es in vielen Blogbeiträgen und Communities empfiehlt (Wartungsmodus auf Server 1 aktiv – patchen – Wartungsmodus auf Server 1 deaktivieren – gleiches Vorgehen für Server 2). Nach der Installation hatte ich dann folgenden Fehler:

Der Text der Meldung (auf Englisch):

Could not load file or assembly ‚Microsoft.Exchange.Common, Version=15.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35‘ or one of its dependencies. The system cannot find the file specified.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.IO.FileNotFoundException: Could not load file or assembly ‚Microsoft.Exchange.Common, Version=15.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35‘ or one of its dependencies. The system cannot find the file specified.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Assembly Load Trace: The following information can be helpful to determine why the assembly ‚Microsoft.Exchange.Common, Version=15.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35‘ could not be loaded.
WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value HKLM\Software\Microsoft\Fusion!EnableLog to 1.

Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

Stack Trace:

[FileNotFoundException: Could not load file or assembly ‚Microsoft.Exchange.Common, Version=15.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35‘ or one of its dependencies. The system cannot find the file specified.]
System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type) +0
System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName) +100
System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) +47
System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase) +44
System.Web.Compilation.BuildManager.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase) +59
System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase) +49
[ConfigurationErrorsException: Could not load file or assembly ‚Microsoft.Exchange.Common, Version=15.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35‘ or one of its dependencies. The system cannot find the file specified.]
System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase) +515
System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, Boolean checkAptcaBit) +29
System.Web.Configuration.Common.ModulesEntry.SecureGetType(String typeName, String propertyName, ConfigurationElement configElement) +60
System.Web.Configuration.Common.ModulesEntry..ctor(String name, String typeName, String propertyName, ConfigurationElement configElement) +68
System.Web.HttpApplication.BuildIntegratedModuleCollection(List`1 moduleList) +221
System.Web.HttpApplication.GetModuleCollection(IntPtr appContext) +1153
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +139
System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +168
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +277
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +369
[HttpException (0x80004005): Could not load file or assembly ‚Microsoft.Exchange.Common, Version=15.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35‘ or one of its dependencies. The system cannot find the file specified.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +532
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +114
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +724

Komischer Fehler – aber auf jedem Exchange Server in der Umgebung reproduzierbar. PowerShell Verbindungen und Administration war noch möglich, nur die Webseiten ECP und OWA waren betroffen. Ich habe infolgedessen viele Stunden damit verbracht, Blogs und Webseiten zu lesen die sich mit diesem und ähnlichen Themen beschäftigen, aber keine hatte eine komplette Lösung für mich. Am Ende war der Schlüssel zum Erfolg eine Kombination als Blogartikeln und einem Script, welches im Exchange Scriptverzeichnis versteckt war.

IIS Einstellungen

Die Fehlersuche beginnt am IIS – dort geht man in das Menü Exchange Back End / ecp / Application Settings.

In den Anwendungseinstellungen muss man zuerst den Wert des Attributs BinSearchFolders prüfen. In meinem Fall standen hier total falsche Einträge. Die angegebene Systemvariable %ExchangeInstallDir% existierte auf meinen Exchange Servern überhaupt nicht. Diese kann man (nach meiner Erfahrung) recht bedenkenlos auf den ECHTEN Exchange Server Installationspfad anpassen, z.B. E:\Exchange. Die Variable enthält 3 Pfade, diese müssen alle angepasst werden und auch wieder im ursprünglichen Format abgespeichert werden (mit Strichpunkt getrennt). Beachtet man das nicht, dann läuft man Gefahr, noch mehr IIS Fehler zu produzieren. In meinem Fall sah das funktionierende Beispiel so aus:

Nach dieser Anpassung braucht es einen iisreset aus einer „Als Administrator ausführen“-Kommandozeile:

Mit etwas Glück ist das Problem nun schon gelöst. In meinem Fall ging es aber noch weiter.

Exchange CAS Update

Mit den angepassten IIS Einstellungen waren die Seiten zwar wieder aufrufbar aber ultrahässlich. Sie sahen aus als wäre da kein Style oder CSS hinterlegt:

Das weitere Troubleshooting zeigte dann, dass die Installation der CUs anscheinend die Verzeichnisse der Webseiten nicht sauber mit allen notwendigen Inhalten befüllt hatte. Warum? Keine Ahnung. Glücklicherweise lässt sich das durch ein vom Exchange mitgeliefertes Script beheben 🙂 Der Aufruf ist einfach und klappt in der PowerShell von überall, da das Exchange Scriptverzeichnis in der PATH Systemvariable registriert ist:

Nach ca 10 Minuten Laufzeit (auf jedem Server) ist das Script dann fertig – beim Beobachten fällt auf dass es viel repariert:

Es gibt einige Einträge mit Copying und Updating, das klingt sehr gut. Nachdem das Script seine Arbeit getan hat, habe ich versucht ECP und OWA wieder zu öffnen und das Ergebnis waren funktionierende Webseiten:

Natürlich schadet ein weiterer iisreset nicht bevor man ECP / OWA wieder öffnet, in meinem Fall war er aber nicht notwendig.

Published by Andreas

Gründer von M365 Evangelists Cloud-Architekt, Strategieberater, Consultant für Microsoft Technologien Graph API Enthusiast, PowerShell Enthusiast