How to add a new a alias to an existing Office 365 group

Some time ago I worked with an organization that had difficulties in receiving emails on a newly added address. The Organization used “Set-UnifiedGroup” cmdlet to successfully add a new alias to an existing Office 365 group, but external senders were receiving the following NDR: “550 5.4.1 [newaddress@contoso.com]: Recipient address rejected: Access denied” upon sending an email to the new address.

So, I've decided to write a script and help this organization.

Scenario:

  • You want to add a new alias to an existing Office 365 Group.
  • You want external senders to be able to send emails to the new alias.

Current limitations:

  • It is not possible to add a new alias to an existing Office 365 Group in EAC.
  • The new alias is not replicated to DBEB (resulting in a rejection if an email is sent to the new address).

Workaround:

  • Use the Set-UnifiedGroup PowerShell cmdlet to add an alias to an existing Office 365 group (ex. Set-UnifiedGroup -Identity current_group_address@contoso.com -EmailAddresses: @{add="smtp:newaddress@contoso.com"}
  • Force the replication in DBEB by changing the primary address in Exchange Online (ex. Set-UnifiedGroup -PrimarySmtpAddress newaddress@contoso.com)

DISCLAIMER:

This application is a sample application. The sample is provided “as is” without warranty of any kind. Microsoft further disclaims all implied warranties including without limitation any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the samples remains with you. In no event shall Microsoft or its suppliers be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, data loss or other pecuniary loss arising out of the use of or inability to use the samples, even if Microsoft has been advised of the possibility of such damages. Because some states do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to you.

 Prerequisites:

Script logic:

  • Before taking any actions, the script tries to do some basic verifications:
    • Checks if the Current Group Address really exists in Exchange Online
    • Checks if the Current Group Address is the primary address (as at the end we will set it back)
    • Checks the domain of the New Group Address
    • Checks if the New Group Address already exists in Exchange Online
    • Checks if the New Group Address already exists in Azure AD
  • Adds the New Group Address to the Office 365 group
  • Sets the New Group Address as primary address in order to replicate it in DBEB
  • Reverts the primary address to Current Group Address

Script Sample:

#------------------------------------------------------------------------------
#
# Copyright © 2017 Microsoft Corporation.  All rights reserved.
#
# THIS CODE AND ANY ASSOCIATED INFORMATION ARE PROVIDED “AS IS” WITHOUT
# WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
# LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
# FOR A PARTICULAR PURPOSE. THE ENTIRE RISK OF USE, INABILITY TO USE, OR
# RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#
#------------------------------------------------------------------------------
#
# PowerShell Source Code
#
# NAME:
#    Office365_add_alias.ps1
#
# VERSION:
#    1.0
#
#------------------------------------------------------------------------------
[CmdletBinding()]
param
(
[Parameter(Mandatory = $True, Position = 0)]
[ValidateNotNullOrEmpty()]
[string]$CurrentGroupAddress,

[Parameter(Mandatory = $True, Position = 1)]
[ValidateNotNullOrEmpty()]
[string]$NewGroupAddress
)

#region Set Up Variables
$Matcheduser = $Null
$Matchedgroup = $Null
$MatchedOldGroup = $Null
$Objid = $Null
$CheckDomain = $Null
$AllUsers = $Null
$AllGroups = $Null
$MatchedUnifiedOldGroup = $Null
$MatchedRecipient = $Null
$MatchedMSODS = $Null
$MatchedEXO = $Null
$UserMatchFound = $false
$GroupMatchFound = $false
$MSODSEmailAddress = $Null
$CounterEXO = 6
$CounterMSODS = 6
$CheckEXO = $Null
$CheckMSODS = $Null
#endregion

#region Connect to Office 365
try
{
# Connect to Azure AD
Write-Host "Please enter your Office 365 credentials" -ForeGroundColor Green
$O365Cred = Get-Credential
Import-Module MSOnline
Write-Host "`nConnecting to Azure AD..."
Connect-MsolService –Credential $O365Cred

# Connect to Exchange Online
Write-Host "`nConnecting to Exchange Online..."
$O365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $O365Cred -Authentication "Basic" -AllowRedirection
Import-PSSession $O365Session -DisableNameChecking -AllowClobber | ft

}
catch
{
Write-Host "`nUnable to connect to Office 365`n" -Foregroundcolor Red
Read-Host “Press ENTER to exit...”
Exit
}
#endregion

#region Checking if the old address exists
Write-Host "Checking the address $CurrentGroupAddress in Exchange Online"
$MatchedUnifiedOldGroup = Get-UnifiedGroup -Identity $CurrentGroupAddress -ErrorAction SilentlyContinue | select Name, EmailAddresses
if ($MatchedUnifiedOldGroup -eq $Null)
{
Write-Host "`tI was not able to find $CurrentGroupAddress in Exchange Online `n"-Foregroundcolor Red
Read-Host “Press ENTER to exit...”
Exit
}
else
{
Write-Host "`tDone. The address $CurrentGroupAddress was found in Exchange Online`n" -Foregroundcolor Yellow
}
Write-Host "Checking the address $CurrentGroupAddress in Azure AD"
$MatchedOldGroup = Get-MsolGroup -All -SearchString $CurrentGroupAddress | select ObjectId,proxyAddresses
if ($MatchedOldGroup -eq $Null)
{
Write-Host "`tI was not able to find $CurrentGroupAddress. Are you sure this is the primary address of the group?`n"-Foregroundcolor Red
$Objid = (Get-UnifiedGroup $CurrentGroupAddress).ExternalDirectoryObjectId
$MSODSEmailAddress = Get-MsolGroup -ObjectId $objid |select EmailAddress
Write-Host "Based on Exchange Online info $($MSODSEmailAddress.EmailAddress) might be the primary address. Would you like me to use this address instead of $($CurrentGroupAddress)? (Default is No)" -Foregroundcolor Yellow
$Readhost = Read-Host "Enter your choice ( y / n ) "
Write-Host "`n"
Switch ($ReadHost)
{
Y {$CurrentGroupAddress = $MSODSEmailAddress.EmailAddress}
N {Read-Host “Press ENTER to exit...”;  Exit}
Default {Read-Host “Press ENTER to exit...”;  Exit}
}
}
else
{
Write-Host "`tDone. The address $CurrentGroupAddress was found `n" -Foregroundcolor Yellow
}
#endregion

#region Verify the new address
Write-Host "Checking if the address $NewGroupAddress is part of an accepted domain"
$CheckDomain = Get-AcceptedDomain -Identity ($NewGroupAddress.Split("@"))[1] -ErrorAction SilentlyContinue
If ($CheckDomain -eq $Null)
{
Write-Host "`tDomain does not exists or is not correct`n" -Foregroundcolor Red
Read-Host “Press ENTER to exit...”
Exit
}
else
{
Write-Host "`tDone. The domain was found `n" -Foregroundcolor Yellow
}
#endregion

#region Checking if new address exists in MSODS
Write-Host "Checking if any user in Azure AD contains $NewGroupAddress (this may take a while)..."
$AllUsers = Get-MsolUser –All | Select userPrincipalName,proxyAddresses
$AllGroups = Get-MsolGroup –All | Select ObjectId,proxyAddresses

#loop all users
ForEach ($User in $AllUsers)
{
#loop proxyAddresses
ForEach ($UPA in $User.ProxyAddresses)
{
If ($UPA –Match $NewGroupAddress)
{
$UserMatchFound = $True
$Matcheduser = $User
}
}

}
write-host "`tDone. `n" -Foregroundcolor Yellow
write-host "Checking if any group in Azure AD contains $NewGroupAddress (this may take a while)..."

#loop all groups
ForEach ($Group in $AllGroups)
{

#loop proxyAddresses
ForEach ($GPA in $Group.ProxyAddresses)
{
If ($GPA –Match $NewGroupAddress)
{
$GroupMatchFound = $True
$Matchedgroup = $Group
}
}

}
write-host "`tDone.`n" -Foregroundcolor Yellow

If ($UserMatchFound -or $GroupMatchFound)
{
$MatchedMSODS = $true
If ($UserMatchFound)
{
Write-Host "`nThe new address exists in Azure AD"
Write-Host "The user $($Matcheduser.userPrincipalName) contains the following addresses: $($Matcheduser.ProxyAddresses)`n" -Foregroundcolor Red
Read-Host “Press ENTER to exit...”
Exit
}
Else
{
Write-Host "`nThe new address exists in Azure AD"
Write-Host "`The group $($Matchedgroup.ObjectId) contains the following addresses: $($Matchedgroup.ProxyAddresses)`n" -Foregroundcolor Red
Read-Host “Press ENTER to exit...”
Exit
}
}
Else
{
write-host "`tDone. No user or group found in Azure AD`n" -Foregroundcolor Yellow
}

#endregion

#region Checking if new address exists in EXO
Write-Host "Checking the address $NewGroupAddress in Exchange Online "
$MatchedUnifiedGroup = Get-UnifiedGroup -Identity $NewGroupAddress -ErrorAction SilentlyContinue | select Name, EmailAddresses
$MatchedRecipient = Get-Recipient -Identity $NewGroupAddress -ErrorAction SilentlyContinue | select Name, EmailAddresses
if (($MatchedUnifiedGroup -ne $Null) -or ($MatchedRecipient -ne $Null))
{
$MatchedEXO = $true
If ($MatchedRecipient -ne $Null)
{
Write-Host "`tDone. receipint $($MatchedRecipient.name) contains the following addresses: $($MatchedRecipient.EmailAddresses) `n" -Foregroundcolor Yellow
}
Else
{
Write-Host "`tDone. Unified Group $($MatchedUnifiedGroup.Name) contains the following addresses: $($MatchedUnifiedGroup.EmailAddresses)  `n" -Foregroundcolor Yellow
}
Write-Host "The new address already exists`n" -Foregroundcolor Red
Read-Host “Press ENTER to exit...”
Exit
}
Else
{
Write-Host "`tDone. No user or group was found in Exchange Online`n" -Foregroundcolor Yellow
}
#endregion

#region Adding the new address
Write-Host "Finished all checks. Moving forward...`n" -Foregroundcolor Green
if (!$MatchedMSODS -and !$MatchedEXO)
{
$Objid = (Get-UnifiedGroup $CurrentGroupAddress).ExternalDirectoryObjectId
Write-Host "Adding $NewGroupAddress in Exchange Online"

# add the new address
Set-UnifiedGroup -Identity $CurrentGroupAddress -EmailAddresses: @{add="smtp:$NewGroupAddress"}

do
{
sleep 10
$CounterEXO--
$CheckEXO = Get-UnifiedGroup -Identity $NewGroupAddress
}
while (($CounterEXO -ge 0) -and ($CheckEXO -eq $Null))

if ($CheckEXO -eq $Null)
{
Write-Host "I was not able to add the new address`n" -Foregroundcolor Red
Read-Host “Press ENTER to exit...”
Exit
}
Else
{
Write-Host "`tDone.`n" -Foregroundcolor Yellow
}

Write-Host "Adding $NewGroupAddress in Azure AD"

# Changing the primary address to force the sync
Get-UnifiedGroup $CurrentGroupAddress | Set-UnifiedGroup -PrimarySmtpAddress $NewGroupAddress

do
{
sleep 10
$CounterMSODS--
$CheckMSODS = Get-MsolGroup -All -SearchString $NewGroupAddress | select emailaddress
Write-Host "`tPlease wait..."
}
while (($CounterMSODS -ge 0) -and ($CheckMSODS -eq $Null))

if ($CheckMSODS  -eq $Null)
{
Write-Host "I was not able to sync the new address`n" -Foregroundcolor Red
Read-Host “Press ENTER to exit...”
Exit
}
Else
{
Write-Host "`tDone.`n" -Foregroundcolor Yellow
}

# Changing back the primary address
Get-UnifiedGroup $NewGroupAddress | Set-UnifiedGroup -PrimarySmtpAddress $CurrentGroupAddress
Write-Host "`nAll Done! Wait 15 mins before doing a test!`n" -Foregroundcolor Yellow
Read-Host “Press ENTER to exit...”
Remove-PSSession $O365Session
}
#endregion