Managing Office 365 e-mail addresses easy with PowerShell when using DirSync

In most cases you uninstall your local Exchange server after migrating your e-mail to Exchange Online. If you also choose to implement DirSync you place the administration in your local domain instead of the Office 365 Administration Portal.

This means that there is no longer a GUI tool to handle some of the settings related to your mailboxes. Of course you can keep a machine with your old Exchange 2010 Management Console, but often the reason for moving to the cloud is to reduce the complexity and minimize the number of machines.

We don’t have the same problem with other attributes, for example displayname or phone numbers that you’ll find in Users and Computers or the Administrative Center introduced in Windows Server 2008. It does get a bit trickier when you are about to modify primary email address or add alias addresses.

Currently there are no available GUI tools from Microsoft to handle these types of updates easy (but keep your eyes open, things might change 😉 ). However, there are a few third-party tools to achieve this, unless you want to use the Attribute Editor in Users and Computers, or Adsiedit.

Since I’m a big fan of PowerShell I wanted to build a small set of tools to handle simple changes of email addresses. These functions are easy for you to use in your own scripts.

First of all, a function that lists all email addresses of a user:

function Get-O365AliasAddress {
<#
.SYNOPSIS
    Displays all email addresses assigned to a user.
.PARAMETER Identity
    The user to query.
.EXAMPLE
    Get-O365AliasAddress -Identity user01
.EXAMPLE
    Get-ADUser user01 | Get-O365AliasAddress
.NOTES
    Author: Andreas Lindahl
    Blog: 365lab.net
    Email: andreas.lindahl[at]jsc.se
    The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights.
#>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipelineByPropertyName=$true,Mandatory=$True,ValueFromPipeline=$True,
        HelpMessage="The name of the user to get addresses of")]
        [string]$Identity
    )

    Import-Module ActiveDirectory

    $result = @()

    (Get-ADUser -Identity $Identity -Properties proxyAddresses).proxyAddresses | foreach {
        $proxy =  $_.split(":")
        $object = New-Object System.Object
        $object | Add-Member –Type NoteProperty –Name Type –Value $proxy[0]
        $object | Add-Member –Type NoteProperty –Name Address –Value $proxy[1]
        $object | Add-Member –Type NoteProperty –Name IsPrimary –Value ($proxy[0] -ceq $($proxy[0].ToUpper()))
        $result += $object
    }
    return $result
}

Next, a function that adds an alias to an existing user

function Add-O365AliasAddress {
<#
.SYNOPSIS
    Adds an alias address to a user.
.PARAMETER Identity
    The user to modify.
.PARAMETER Address
    The address to add.
.PARAMETER Type
    The type of address. Default is smtp.
.PARAMETER SetAsDefault
    Indicates if the address should be de default address of the user
.EXAMPLE
    Add-O365AliasAddress -Identity user01 -Address test@365lab.net -SetAsPrimary
.NOTES
    Author: Andreas Lindahl
    Blog: 365lab.net
    Email: andreas.lindahl[at]jsc.se
    The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights.
#>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipelineByPropertyName=$true,Mandatory=$True,ValueFromPipeline=$True,
        HelpMessage="The name of the user")]
        [string]$Identity,

        [Parameter(Mandatory=$True,
        HelpMessage="The address to add")]
        [string]$Address,

        [Parameter(
        HelpMessage="The type of the address to add")]
        [string]$Type="smtp",

        [Parameter(
        HelpMessage="Indicates that the address will be set as the default address")]
        [switch]$SetAsDefault
    )

    Import-Module ActiveDirectory

    $Type = $Type.ToLower()

    $defaultaddress = ''
    $proxyaddresses = ''
    $proxyaddress = ''

    #Get all existing proxyAddresses of the same type
    $proxyaddresses = (Get-ADUser -Identity $Identity -Properties proxyAddresses).proxyAddresses | where-object { $_ -like "$Type*" }

    #Get current default address of this type
    foreach ($proxyaddress in $proxyaddresses) {
        $pa = $proxyaddress.split(':')
        if ($pa[0] -ceq $pa[0].ToUpper()) {
            $defaultaddress = $proxyaddress
        }
    }

    #If this is the first address, it will be the default
    if ($proxyaddresses.count -eq 0) {
        $SetAsDefault = $true
    }

    if ($SetAsDefault) {

        #New default address to set. Start by removing the old one, but keep it as alias.
        if ($defaultaddress) {
            $pa = $defaultaddress.split(':')
            $newdefaultaddress = "$($pa[0].ToLower()):$($pa[1])"
            Set-ADUser -Identity $Identity -Remove @{proxyaddresses=$defaultaddress} -Add @{proxyaddresses=$newdefaultaddress}
        }

        #Set new default address. In case it already exists, remove it first (it might already be used as alias)
        if ($Type -eq 'SMTP') {
            Set-ADUser -Identity $Identity -Remove @{proxyaddresses="$($Type.ToLower()):$Address" } -Add @{proxyaddresses="$($Type.ToUpper()):$Address" } -EmailAddress $Address
        } else {
            Set-ADUser -Identity $Identity -Remove @{proxyaddresses="$($Type.ToLower()):$Address" } -Add @{proxyaddresses="$($Type.ToUpper()):$Address" }
        }

    } else {
        #Just add the new address
        Set-ADUser -Identity $Identity -Add @{proxyaddresses="$($Type):$Address" }
    }
}

Finally we also need a script to delete addresses

function Remove-O365AliasAddress {
<#
.SYNOPSIS
    Removes an alias address from a user.
.PARAMETER Identity
    The user to modify.
.PARAMETER Address
    The address to remove.
.PARAMETER Type
    The type of address. Default is smtp.
.EXAMPLE
    Remove-O365AliasAddress -Identity user01 -Address test@365lab.net
.NOTES
    Author: Andreas Lindahl
    Blog: 365lab.net
    Email: andreas.lindahl[at]jsc.se
    The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights.
#>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipelineByPropertyName=$true,Mandatory=$True,ValueFromPipeline=$True,
        HelpMessage="The name of the user")]
        [string]$Identity,

        [Parameter(Mandatory=$True,
        HelpMessage="The address to remove")]
        [string]$Address,

        [Parameter(
        HelpMessage="The type of the address to remove")]
        [string]$Type="smtp"

    )

    Import-Module ActiveDirectory

    $Type = $Type.ToLower()
    $defaultaddress = ''
    $newdefaultaddress = ''
    $proxyaddresses = ''

    #Get all existing proxyAddresses of the same type
    $proxyaddresses = (Get-ADUser -Identity $Identity -Properties proxyAddresses).proxyAddresses | where-object { $_ -like "$Type*" }

    #Get current default address of this type
    foreach ($proxyaddress in $proxyaddresses) {
        $pa = $proxyaddress.split(':')
        if ($pa[0] -ceq $pa[0].ToUpper()) {
            $defaultaddress = $proxyaddress
        }
    }

    if ($defaultaddress -eq "$($Type):$Address") {
        #We are trying to remove the default address. Now it becomes a bit tricky...
        #First, find the next address of the same type that we can use as default address
        foreach ($proxyaddress in $proxyaddresses) {
            if ($proxyaddress -ne "$($Type):$Address") {
                $newdefaultaddress = $proxyaddress
                break
            }
        }
    }

    #Now we can remove the address
    Set-ADUser -Identity $Identity -Remove @{proxyaddresses="$($Type):$Address"}
    if ($Type -eq 'smtp' -and $defaultaddress -eq "$($Type):$Address") {
        Set-ADUser -Identity $Identity -Clear mail
    }

    if ($newdefaultaddress) {
        #Set $newdefaultaddress as new default address
        Write-Warning "New default address set: $newdefaultaddress"
        Add-O365AliasAddress -Identity $Identity -Address $newdefaultaddress.split(":")[1] -Type $Type -SetAsDefault
    }
}

Now we can play with these functions:

O365AliasAddress

I have put together a PowerShell Module for you to import. Just load it with the Import-Module cmdlet.

Import-Module O365ProxyAddresses

The module can be downloaded here.

I hope that you will find these functions useful in your daily user administration tasks. Please leave your comments below and feel free to suggest improvements.

Happy coding!

/ Andreas

Advertisements

20 thoughts on “Managing Office 365 e-mail addresses easy with PowerShell when using DirSync

      1. rebootrinserepeat

        Let me ask another way. If that specific module is already installed (as it seems to be by default) and the script command “get-o365aliasaddress ” is run from an Exchange 2010 server (or dirsync server) hosted on Windows 2008 R2, how does one avoid getting “unable to connect to server” or “unable to find default server with active directory web services running” as the results?

    1. Andreas Lindahl Post author

      Hi. The script uses the Set-ADUser cmdlet, which requires a Windows Server 2008 R2 Domain Controller or newer.

  1. Pingback: The UC Architects » Episode 33: Managing, Migrating, and Moving

  2. Birddogsc

    Thanks for the script… I have been looking for a way to make this easier for my lower-level admins. This will definitely help. I was planning to try to wrap something like this up in a GUI. Any chance of something like that showing up?

    1. Johan Dahlbom

      Thanks for reading! We don’t have a gui wrapper planned as of right now, but the more requests we get on specific features, the easier it will be for us to prioritize what to do first. 🙂

  3. asuthanah

    HI,

    Thanks for this, its very useful. A GUI wrapper would be really handy too – just asking!

    Thanks

  4. Leonard Larsen

    Great work, Thanks a lot! 🙂

    I have made a small function to this that I thought I would share.

    It is a simple function that reads each line in a .txt file containing my company’s domains and pipes that into a foreach loop, this way I only have to run one command to add all the default addresses that we normaly add to a new user.

    I am not sure if this is the best way to go about doing this, but I am just starting out learning Powershell and it works for me.

    The file shout only have one domaine per line and shout start white a “@”, Like so;
    @leolab.com
    @leolab.dk
    @dom.leolab.com

    Remember that the first line/domaine in the file will be the primary SMTP address by the “Add-O365AliasAddress” command, unless the user already have an SMTP address, in which case you must do this manually if needed.

    The script:

    function Apply-O365DefaultProxyAddress {
    
        [CmdletBinding()] 
        param (
            [Parameter(ValueFromPipelineByPropertyName=$true,Mandatory=$True,ValueFromPipeline=$True)] 
            [string]$Identity,
    
            [Parameter()] 
            [string]$SourceFile="C:\Users\adminll\Documents\Admin Scripts\defaultSMTP.txt",
            
            [Parameter()]
            [string]$mailName = $Identity
        )
        
        import-module ActiveDirectory
        # Get files from default file, and pipe it down an foreach loop that takes each line one at a tilme.
        Get-Content $SourceFile | ForEach {
            # The SMTP address is found by merging both the mailname (eks. HelpDisk) and the pipline var (Eks. @leolab.dk)
            $address = $mailName + $_
        
            Write-Verbose  "Calling Add-O365ProxyAddress as Identity $Identity and an address of $address "
            Add-O365ProxyAddress -Identity $Identity -Address $address
        } 
    }
    
    1. Andreas Lindahl Post author

      Thanks for sharing! Always good to hear that our blog posts are helpful to you.

  5. Pingback: Minimum Exchange Hybrid Server Requirements for Managing On-Premises Users | The Cloud Technologist

  6. Josh

    I made a GUI for this mate to make it easier for some of my clients who are less good at scripting. Just extract all to somewhere (with powershell 3, .net 4 and admin tools installed) then run the “O365 email address management gui.ps1” file.

    http://1drv.ms/1FL1HU4

    You will also need to set your execution policy to allow it to run.

    The GUI stuff was borrowed from here http://blogs.technet.com/b/heyscriptingguy/archive/2014/08/01/i-39-ve-got-a-powershell-secret-adding-a-gui-to-scripts.aspx if anyone wants to have a go or improve my design.

    Also there is a try, catch in there for wrong usernames, this will stop it showing error messages if its not running right comment out the try and catch lines then try again.

    Hope its of use to someone.

  7. steve

    Hi Josh – the GUI just errors for me
    PS C:\nx\O365 email management GUI> & ‘.\Office 365 Email address manageme
    nt GUI.ps1’
    Security Warning
    Run only scripts that you trust. While scripts from the Internet can be useful,
    this script can potentially harm your computer. Do you want to run
    C:\nx\O365 email management GUI\Office 365 Email address management
    GUI.ps1?
    [D] Do not run [R] Run once [S] Suspend [?] Help (default is “D”): r

    Security Warning
    Run only scripts that you trust. While scripts from the Internet can be useful,
     this script can potentially harm your computer. Do you want to run
    C:\nx\O365 email management GUI\loadDialog.ps1?
    [D] Do not run  [R] Run once  [S] Suspend  [?] Help (default is "D"): r
    Exception calling "Load" with "1" argument(s): "The invocation of the construct
    or on type 'System.Windows.Window' that matches the specified binding constrain
    ts threw an exception."
    At C:\nx\O365 email management GUI\loadDialog.ps1:33 char:51
    + $Global:xamGUI = [Windows.Markup.XamlReader]::Load <<<< ((new-object System.X
    ml.XmlNodeReader $xmlWPF))
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    You cannot call a method on a null-valued expression.
    At C:\nx\O365 email management GUI\loadDialog.ps1:41 char:54
    +  Set-Variable -Name ($_.Name) -Value $xamGUI.FindName <<<< ($_.Name) -Scope G
    lobal
        + CategoryInfo          : InvalidOperation: (FindName:String) [], RuntimeE
       xception
        + FullyQualifiedErrorId : InvokeMethodOnNull
    
    Security Warning
    Run only scripts that you trust. While scripts from the Internet can be useful,
     this script can potentially harm your computer. Do you want to run
    C:\nx\O365 email management GUI\O365ProxyAddresses.psm1?
    [D] Do not run  [R] Run once  [S] Suspend  [?] Help (default is "D"):
    
  8. Josh

    Hi Steve, Sorry I didnt get an email to say there was a reply. you might need to set the execution policy for powershell to allow unsigned scripts, run (as administrator in powershell) Set-ExecutionPolicy unrestricted then try again. Do so at own risk etc etc etc.

  9. Pingback: References: Managing Office 365 through Directory Synchronization without Exchange | ODDYTEE

  10. Pingback: Minimum Exchange Hybrid Server Requirements for Managing On-Premises Users | Catapult Systems

  11. Gord Clee

    In my environment I got an error in the Add-O365AliasAddress function. A type mismatch in the line:
    Set-AdUser -Identity $Identity -Remove @{proxyaddresses=$defaultaddress} -Add @{proxyaddresses=$newdefaultaddress}

    I fixed it by adding some double quotes like this:
    Set-AdUser -Identity $Identity -Remove @{proxyaddresses=”$defaultaddress”} -Add @{proxyaddresses=”$newdefaultaddress”}

    I hope this helps someone else who may have the same problem.

  12. Pingback: Decommission or Maintain Exchange Hybrid? It Depends | ODDYTEE

Comments are closed.