Exchange .NET Framework Upgrade – The Unsupported Kangaroo In The Room

It is critical Exchange installations are properly maintained in all regards.  In order to stay current with Exchange Cumulative Updates (CUs), it is necessary to read the release notes for a given CU to determine if an update is required for the .NET Framework.  Staying current on updates is required to receive full support from Microsoft.  Exchange Hybrid supports N and N-1 for on-premises CUs, and the same is typically true for security updates that are released for Exchange.

If support is added for a new version of .NET the update it will allow time for administrators to manage the change.  They can transition from the current CU, then to the new .NET version while it is optional so that when the new .NET is required with a subsequent CU the servers are already prepared.  For example, this happened with .NET 4.6.2 and Exchange 2016 CU5.   This is illustrated for Exchange 2016 in the image below which is from the official Exchange support matrix.  Note that each coloured box highlights which CUs support the given version of .NET Framework.

Note that you are given time to transition from the currently supported version of .NET to the next, that is indicate by the overlap of a given coloured box. Each box represents an instance where .NET required to be updated to a newer version.

This is the supported path to manage Exchange and .NET Framework updates.

Exchange Support Matrix For .NET Framework

What happens though when an environment is not maintained, and the updates are not properly managed?

That takes us off the supported path, and leads to an unsupported state.

Unsupported .NET Upgrade

Failing to install Exchange updates will place your environment at critical risk, especially when you are unable to rapidly install a Security Update for Exchange.

As an example, let's say that Exchange 2016 CU4 is installed on a server.  At the time of writing the current CU is 19.  Note that there is no overlap in the image above for that range of CUs with .NET Framework.

Exchange 2016 CU19 will NOT install onto that server as the verification pre-flight step will fail as .NET Framework 4.8 is required.

Directly upgrading .NET 4.6.2 to 4.8 is not supported, and this is where the lack of proactive maintenance causes an issue.  As stated here, doing this upgrade is not officially tested and supported by Microsoft.

Steps are outlined in Docs, but I would rather not have Exchange running on an unsupported .NET Framework at all so I personally modify the steps slightly so that Exchange services do not run until we have an aligned version of .NET Framework.

That still does not change the fact this is fundamentally an unsupported process, and Exchange servers need to be proactively maintained.

The below is an example to upgrade from Exchange 2016 CU4 to Exchange 2016 CU19 so that the Hafnium Security Update (SU) can be installed.   Note that you need to understand your services and how they are configured as your POP or IMAP services may be enabled.  The default Exchange services and their startup type is documented, but you should document and understand your environment before starting.

The high level process is outlined below, and PowerShell commands to start & stop services are included below.

  1. Ensure all the AD prep work was done – /PrepareSchema /PrepareAD etc.
  2. Place the Exchange server into maintenance mode
  3. Document Exchange services start up type (Automatic/Manual)
  4. Set all Exchange services to manual and stop
  5. Install .NET 4.8 from an elevated CMD prompt
  6. Restart server
  7. Either wait for .NET compilation or this blog post to make it go accelerando
  8. Once .NET has done its thing, and CPU usage has abated you may proceed
  9. Set Exchange services to the initial start up type, e.g. Automatic.  Do NOT start them though
  10. From an elevated CMD prompt, install Exchange 2016 CU19
  11. Setup will start a couple of services during setup then additional ones as setup progresses
  12. When CU19 setup completes successfully, verify service start up type is correct
  13. Restart server
  14. Verify services running and overall server health
  15. Install Exchange 2019 SU from an elevated CMD prompt or using Microsoft Update
  16. Restart server
  17. Verify services running and overall server health
  18. Install updates from Microsoft Update – ensure server is set to check for additional products.  There will be .NET security & quality updates to install for example
  19. Reboot server
  20. Verify services running and overall server health
  21. Run Exchange HealthChecker.ps1 script to ensure that no issues are noted.  Remediate if necessary
  22. Take sever out of maintenance mode
  23. Have a large single malt


To help with some of the tasks above, some sample automation is included below.
Then we move onto updating .NET and then installing the current Exchange CU at the end of this post.

List of Exchange 2016 Mailbox Services

We can use Get-Service to list all services that have "Microsoft Exchange" in their display name.

Get-Service | Where-Object {$_.DisplayName -match "Microsoft Exchange"}

There is an additional Exchange service (SearchExchangeTracing  -  Tracing Service for Search in Exchange) that is not directly exposed in services.msc and we will not modify that one.

List Services Containing The Word "Exchange"

There are 31 services listed there.  You can pipe to Measure-Object to count.

Get-Service | Where-Object {$_.DisplayName -Match "Microsoft Exchange"} | Measure-Object

We are focussing on the Exchange specific services, but there are additional dependencies. IISAdmin, Performance Logs & Alerts and the W3 Service.

Get-Service -Include "IISadmin", "W3SVC", "PLA" | Set-Service -StartupType Automatic
Get-Service -Include "IISadmin", "W3SVC", "PLA" | Start-Service



Stop Exchange Services

Set the service startup type to manual.  Then the next command disables the service.

Get-Service | Where-Object {$_.DisplayName -match "Microsoft Exchange"} | Set-Service -StartupType Manual
Get-Service | Where-Object {$_.DisplayName -match "Microsoft Exchange"} | Stop-Service -Force

Default Config - No POP or IMAP Enabled

Default config with no POP or IMAP enabled, then those services should be set to manual start up and will not be running.

Get-Service -Exclude "*POP*","*IMAP*" | Where-Object {$_.DisplayName -match "Microsoft Exchange"}

POP & IMAP Enabled

If you do have both IMAP and POP enabled those  front end and back end services will have been changed from the default configuration previously.

Get Service Status

The list of services that are concerned about also needs to include the Filter Management Service (FMS), Exchange Server Backup Extension (wsbexchange) and the Tracing Service for Search in Exchange (SearchExchangeTracing).  Not all of them have the word Exchange in the service display name, hence they are explicity added into the command.

Get-Service | Where-Object {$_.DisplayName -match "Microsoft Exchange" –OR $_.Name –eq "SearchExchangeTracing" -OR $_.Name –eq "wsbexchange" -OR $_.Name -eq "FMS" }


Set Services to Automatic Startup

Note that this ignores POP and IMAP. Only if you need them, enable those services afterwards or change the command.

Get-Service -Exclude "*POP*","*IMAP*" | Where-Object {$_.DisplayName -match "Microsoft Exchange" –OR $_.Name –eq "SearchExchangeTracing" -OR $_.Name –eq "wsbexchange" -OR $_.Name -eq "FMS"} | Set-Service -StartupType Automatic


Start Exchange Services

Start all services with "Microsoft Exchange" in their display name.  POP and IMAP are excluded.

Get-Service -Exclude "*POP*","*IMAP*"  | Where-Object {$_.DisplayName -match "Microsoft Exchange" –OR $_.Name –eq "SearchExchangeTracing" -OR $_.Name –eq "wsbexchange" -OR $_.Name -eq "FMS" } |Start-Service

Set POP & IMAP Services To Manual

If you accidentally set all Exchange services to Automatic, POP & IMAP are now running when you may not want that.  The section below will set those services back to the default startup of Manual.  Note this is done for both the Frontend and Backend services.

Get-Service -Include "*POP*","*IMAP*"| Set-Service -StartupType Manual

Then you should also ensure those services are stopped.

Get-Service -Include "*POP*","*IMAP*" | Stop-Service


Start Only POP & IMAP Services

Only starts the POP & IMAP Frontend and Backend services.

Get-Service -Include "*POP*","*IMAP*" | Start-Service

Additional 3rd Party Services

In case you also need to stop some additional 3rd party services, the commands can be easily modified.  Two additional services were added to the below sample command where services called 3rdPartyService#1 and 3rdPartyService#2 need to be stopped.

Get-Service -Exclude "*POP*","*IMAP*" | Where-Object {$_.DisplayName -match "Microsoft Exchange" -OR $_.Name -eq "3rdPartyService#1" -OR $_.Name -eq "3rdPartyService#2" }

Why Manual?

You may be wondering why the services were not set to a startup of disabled.  That is be cause setup will attempt to start some of the services during setup, and setup will fail if the services can not start.

If you look at the installation screenshots below, they are taken at different points during the CU upgrade.  The command prompt window illustrates where the Exchange installer is at with the upgrade.  Whilst the PowerShell window lists the Exchange services at that time.

Get-Service | Where-Object {$_.DisplayName -match "Microsoft Exchange" -and $_.Status -eq "Running"}

Exchange Services Set To Manual Rather Than Disabled - Else Can NOT Run During Setup

A similar picture is shown below. Note that setup has almost completed and is at the "Finalizing Setup" stage.

Exchange Services Set To Manual Rather Than Disabled - Else Can NOT Run During Setup - Example 2

Finally the third example shows even more services running as setup is almost complete.

Exchange Services Set To Manual Rather Than Disabled - Else Can NOT Run During Setup - Example 3


Rhoderick Milne [MSFT]

Leave a Reply

Your email address will not be published. Required fields are marked *