If you are looking for a way to automate and simplify your Microsoft 365 administration tasks, PowerShell is a great option. However, PowerShell scripting is not without its challenges. Not proactively maintaining code can quickly become an issue because of the changes made to dependencies such as modules, as well as the cmdlets you use.
In an article I wrote for Practical 365, related to the presentation of the same name held at the The Experts Conference 2023 in Atlanta this year, I discuss some of the challenges administrators might encounter with PowerShell scripts. Also, I provide some guidance and point out a few tools that can assist with rewriting or refactoring code, i.e., updating code while keeping its external functionality.
The MTA-STS policy (MTA Strict Transport Security) is to prevent Man-In-The-Middle attacks by publishing authorized mail servers and prevent TLS downgrade attacks (Opportunistic TLS), when both parties support MTA-STS. MTA-STS is easier to implement over DANE with DNSSEC, which is expected to get inbound support in Exchange Online next year. Since I am using WordPress to host this blog, I was looking for ways to host the policy file for MTA-STS at the required location, as hosted WordPress does not offer this possibility.
There is documentation describing how to accomplish this using, for example, Azure Static Web Sites, but this requires an Azure subscription. There are also 3rd parties offering hosted MTA-STS, which are usually not free.
Then I stumbled upon the possibility of using a custom domain with GitHub pages, which can be used for this. So, here is a quick write-up on how to host your MTA-STS policy file on GitHub using GitHub Pages. This process could also be used when needed for hosting other files on GitHub.
Hosting MTA-STS Policy using GitHub Pages
Start by creating a new repository in GitHub. You can name it anything you want, but for the sake of the example, I called it mta-sts. Make sure it is public.
Next, we must create an empty file called .nojekyll in the repository. This file will instruct GitHub not to build pages, and just serve your files. So, Add file > Create new file, enter .nojekyll as Name your file and Commit changes.
Now, create the policy file that needs to be named mta-sts.txt in the .well-known folder file, select Add file > Create new file and enter .well-known/mta-sts.txt as the name of your file. This will also create the required folder. In the contents field, paste your policy. For example, the MTA-STS policy file when using only Exchange Online for receiving e-mail could look something like this:
When done, commit your changes to store the policy file on GitHub. For more information on the MTA-STS policy file definition, click here.
Next, we need to enable GitHub Pages for this repository. Go to Settings, and select the Pages tab. Under Branch, select the branch you want to publish, eg. main, and press Save. Note that GitHub Pages are served using a valid 3rd party certificate, which satisfies one of the requirements for MTA-STS.
New options should now appear on the GitHub Pages settings, one of which is Custom domain. If you decided to use a custom domain in the previous step, enter it here, eg. mta-sts.contoso.com, and click Save.
GitHub will start to check DNS for the presence of this domain. Time to head over to your ISP portal, and create the required records in DNS.
First, if you used a custom domain for hosting the MTA-STS policy, create a CNAME mta-sts record for your domain pointing to <user>.github.io or <org>.github.io, e.g.
mta-sts.contoso.com CNAME 3600 user.github.io
Next, create the DNS TXT _mta-sts record to indicate MTA-STS support, e.g.
Note that you need to update ‘id,’ usually with timestamp yyyymmddhhmm, whenever you make changes to the policy. This indicates to MTA-STS supporting hosts there has been a change on your end.
You are now set. After DNS some time for DNS to propagate changes, you can start verifying your configuration by browsing https://mta-sts.contoso.com/.well-known/mta-sts.txt, which should return your policy file without any certificate prompts. You can verify DNS and policy access using websites like MxToolbox or PowerDMARC. The example below was generated using EasyDMARC:
TLS Reporting
In addition to setting up MTA-STS, you can configure TLS Reporting (TLS-RPT). This will instruct supporting servers to report on TLS usage and mention certificate issues, for example. Note that these are reports on inbound messages, whereas Exchange Online offers information on outbound TLS usage. To set up TLS-RPT, configure a DNS TXT record _smtp._tls and specify a recipient for these reports, e.g.
The rua field contains the e-mail address where reports should be sent. You can process these reports in JSON format yourself or have one of the 3rd parties offering this service do this for you. The example below is generated by Dmarcian.
Updated: 1.2 adds default ExchangeOnlineManagement cmdlets scanning and authentication options.
Since the original announcement on deprecation of Basic Authentication, organizations had time to analyze their environment which may include Exchange-related procedures and tools. These usually also contain scripts or commands, which depend on the Exchange Online Management module. A previous blog on its history and how version 2 of this module lends itself for unattended operation with certificate-based modern authentication support can be found here.
The initial release of the Exchange Online Management v2 – or EXOv2 – module offered a an additional small set of cmdlets which utilized REST-based services. Apart from the functional discrepancies, such as having to specify a property set to indicate which properties to return, the big advantage of these added commands was that they did not depend on the Windows Remote Management (WinRM) client using Basic Authentication for token exchange. Disabling Basic Authentication on WinRM client lead to messages such as:
Connecting to remote server outlook.office365.com failed with the following error message : The WinRM client cannot process the request. Basic authentication is currently disabled in the client configuration.
This dependency makes it challenging for organizations to turn off Basic Authentication altogether, or lead to problems when they did. Fast forward to the present, where the Exchange Online Management module in its current release is offering nearly all Exchange cmdlets in REST-based form, with full functional parity.
While I expect Microsoft to reach full command parity before they flick the Basic Authentication switch to off, there are also other use cases for which analyzing scripts might be helpful:
Ths initial purpose was identifying commands which require RPS (Remote PowerShell), and thus thus require WinRM Basic Authentication enabled. Because the Exchange Team did an amazing job in catching up in the recent months, only few Exchange Online cmdlets are still lacking REST support in my tenant at this moment, e.g. New-ApplicationAccessPolicy. But then again, your mileage may vary, as the recent Preview 7 module removed few UnifiedGroup related cmdlets which had issues.
New Exchange Online commands may not receive immediate REST support.
Organizations might want to cross-reference commands with scripts.
Identifying Exchange Online commands and parameters in scripts helps in determining the minimum set of permissions required to run the script.
To analyze and report on Exchange Online scripts, I created a simple script Analyze-ExoScript.ps1. This script, which is available on GitHub here, does the following:
Connect to Exchange Online using RPS and inventory the commands available. Note that this requires the UseRPSSession switch when connecting, which is only available per 2.0.6-Preview3 of the module. If your organization only runs GA versions of the module, this script cannot be used.
Connect to Exchange Online using REST and inventory the commands available. It will re-use the account used for authenticating the RPS session, which should prevent receiving another authentication dialog or MFA challenge.
Cache cmdlet information in an external file to prevent having to connect to Exchange Online for every run. The file is named EXO-CmdletInfo.xml and will be stored in the same folder as the script.
Process the script and report on the Exchange-related commands used.
Usage Calling Analyze-ExoScript is straightforward:
File is the name of one or more files which you want to analyze. Note that the script accepted pipeline output, so you can also feed it filenames using Get-ChildItem for example.
The ShowAll switch tells the script to output all found commands, not only the Exchange ones.
The switch Refresh tells the script to ignore saved command information, trigger reconnecting to Exchange Online in order to refresh the command sets.
Credential specifies the (Basic Authentication) credential to pass to Connect-ExchangeOnline.
Organization and AppId can be used to specify the tenant ID (x.onmicrosoft.com) and registered application ID to use with Connect-ExchangeOnline using Modern Authentication. This also requires one of the following:
CertificateThumbprint of the certificate to use for authentication.
CertificateFile of the file containing the certificate to use, together with CertificatePassword to specify its password.
When asked to authenticate, make sure your role has the necessary Exchange-related permissions as that will determine the Exchange Online cmdlets available to you, and consequently also the commands which Analyze-ExoScript will recognize in scripts to process.
For example, to process a script Fix-MailboxFolders.ps1, use:
The output consists of objects, which allow for further filtering:
The returned properties are:
Command is the Exchange Online command identified
Type will tell you if the command supports REST or requires RPS.
Parameters are the parameters used together with the command. This includes common parameters, which might be less usable for role assignment purposes.
Alt contains alternative REST-based cmdlet you could consider using for performance reasons, e.g. Get-EXOMailbox instead of Get-Mailbox.
File and Line are the file containing the command and on which line it is located.
AST To analyze code, I leveraged PowerShell feature called Abstract Syntax Tree, which was an interesting exploration in itself. PowerShell AST can be used to decompose PowerShell code into tokens. This is way better than simply looking for strings, and does away with having to interpret code yourself to see if something is a command, comment or just some string. AST allows for analysis of these tokens, in this case filtering on commands which are related to Exchange Online. If you want to get started on AST, check out this article, or plunge in the PowerShell SDK straightaway.
Final Words When every Exchange Online command discovered is found to be offering REST support, you can turn off Basic Authentication on the client, for example through GPO or by reconfiguring WinRM:
winrm set winrm/config/client/auth @{Basic="false"}
Only thing you might need to refactor is if and how the script connects to Exchange Online, as Basic Authentication allowed for connecting to Exchange Online using (stored) credentials for example. Examples on how to use more secure Modern Authentication-based methods to connect can be found in an earlier article here.
In the announcement of the most recent set of Cumulative Updates for Exchange Server 2019 and 2016, Microsoft introduced some changes – features if you will – as well, which were received with enthusiasm. An overview of these Cumulative Updates and the features introduced was given in an earlier article. In this article however, I would like to zoom in on one of those features, which also happens to be a popular topic among customers running Exchange Hybrid deployments, “The Last Exchange Server”.
Up to Exchange 2019 CU12 (2022 H1), customers that migrated to Exchange Online were still required to leave Exchange-related components running on-premises. Even today, with all the information published around this topic, I am surprised this still surprised customers. This Exchange server running on-premises is to be used for managing recipients which have their source of authority in Active Directory, leveraging Active Directory Connect to propagate objects to Azure Active Directory and thus Exchange Online. Also, when there is a need to relay messages from applications or multi-functional devices, customers often need to have an Exchange server on-premises to accept these messages, as Exchange is the only supported mail relay product for hybrid deployments.
Back in September 2019, Microsoft announced it would start to turn off Basic Authentication for non-SMTP protocols in Exchange Online on tenants where the authentication protocol was detected as inactive. This is part of an overall movement to deprecate the less secure Basic Authentication, which is unfit to face the security challenges of the modern world, being subject to things like password spray attacks. It’s modern successor, modern authentication or OAuth2, uses a token and claim based mechanism contrary to sending accounts and passwords, and is the preferred authentication method. When combined with Azure AD for authentication, Modern Authentication also supports features such as Multi-Factor Authentication or Conditional Access.
The original date for disabling of Basic Authentication was October 13th, 2020. Then the world had other matters to deal with, and Microsoft extended the timelines. After initially postponing turning Basic Authentication off to second half of 2021, the ‘start date’ for permanently turning the lights off for Basic Authentication was set to October 1st, 2022, as per this article on Docs and MC286990 in the Message Center. Mind the ‘start’ in start date, as flicking the switch for millions of tenants takes time before it becomes effective on your tenant. Organizations do need to anticipate on this change for the first of October.
On September 1st, Microsoft published an update to these timelines as there were still some cases were organizations could not make the deadline of October 1st. To meet these customers “one last time”, organizations can now use the self-service diagnostics to extend disabling of Basic Authentication to January 2023. This needs to be done per protocol, also if organizations requested opt-out or re-enabled Basic Authentication earlier. Details as well as instructions and revised timelines on Basic Authentication switching off are laid out in a new article.
Until then, organizations can (re-)enable Basic Authentication for the protocols they need, using the self-help system in the Microsoft 365 admin center. After entering “Diag: Enable Basic Auth in EXO” in the problem search query, the request will be checked, and Basic Authentication will get enabled. But with the end of support for Basic Authentication, so will this temporary workaround. On a side note, per end of 2020, newly created tenants already have basic authentication disabled by means of security defaults – if those organizations require Basic Authentication for some reason, they will also need to reconfigure security defaults which by default is an all or nothing option for all protocols.
So, with the doomsday counter ticking away for Basic Authentication, what are the consequences for Exchange related workloads organizations might wonder. In this article, I will address some of these concerns.
Update: Microsoft meanwhile has disclosed much awaited details on changes in the native Mail app on iOS. This update is effective per iOS 15.6, and adds support for migrating configured accounts from using Basic Authentication to using Modern Authentication (OAuth). For this work work seamlessly and without user interruption, some configuration is needed on the back-end. Details can be found in a separate article here on this specific topic.