Category Archives: Exchange

Exchange Security Updates August 2022

On August 9, 2022 Microsoft has released important Security Updates for Exchange 2013, Exchange 2016 and Exchange 2019 that are rated ‘critical’ (Elevation of Privileges) and ‘important’ (Information Disclosure).

This security update rollup resolves vulnerabilities found in Microsoft Exchange Server. To learn more about these vulnerabilities, see the following Common Vulnerabilities and Exposures (CVE):

  • CVE-2022-21979 – Microsoft Exchange Information Disclosure Vulnerability
  • CVE-2022-21980 – Microsoft Exchange Server Elevation of Privilege Vulnerability
  • CVE-2022-24477 – Microsoft Exchange Server Elevation of Privilege Vulnerability
  • CVE-2022-24516 – Microsoft Exchange Server Elevation of Privilege Vulnerability
  • CVE-2022-30134 – Microsoft Exchange Server Elevation of Privilege Vulnerability

This Security Update introduces support for Extended Protection. Extended protection enhances authentication to mitigate ‘man in the middle’ attacks. Extended protection is supported on the latest version of Exchange 2016 and Exchange 2019 (2022H1) and the August 2022 Security Update (this one) so it is vital to bring your Exchange servers up-to-date. 

Be aware of the following limitations:

  • Extended protection is only supported on the current and previous versions of Exchange (i.e. Exchange 2016 CU21/CU21 and Exchange 2019 CU12/CU11) and Exchange 2013 CU23 with the August 2022 SU installed
  • Extended protection is not supported on hybrid servers with the hybrid agent.
  • Extended protection is not supported with SSL Offloading. SSL Re-encrypt (also knows as SSL Bridging) is supported, as long as the SSL certificate on the load balancer is identical to the SSL certificate on the Exchange servers.
  • If you still have Exchange 2013 in your environment and you are using Public Folders, make sure your Public Folders are hosted on Exchange 2016 or Exchange 2019.

Note. Make sure you have your Exchange server properly configured with all related security settings. Use the latest HealthChecker.ps1 script to find any anomalies in your Exchange configuration. If you fail to do so, the script to enable Extended Protection will fail with numerous error messages.

Enable Extended Protection

First off, make sure you have the latest Cumulative Update installed on all your Exchange servers and install the August 2022 Security Updates on all your servers, including the Exchange 2013 servers.

Another important thing is that you must make sure that TLS settings across all Exchange servers are identical. You can use the healthchecker.ps1 script to figure out if this is the case. Personally, it took me quite some time to get this right.

The easiest way to configure Extended Protection is by using the ExchangeExtendedProtectionManagement.ps1 script (which can be found on github). This script can enable Extended Protection on all Exchange servers in your organization, but by using the -SkipExchangeServerNames option you can exclude certain Exchange servers (for example, Exchange 2013 servers or servers running the hybrid agent). There’s also the -ExchangeServerNames option which lets you specify which servers to enable the Extended Protection on.

More information and downloads can be found here:

Exchange versionDownloadKB article
Exchange 2013 CU23
Exchange 2016 CU22
Exchange 2016 2022H1
Exchange 2019 CU11
Exchange 2019 2022H1
Exchange Protection Script
Healthchecker scripts

Some important notes:

  • As always, make sure you thoroughly test this in your lab environment, especially enabling Extended protection.
  • You can start the SU from a command prompt or from Windows Explorer, no need anymore to start from a command prompt with elevated privileges.
  • This SU contains all security updates from previous SUs for this particular Exchange version.

Export-ExchangeCertificate not accepting -FileName option

As long as I can remember I have been creating, updating, renewing, exporting and importing Exchange certificates on Exchange servers.

This morning I had to renew my own Exchange certificate, and my PowerShell command Export-ExchangeCertificate failed on the -FileName option so it would not accept the option to store the file somewhere. This is strange, because in our Exchange 2016/2019 book that was released less then a year ago we were able to use the -FileName option.

It turned out that for the Export-ExchangeCertificate and Import-Certificate the -FileName option was removed because of security concerns. In more detail, the -FileName option accepts a UNC path which makes it possible for compromised servers to access other servers using UNC paths.

The way to export a certificate in Exchange 2016 CU23 and Exchange 2019 CU12 (and higher) is to import the certificate in a variable and store this in a file:

[PS] C:\> $Cert = Export-ExchangeCertificate -BinaryEncoded -Thumbprint <Thumbprint> -BinaryEncoded -Password (ConvertTo-SecureString -String 'Pass1word' -AsPlainText -Force)
[PS] C:\> [System.IO.File]::WriteAllBytes('C:\Install\CertExport.pfx', $Cert.FileData)

For importing certificates it is similar, the -FileName is removed from the commandlet in Exchange 2016 CU23 and Exchange 2019 CU12 (and higher), and the -FileData needs to be used:

[PS] C:\> Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path "<local or UNC path>" -Encoding byte)) -Password (ConvertTo-SecureString -String 'Pass1word' -AsPlainText -Force)

Note. For Exchange 2013 server the -FileName option can still be used.

More information can be found on and

Exchange 2016 and Exchange 2019 SMTP Relay

The last couple of days I have been working with multiple customers on SMTP relay in Exchange 2016 during a migration from Exchange 2010 to Exchange 2016. The last time I did that was with Exchange 2010, almost 9 years ago and things have changed over the years. The changes in Exchange 2016 are carried forward in Exchange 2019…. Oh, and this is true for Exchange 2013 as well, but since Exchange 2013 is already out of support and none of my customers is using Exchange 2013 I’ll skip this….

Exchange 2010 has the Hub Transport service for SMTP, and this is using port 25 for communicating with other SMTP hosts. Exchange 2016 and Exchange 2019 have two services for SMTP transport:

  • Front-End Transport service (FETS) listening on port 25. This is where other SMTP hosts connect to. In the Exchange 2016 Admin Center the FETS Receive Connector is identified as Default Frontend <server> . In Exchange 2013, this service was running on the Client Access Server.
  • Hub Transport Service listening on port 2525. This is a back-end service used by FETS and other Exchange Hub Transport back-end services. Clients are not expected to use the Hub Transport service on port 2525. In the Exchange Admin Center this Receive Connector is identified as Default <server> . In Exchange 2013, this service was running on the Mailbox server.

These connectors are shown in the following screenshot. The Default Frontend Receive Connector (on port 25) is selected, the red arrow points to the Hub Transport Receive Connector on port 2525.

Note. The Client Frontend Receive Connector in the screenshot is listening on port 587 and is used for authenticated SMTP clients like Mozilla Thunderbird.

SMTP Relay in Exchange 2016 and 2019

The Default Frontend Receive Connector allows all SMTP clients to connect to it and drop email messages for local delivery. You don’t want to configure this connector to relay SMTP message to external domains, this is known as an ‘open relay’ and this is the number one reason to be put on every blacklist available on the Internet. You can do this and restrict access based on IP addresses, but I strongly recommend against changing the default connectors. Leave the inbound SMTP traffic end up on the Default Frontend Receive Connector and create a dedicated connector for SMTP relay traffic.

There are two ways to create such a relay connector:

  • Create a dedicated receive connector (on Frontend Transport, not on Transport Service), restrict by IP address and add the Ms-Exch-SMTP-Accept-Any-Recipient permission on the NT AUTHORITY\ANONYMOUS LOGON security principal. This is what I have shown in the blog mentioned earlier, and this is only possible using Exchange PowerShell. Sending hosts are considered anonymous, and anti-spam and message size limits are applied.
  • Create a dedicated receive connector (again on the Frontend Transport), restrict by IP address, and add the Exchange Servers and Externally Secured authentication mechanism to the connector. In this scenario, sending hosts are considered as authenticated senders, and email messages bypass anti-spam and message size limits. And it’s easy to configure using the Exchange Admin Console.

Since the first option is already documented, I will continue with the second option. Personally, I like to do this with PowerShell and the command to create such a connector and configure it are like these:

[PS] C:\>New-ReceiveConnector -Name "SMTP Relay EXCH01" 
-Server EXCH01 -TransportRole FrontendTransport -Custom 
-Bindings -RemoteIpRanges

Identity                 Bindings     Enabled
--------                 --------     -------
EXCH01\SMTP Relay EXCH01 {} True

[PS] C:\>Set-ReceiveConnector "EXCH01\SMTP Relay EXCH01" 
-AuthMechanism ExternalAuthoritative 
-PermissionGroups ExchangeServers

[PS] C:\>

When you check the connector using the Exchange Admin Center, you can see that the authentication mechanism is set correctly as shown in the following screenshot:

It is also possible to create a new connector using the Exchange Admin Center. In the EAC, navigate to mail flow and select the receive connectors tab and click the + icon. Follow the wizard, give the new connector a proper name, select Frontend Transport and Custom, and restrict by IP address as shown in the following screenshots:

When created, open the new receive connector, select security and configure the authentication mechanmism to Externally secured and Exchange servers as shown in a previous screenshot.

It is now possible to relay SMTP messages from the server with IP address Using Telnet on port 25, you will see something like this:

When trying to relay from another server (which is not listed in the Remote Network Settings) it will fail with the 550 5.7.54 SMTP; Unable to relay recipient in non-accepted domain error as shown in the following screenshot:


So in short, do not configure the default receive connector in such a way that it will relay messages outside of the Exchange server. When you need to use SMTP relay, create a dedicated connector.

The first and most secure option is to create a new receive connector, restrict by IP address and configure the Ms-Exch-SMTP-Accept-Any-Recipient permission. Anti-spam and message size limits are applied, but it can only be configured using PowerShell (and thus more complex).

The second on is to create a new receive connector, restrict by IP address and configure the authentication mechanisms. Easier to configure (using EAC) but less secure: anti-spam and message limits are not applied.

It is up to you which one to use.

Retrieve mailbox statistics in PowerShell for a large number of users

I’m currently working on a project where we are going to move 24,000 mailboxes from Exchange 2016 to Exchange Online. For planning purposes we would like to know the basic statistics, like the LastLogonTime and the number of items (both regular and deleted).

To retrieve this for my mailbox, you can use something like this:

[PS] C:\ >Get-Mailbox -Identity wesseliusj | Get-MailboxStatistics | Select DisplayName,LastLogonTime,ItemCount,TotalItemSize,DeletedItemsCount,TotalDeletedItemSize

DisplayName          : Wesselius, J
LastLogonTime        : 28-4-2022 11:24:46
ItemCount            : 1065
TotalItemSize        : 63.95 MB (67,060,296 bytes)
DeletedItemsCount    :
TotalDeletedItemSize : 5.421 MB (5,684,477 bytes)

The TotalItemSize and TotalDeletedItemSize are returned as text and not numeric. Since I want to export everything into a CSV file and import into Excel for further processing, it must be converted to a numeric value. This is called a calculated property and this is possible using the following option:


ToBytes() can also be ToKB(), ToMB() or ToGB() depending on your situation.

The previous command and output will now be something like this:

[PS] C:\>Get-Mailbox -Identity wesseliusj | Get-MailboxStatistics | Select DisplayName,LastLogonTime,ItemCount,@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.ToBytes()}},DeletedItemsCount,@{Name="TotalDeletedItemSizeMB";Expression={$_.TotalDeletedItemSize.Value.ToBytes()}}

DisplayName            : Wesselius, J
LastLogonTime          : 28-4-2022 11:24:46
ItemCount              : 1065
TotalItemSizeMB        : 67060293
DeletedItemsCount      :
TotalDeletedItemSizeMB : 5684477

Now use the Export-Csv command and we are good to go (you would hope 😊):

[PS] C:\>get-mailbox -ResultSize unlimited | Get-MailboxStatistics | Select DisplayName,LastLogonTime,ItemCount,@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.ToBytes()}},DeletedItemsCount,@{Name="TotalDeletedItemSizeMB";Expression={$_.TotalDeletedItemSize.Value.ToBytes()}} | export-csv -Path statistics.csv -nti

Sending data to a remote command failed with the following error message: [ClientAccessServer=EXCH2016,BackEndServer=exch2016.labs.local,RequestId=c0430cd6-6f4d-48a5-8434-d59ebcd91887,TimeStamp=28-4-2022 10:03:54] [FailureCategory=W
SMan-Others] The total data received from the remote client exceeded the allowed maximum. The allowed maximum is 524288000. For more information, see the about_Remote_Troubleshooting Help topic.
    + CategoryInfo          : OperationStopped: (exch2016.labs.local:String) [], PSRemotingTransportException
    + FullyQualifiedErrorId : JobFailure
    + PSComputerName        : exch2016.labs.local

[PS] C:\>

Unfortunately, the Get-Mailbox command retrieves all 24,000 mailboxes in one run and then tries to use this as input for the Get-MailboxStatistics command. While this works for just a few mailboxes, it runs out of memory for a large set of mailboxes.

The solutions here (or one of the solutions) is to import all mailboxes into a variable, and loop through all mailboxes in this variable combined with the Get-MailboxStatistics command:

[PS] C:\> $Mailboxes = Get-Mailbox -Resultsize Unlimited
[PS] C:\> ForEach ($Mailbox in $Mailboxes) {Get-MailboxStatistics $Mailbox | Select  DisplayName,LastLogonTime,ItemCount,@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.ToBytes()}},DeletedItemsCount,@{Name="TotalDeletedItemSizeMB";Expression={$_.TotalDeletedItemSize.Value.ToBytes()}} | export-csv -Path statistics.csv -nti}

One last question I got is to add a UPN or alias of the user to the CSV file. UPN and alias are not in the object that’s returned by Get-MailboxStatistics, but are returned by the Get-Mailbox command. To get these properties in the output, again a calculated property must be used, similar to the size properties that were used earlier.

To retrieve the UPN, use something similar to the following:

@{Name = "UPN"; Expression={$Mailbox.UserPrincipalName}}

This will take the UserPrincipalName property of the first command (Get-Mailbox) and parse it into the output. The entire command will be:

[PS] C:\>ForEach ($Mailbox in $Mailboxes) {Get-MailboxStatistics $Mailbox | Select  DisplayName, @{Name = "UPN"; Expression={$Mailbox.UserPrincipalName}},LastLogonTime,ItemCount,@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.To

DisplayName            : Wesselius, J
UPN                    :
LastLogonTime          : 29-4-2022 14:22:03
ItemCount              : 1098
TotalItemSizeMB        : 68714749
DeletedItemsCount      :
TotalDeletedItemSizeMB : 5822787

[PS] C:\>

This will create a proper CSV file with all the information I need, ready to import into Excel 😊

More information regarding working with large number of users (in Office 365) please check the following article: Running PowerShell cmdlets for large numbers of users in Office 365 – Microsoft Tech Community

H1 2022 Cumulative Update Exchange 2019 (CU12)

Last week, on April 20, Microsoft released Cumulative Update 12 for Exchange 2019 and Cumulative Update 23 for Exchange 2016.

It took Microsoft six month for the Cumulative Update, that’s because Microsoft is changing from a quarterly release cycle to a bi-annual release cycle. As a result, this will the Cumulative Update of the first half of 2022, so H1 2022 Cumulative Update.

This is only true for Exchange 2019 as there will be no new Cumulative Updates for Exchange 2016 anymore. Exchange 2016 has entered extended support, so Microsoft will deliver Security Updates when needed, but not more CUs. Mainstream support for Exchange 2019 will end on January 9, 2024 and extended support for Exchange 2019 will end on October 14, 2025. This is the same date as for Exchange 2016. What will happen then is still unknown….

Exchange 2019 CU12 now has support for Windows 2022 (finally). Support for Windows 2022 is only true for Exchange 2019 CU12, Exchange 2016 is only supported on Windows 2016.

When it comes to Active Directory, only Exchange 2019 CU12 supports Windows 2022 Domain Controllers. Exchange 2016 and Exchange 2013 do not support Windows 2022 Domain Controllers (despite earlier communication from Microsoft). For more information regarding supportability check the Exchange Supportability Matrix.

One of the new features of Windows 2022 is support for TLS 1.3 and several of my clients have a requirement for this. Unfortunately, Exchange 2019 still does not support TLS 1.3 and support for TLS 1.3 is expected by the end of this year.

With the new Cumulative Update comes a change in (free) licensing. Previously, there was a free license for the ‘hybrid server’ but this was Exchange 2016. Now with Exchange 2016 in extended support and no more CUs for Exchange 2016, the free hybrid license is available for Exchange 2019!

A lot of noise regarding the “remove the last Exchange server” in your organization. When you have all mailboxes in Exchange Online and you have Azure AD Connect running, you need to have one Exchange server, just for management purposes. This is no longer required with Exchange 2019 CU12. You can install the management tools for CU12 and get rid of the Exchange server. Be aware that you must NOT UNINSTALL the Exchange server, but clean up the hybrid configuration using PowerShell, shutdown the Exchange server and run the CleanupActiveDirectoryEMT.ps1 script (released with Exchange 2019 CU12).

Are there reasons to not do this? Yes, think about SMTP relay from on-premises to Exchange Online, or RBAC on-premises (not available with only the Management Tools on-premises), or maybe an offloading possibility when needed. Oh, and if you are not good with PowerShell, be aware that this is a PowerShell only solution. If you are addicted to the Exchange Admin Center, leave the Exchange server running 😉

But nevertheless, it’s good that Microsoft finally heard this feedback and offers a solution for the last Exchange server when all mailboxes are in Exchange Online.

A couple of remarks:

  • Be aware that Microsoft only supports the two latest CUs, i.e. Exchange 2019 CU11/CU12 and Exchange 2016 CU22/CU23.
  • There are no schema changes in these Cumulative Updates, but there are changes in the configuration, so you need to run setup with the /PrepareAD switch.
  • When running a Database Availability Group, do not forget to put the Exchange servers in maintenance mode.
  • As always, test the new CUs in your test environment before installing in your production environment.

More information and downloads:

Exchange versionKB ArticleDownload
Exchange 2019 CU12KB5011156
Exchange 2016 CU23KB5011155
Exchange 2016 CU23 language packs