Bulk replacing proxy addresses based on a pattern

This one comes from the TechNet forums, where a user posted a query about being able to update the email aliases (proxy addresses) of a mailbox by removing a predefined string. As usual with such queries, the answer is to use PowerShell, so let’s dig in.

Assume you have a mailbox (appropriately named “left” in my case), which email addresses look something like this:


You want to remove any and all aliases that start with the prefix “left”, regardless of whether we are talking about the Primary SMTP address or secondary aliases. On the other hand, any proxy addresses that contain the “left” as part of the name might still be considered valid, so it’s desirable to only strip those that have it at the beginning of the address string.

Now, there are different approaches to this task, but essentially it all boils down to basic string manipulations. The method I chose was to do a quick filter using the Where-Object clause and the -notlike statement:

$aliases = $mailbox.EmailAddresses | ? {$_.AddressString -notlike 'left*'}

Applying this to the above example will strip the smtp:left@domain.com and smtp:leftSAM.something@domain.com entries, with those four remaining:


Now that the “left” aliases are stripped, we can just feed the remaining ones to the Set-Mailbox cmdlets and be done with it. Easy enough, right? Well, if you want a more robust solution, you have to cover some corner cases. What if the above filter removed the Primary SMTP address? Or what if it removed ALL aliases? You will of course need at least one valid proxy address in order to reconfigure the mailbox, so what kind of solution can we code to account for this?

For the first corner case, we can select one of the remaining proxy addresses and promote it to Primary SMTP Address. My regex skills are still mediocre so there is probably a better way to do this, but the following code seems to work just fine:

$emailaddresses = ($aliases.ProxyAddressString -join "," -replace "smtp:(?!.*smtp:)","SMTP:") -split ","

In a nutshell, the above converts the array of aliases to string of comma-separated proxy addresses, applies a regex to find the last instance of (lowercase) “smtp:” and replaces it with uppercase “SMTP:”, then converts back to array.

The other corner case to handle is when all aliases were removed, so we craft a new one using the below code sample:

$emailaddresses = $("SMTP:" + $mailbox.Alias + "@" + (Get-AcceptedDomain | ? {$_.Default -eq $true}).Name)

The new Primary SMTP address will consist of the Alias/MailNickname attribute of the user, the at sign and the default accepted domain for the company.

Combining all of the above into a single piece of code:

$mailbox = Get-Mailbox 'left' | Select-Object Alias, Emailaddresses

$aliases = $mailbox | select -ExpandProperty EmailAddresses | ? {$_.AddressString -notlike 'left*'}
if ($aliases | ? {$_ -cmatch "SMTP:"}) {
    $emailaddresses = $aliases.ProxyAddressString
elseif (!$aliases) { $emailaddresses = $("SMTP:" + $mailbox.Alias + "@" + (Get-AcceptedDomain | ? {$_.Default -eq $true}).Name)  }
else {
    $emailaddresses = ($aliases.ProxyAddressString -join "," -replace "smtp:(?!.*smtp:)","SMTP:") -split ","

Set-Mailbox 'left' -EmailAddresses $emailaddresses

Now, you might as well want to execute this against in bulk against a list of mailboxes. It is indeed possible, with just some minor modifications:

$mailboxes = Get-Mailbox | Select-Object Alias,ExchangeGuid,Emailaddresses
foreach ($mailbox in $mailboxes) {

    $aliases = $mailbox | select -ExpandProperty EmailAddresses | ? {$_.AddressString -notlike 'left*'}
    if ($aliases.AddressString.Count -eq $mailbox.EmailAddresses.Count) {continue}
    if ($aliases | ? {$_ -cmatch "SMTP:"}) { 
        $emailaddresses = $aliases.ProxyAddressString
    elseif (!$aliases) { $emailaddresses = $("SMTP:" + $mailbox.Alias + "@" + (Get-AcceptedDomain | ? {$_.Default -eq $true}).Name)  }
    else {
        $emailaddresses = ($aliases.ProxyAddressString -join "," -replace "smtp:(?!.*smtp:)","SMTP:") -split ","
    Set-Mailbox $mailbox.ExchangeGuid.ToString() -EmailAddresses $emailaddresses

The code above expects that the full Deserialized.Microsoft.Exchange.Data.SmtpProxyAddress object is exposed, as in the cmdlets are executed against the EMS if using on-premises Exchange or Implicit session if using Exchange Online. If you are using PowerShell remoting instead, some minor modifications will be needed:

$mailboxes = Get-Mailbox | Select-Object Alias,ExchangeGuid,Emailaddresses
foreach ($mailbox in $mailboxes) {

    $aliases = $mailbox | select -ExpandProperty EmailAddresses | ? {$_.Split(":")[1] -notlike 'left*'}
    if ($aliases.Count -eq $mailbox.EmailAddresses.Count) {continue}

    if ($aliases | ? {$_ -cmatch "SMTP:"}) {
        $emailaddresses = $aliases
    elseif (!$aliases) { $emailaddresses = $("SMTP:" + $mailbox.Alias + "@" + (Get-AcceptedDomain | ? {$_.Default -eq $true}).Name)  }
    else {
        $emailaddresses = ($aliases -join "," -replace "smtp:(?!.*smtp:)","SMTP:") -split ","
    Set-Mailbox $mailbox.ExchangeGuid.ToString() -EmailAddresses $emailaddresses

Additional details are available in the TechNet forums thread: Update Email addresses in Exchange for a user

Posted in Exchange Online, PowerShell | Leave a comment

New version of the Azure AD PowerShell module released,

Earlier today, a new version of the Azure AD PowerShell module has been released, namely For those of you following the development of the Preview module, this version brings nothing new, it simply adds all the Azure AD Application Proxy related cmdlets. Here’s the full list:


In terms of changes to any existing cmdlets and parameters, nothing is immediately visible. You can get the module here: https://www.powershellgallery.com/packages/AzureAD

The Azure AD Preview module also got bumped by a version number and it currently sits at Yes, still a lower version than the non-preview one.

For the Azure AD Preview module, the following changes have been made in cmdlets:


Those cmdlets deal with managing Identity Providers for applications secured by Azure AD B2C, for example Google or LinkedIn. The current list of Identity providers supported is Microsoft, Google, Facebook, Amazon, or LinkedIn.

No changes to existing cmdlets were spotted, all their parameters remain the same. Get the Azure AD Preview module here: https://www.powershellgallery.com/packages/AzureADPreview

Posted in Azure AD, Office 365, PowerShell | Leave a comment

Teams, mail users and compliance – could it be handled better?

Back when Teams initially launched, most of us were quite happy with its compliance story – unlike many of the new apps that appeared over the last few years, Teams actually had a good coverage from the get go. This was largely thanks to the investments Microsoft has made in compliance features for the underlying workloads on which Teams is built. Even back then however, a few gaps were apparent, such as the inability to capture Bot interactions or messages ingested by connectors.

Additional issues arose around the handling of Hybrid users with mailboxes hosted on-premises, as a copy of the IM conversations cannot be stored for those. Even in cases where all the data was properly stored, retrieving it provides issues on its own, as each individual contribution is stored as separate message, greatly complicating the task for any legal officer. Moreover, the existence of the “chat service” that stores copies of the messages somewhere in Azure remains an unknown factor and a wildcard, with little to no public information provided on its workings and compliance status.

Fast forward few months and another round of compliance related issues became apparent with the introduction of support for Guest users. As Guest users do not have a mailbox homed in the tenant, they are represented by mail user objects and their contributions to Teams conversations are not captured in some cases. Even when contributions are actually captured, the method used can cause some trouble.

The thing is, conversation items are stored inside the Team (or user) mailbox by using the Primary SMTP address of each participant as identifier. For users with mailboxes in Exchange Online this approach works flawlessly, as the Primary SMTP address is a unique identifier. However, if the user does not have a mailbox in Exchange Online, or has it in another organization’s tenant, things are different. Such user is represented by a “mail user” object, and being a mail user, it can have *any* email address associated with it. Any!

Exchange Online does not enforce any restrictions as to what the email address(es) associated with a mail user look like, as by definition those objects can represent external users. Thus, it’s perfectly acceptable for a mail user to have an email address matching a domain that is not verified in your Office 365 tenant. For example, every Office 365 tenant out there can create a mail user with satya@microsoft.com for an email! However, that user cannot actually send messages via Exchange Online and in general has to use a UserPrincipalName associated with one of the domains you have verified in Office 365 if he is to access any Office 365 service, Teams included.

And therein lies the issue. While a mail user or a guest user has to login with the corresponding UPN in order to participate in Teams activities, any conversations he is part of are being stored using his Primary SMTP Address as the identifier. It’s much easier to understand the problem when an example is given, so let’s assume that some naughty person in my tenant decided to abuse this and created a mail user with satya@microsoft.com as the email address. The below example illustrates how easy is to create such mail user:

Now of course that’s just a simple example, so I didn’t bother to configure a proper display name, title and so on. Thus, it will be easy enough to spot that this user is not the actual Microsoft CEO. Technically, all of this is doable though, including adding the “(Guest)” suffix. So bear with me for a minute, and focus on the email address only.

Once this user is created and added to any Team, he can participate in the conversations in any of the Channels. Even without being member of a Team, he can still message users directly. For example, he can message an unsuspecting user and make them a job offer:

As mentioned above, in this simple example it’s easy enough to notice the discrepancy in user’s information, even without looking into the contact card. However, the topic at hand here is compliance, so let’s see what happens once an eDiscovery officer stumbles into the above example. Let’s assume a query has been run to return all Teams chats for my user (“Vasil” in the above example). This is what the legal officer will actually see:

Note the From address in the above dialog – an unsuspecting person will not be able to tell whether this is an actual Guest user or a Mail user with “spoofed” address. All he can see here is that the user is represented as satya@microsoft.com. A better solution would be to use the UserPrincipalName to populate the From field instead, as it is unique across all Office 365 tenants and can only be used in the tenant that “owns” the domain. Thus a mail user would have been represented via the satya@michevdev3.onmicrosoft.com UPN in this particular tenant, and if Satya visited the tenant as a Guest user, his UPN would be satya_microsoft.com#EXT#@michevdev3.onmicrosoft.com. Easily distinguishable.

Here’s another view of the same content search, presented this time as the CSV report file:

Again, the From and/or To fields use the Primary SMTP Address of the user, which can lead to confusion. Of course, looking at the actual IM item stored in the mailbox will produce the same results. Unless you know where to look, but more on this later.

Now, it’s important to understand that the method described above can only be exploited by users with permissions to manage mail user objects in your tenant. While you can certainly create a new tenant and provision any number of mail users with random addresses within them, to access the “target” tenant you still need to be invited (the invite doesn’t have to be received/accepted actually, but that’s a topic for another post). And even if you manage to get into the “target” tenant, the Guest (mail) user will automatically be created with an email address matching the UPN, thus mitigating the issue.

However, the user can still be edited after the process. For example, the below illustrates how the external mail user (the one with primary SMTP address satya@microsoft.com) will be provisioned when added to another tenant. As expected, the service creates the Guest user account with SMTP address matching the UPN (top of the screenshot), which leaves no room for impersonation. The corresponding mail user object can later be edited to have it’s primary SMTP address updated to any value, which in turn not only updates the object properties but the actual From/To fields in the compliance trail:

Back to the eDiscovery results, it seems that the issue stems from the fact that Exchange resolves the recipient object (based on the LegacyExchangeDN attribute)  and replaces its properties dynamically. In the above example, this will result in updating the primary SMTP address to reflect the changes made by the nefarious admin. The issue is thus “internal” to Exchange, but as mail users have not been able to generate items until the advent of Teams, everything was working in an acceptable manner. Nowadays, in order to get the correct information about the sender you will have to take a deeper look into the item properties, instead of relying on the information surfaced in the eDiscovery UI.

Technically, the last statement isn’t completely true. The same issue can be observed with Skype for Business IMs, when the underlying user does not have a mailbox (or Exchange Online license). Just like with the Teams example above, changing the SMTP address of the user will result in Exchange automatically resolving to the new value when displaying any messages in the eDiscovery UI. However, even for a mail user without Exchange license, the corresponding IM items related to Skype for Business conversations contain the information about the SIP address of the user, which similarly to the Primary SMTP address cannot be spoofed.

Overall, the issue described above is not so much a spoofing/phishing vector, as it can only be (ab)used by privileged users and an attack cannot be carried out by externals. However, the way the compliance record is kept for mail users can lead to confusion and ideally a change on how Microsoft stores those items should be examined. Otherwise, you will have to download the full IM item or fetch it from the mailbox via MFCMAPI, then examine some of the more obscure properties such as SkypeMessagePropertyBag (or ptagRecipientSipUri for SfB messages) in order to get a unique identifier for the user. Simply looking at the From/To fields in the UI or the related message properties might play a joke on you, so remember that the next time you are running an eDiscovery for any conversation data!

Apart from the issue detailed in this article, we will surely benefit from an improved method of storing threads and conversations, instead of the current “each reply is a separate item” situation. Whether Microsoft will address these shortcomings remains to be seen.

Posted in Exchange Online, Office 365 | Leave a comment

Cross-premises support for Send on behalf of and Folder level permissions

Without much ado, Microsoft started rolling out updates to expand the scope of delegate permissions supported in Hybrid configurations. The rollout is expected to complete by the end of April and will bring support for cross-premises Send on behalf or and folder-level delegation.

While no EHLO blog post has been published yet, the support articles (linked in the text below) have been updated to reflect the changes. In addition, the following item appeared on the Office 365 Roadmap:

Once the changes are completed, the following set of permissions will be supported:

  • Full Access (automapping is NOT yet supported)
  • Send on behalf of
  • Folder-level permissions

Note that all of the above permissions are only supported via the desktop Outlook client. Outlook for mobiles or OWA are not supported. Send As permissions are also not supported yet, neither is automapping. Those might be coming in future updates.

To take advantage of the new functionalities, some additional changes might be required, depending on your Exchange server version. In a nutshell, those include updating to the latest CU applicable and making sure that support for Access Control Lists (ACLs) is enabled for mail objects. Depending on the server version, you might need to manually enable ACLs for some objects. You will also need AAD Connect version 1.1.553.0 or later to make sure the permissions are correctly synced between on-premises and Exchange Online. Additional information can be found in this support article.

It’s important to note that ACLs are not enabled on Remote mailbox objects and you will have to perform some additional actions for those. To work around this, Microsoft recommends that you create mailboxes on-premises and move them to Office 365 instead of creating Remote mailboxes. More information is available in this article. Some other considerations and additional troubleshooting information about all cross-premises delegation scenarios can be found in the following KB article.

I expect these improvements will get some more coverage in the coming weeks, as the rollout completes. Overall, this is a much welcomed, albeit a little overdue improvement.

Posted in Exchange Online, Office 365 | Leave a comment

Managing Outlook delegates via PowerShell

In another example of a small, but impactful change, Microsoft has started rolling out improvements to the PowerShell cmdlets responsible for folder permissions that will allow us to manage some of the delegate-related settings. Two parameters have been added to the *-MailboxFolderPermission cmdlets to facilitate those changes, namely the SendNotificationToUser and SharingPermissionFlags. We will take a look at them in a moment, but first, let’s try to explain what a delegate is and why the changes are important.

What is a delegate

In the Exchange world, a delegate is a person you have given some level of access to over your own mailbox. The access can range from being only able to read your messages, to being able to manage all your email as well as compose and send messages on your behalf. While you can set folder level permissions by right-clicking any of your folders in Outlook and selecting the corresponding menu item, the Delegates dialog under File -> Account settings -> Delegate access exposes some additional controls. It’s easy to use this method to grant permissions on commonly used folders, but more importantly it allows you to control access to Private items and to configure the handling of meeting responses. The corresponding settings are shown on the screenshot below:

















Now, as the folder permissions are configurable via other means as well, what is usually referred to as Delegate is a user for which the “delegate receives a copy of meeting-related messages sent to me” setting is configured. This option only becomes available in the UI when the Calendar folder permissions are set to Editor. Once a Delegate is configured for your mailbox, in the sense of configuring the checkbox mentioned above, the “Deliver meeting requests addressed to me and responses to meeting requests where I am the organizer to” option becomes available, and you can decide whether you, the delegate, or both should receive those. In addition, a Delegate also receives Send on behalf of permissions to your mailbox. More information can be found in the official documentation.

Up until now, some of those settings were only configurable via Outlook, and we as administrators were not able to even see their corresponding values, let alone change them, as they were not exposed in the EAC or any of the underlying PowerShell cmdlets. This in turn created situations in which the admin or support person troubleshooting an issue had to “guess” what the related configuration was, or wait for the user to provide the required details. The only way to obtain this information outside of Outlook, or modify it, was via EWS, which required additional configuration and permissions, so it was far from ideal. Still, in some cases it was easier to use EWS instead of having to get to the user in order to check the settings from Outlook, thus administrators often used solutions such as the EWS delegate module.

Configuring a Delegate via PowerShell

With the recently introduced changes, all of this is now possible via PowerShell. To make things easier and to ensure compatibility with any custom scripts you might already be using, the team opted to not introduce any new cmdlets for delegate management. Instead, the familiar Add-/Get-/Remove-/Set-MailboxFolderPermission cmdlets have been updated to handle delegate scenarios.

You might have noticed that the output of the Get-MailboxFolderPermission changed few weeks back, and it now features one additional column, SharingPermissionFlags. So for example, you would see something like this:

Get-MailboxFolderPermission HuKu:\Calendar

FolderName           User                 AccessRights          SharingPermissionFlags
----------           ----                 ------------          ----------------------
Calendar             Default              {LimitedDetails}
Calendar             Anonymous            {None}

Unfortunately, the SharingPermissionFlags property will not always reflect the correct status, but more on this later. Let’s now see how one can configure delegate settings via PowerShell, as in how we can use the Add-MailboxFolderPermission cmdlet with the new parameters. If I want to add myself as delegate for another user, in addition to the customary Identity, User and AccessRights parameters, I will need to also specify the “level” of delegate access via the SharingPermissionFlags parameter. The parameter is a bit quirky, as it requires you to specify multiple values separated with comma for some configurations. More importantly, the SharingPermissionFlags parameter will only work if you have set the AccessRights parameter value to Editor, so make sure to remember that. To specify the fact that the user need to be added as delegate, set the value of SharingPermissionFlags to Delegate. Here’s an example:

Add-MailboxFolderPermission huku:\calendar -User vasil -AccessRights Editor -SharingPermissionFlags Delegate

FolderName           User                 AccessRights         SharingPermissionFlags
----------           ----                 ------------         ----------------------
Calendar             Vasil Michev         {Editor}             Delegate

Once this option is set, the user (me) will receive the Editor level of access to the Calendar folder, and the mailbox will have the “delegate receives a copy of meeting-related messages sent to me” option enabled, just as described in the previous section. Note that the cmdlet does not expose any way to change the scope of meeting requests delivery controlled by the “Deliver meeting requests addressed to me and responses to meeting requests where I am the organizer to” option. The reasons being, this is a global option and not configurable per delegate, but you can still use Outlook or EWS to control it.

Other uses of the SharingPermissionFlags parameter

If we also want to make sure that the delegate will be able to see Private items, the SharingPermissionFlags parameter needs to include the corresponding CanViewPrivateItems value. This value can only be supplied if Delegate value is also present, and as already mentioned above, if the AccessRights parameter is set to Editor. As we already used the Add-MailboxFolderPermission cmdlet to create a permission entry for that user though, this time we will use the Set-MailboxFolderPermission cmdlet to update it:

Set-MailboxFolderPermission huku:\calendar -User vasil -AccessRights Editor -SharingPermissionFlags Delegate,CanViewPrivateItems

To verify the permissions are applied, we can rerun the Get-MailboxFolderPermission cmdlet:

Get-MailboxFolderPermission HuKu:\Calendar

FolderName           User                 AccessRights           SharingPermissionFlags
----------           ----                 ------------           ----------------------
Calendar             Default              {LimitedDetails}
Calendar             Anonymous            {None}
Calendar             Vasil Michev         {Editor}               Delegate, CanViewPrivateItems

Note that the “Delegate can see my private items” option, corresponding to the CanViewPrivateItems value can technically be configured without requiring the user to be Delegate. This requirement is enforced by the parameter sets for the cmdlet, in order to reflect the “supported” configuration.

You can make additional changes at any point via the Set-MailboxFolderPermission cmdlet, for example, if you want to revoke the delegate-level permissions but still keep the user as Editor on the Calendar, specify the None value for the SharingPermissionFlags parameter:

Set-MailboxFolderPermission huku:\calendar -User vasil -AccessRights Editor -SharingPermissionFlags None

Or you can remove the entry altogether via the Remove-MailboxFolderPermission cmdlet:

Remove-MailboxFolderPermission huku:\calendar -User vasil

As with other folder level permissions, make sure that no existing entry exists before using the Add-MailboxFolderPermission cmdlet. Otherwise an error will be thrown, and you have to use the Set-MailboxFolderPermission cmdlet or simply remove the entry via the Remove-MailboxFolderPermission cmdlet first.

Using the SendNotificationToUser parameter

The other newly introduced parameter, SendNotificationToUser, serves to generate an email message summarizing the changes made into a “sharing invitation”. It’s the analog of the “Automatically send a message to delegate summarizing these permissions” checkbox in the Outlook Delegate dialog, shown above. The parameter can only be used when configuring permissions for Calendar folders, and only when one of the following AccessRights parameter values is specified: AvailabilityOnly, LimitedDetails, Reviewer or Editor.

Another important thing to note is that the SendNotificationToUser parameter is a Boolean, not a Switch. Thus, whenever you specify it, don’t forget to include the corresponding $true or $false value. I would personally prefer a switch, as it’s a cleaner and easier solution. I would also extend the same argument to the SharingPermissionFlags parameter, and have already left this feedback with Microsoft.

To complete our covering of the SendNotificationToUser parameter, here’s an example of what a “sharing invitation” will look like:


In this article, we took a quick look at the new parameters introduced to handle delegates in Exchange Online. While the changes to the *-MailboxFolderPermission can be classified as “minor”, they bring a welcome improvement to the way we can report on or set delegate permissions. With the changes discussed above, using EWS will no longer be necessary to accomplish this task, instead we can rely on the familiar PowerShell cmdlets, making the life of the admins easier.

It is important to understand that the new capabilities cannot account for every possible delegate scenario. In some cases, such as configuring the delivery scope of meeting requests, one might still need to resort to using Outlook or EWS. Another example is the requirement that the CanViewPrivateItems flag can only be used when the Delegate flag is set. Similarly, it’s also important to understand that the Get-MailboxFolderPermission might not correctly reflect on changes made via EWS or Outlook, as it only reflects the “supported” configuration.

Lastly, for folks still using on-premises Exchange – the changes detailed here are only available in Exchange Online. At least for the time being.

Posted in Exchange Online, Office 365, PowerShell | Leave a comment