Use PowerShell to move mailboxes

You can use PowerShell to move mailboxes, in addition to the Exchange Admin Center (EAC).

Move on-premises mailboxes to an Exchange Online organization

To move an on-premises mailbox to Exchange Online using PowerShell, perform the following steps:

  1. Connect to Exchange Online PowerShell: Start PowerShell as administrator and Connect to Exchange Online PowerShell by running the following command:

    PS C:\> Connect-ExchangeOnline
    
  2. Find migration endpoint remote server URL: Get the remote server URL by using the Get-MigrationEndpoint cmdlet.

    Get-MigrationEndpoint | Format-List Identity, RemoteServer
    

    The following output appears:

    PS C:\> Get-MigrationEndpoint | Format-List Identity, RemoteServer
    
    Identity     : Hybrid Migration Endpoint - EWS (Default Web Site)
    RemoteServer : <GUID>.resource.mailboxmigration.his.msappproxy.net
    

    Note

    The RemoteServer value in the preceding command syntax output is generated by running Hybrid Configuration Wizard (HCW).

  3. Copy the RemoteServer value as you need it in the next part.

    Note

    The value for the RemoteServer displayed in the preceding output command-syntax is generated when the user selects Use Exchange Modern Hybrid Topology in the Hybrid Topology page.

  4. Create a new move request to move primary and archive mailboxes to Exchange Online using PowerShell

    • Fill in the following details to create a new move request to move the primary mailbox and archive mailbox to Exchange Online:

      • Identity: Mailbox name or email address.
      • RemoteHostName: The remote server that you copied in Step 2.
      • TargetDeliveryDomain: Primary SMTP domain used for the Exchange Online organization mailboxes.
      • RemoteCredential: On-premises administrator account with privileges.

      After running the command, a credential sign-in request shows up.

      New-MoveRequest -Identity "Maisha.Lee@contoso.com" -Remote -RemoteHostName "mail.contoso.com" -TargetDeliveryDomain "<domain>.mail.onmicrosoft.com" -RemoteCredential (Get-Credential)
      
    • Fill in the password of the on-premises credentials (RemoteCredential).

  5. Move multiple mailboxes to Exchange Online using PowerShell

    • Create a CSV file named Users.csv and place it in the directory C:\migration.

    • Open the CSV file, name the header column EmailAddress, and fill in all the mailboxes that you like to move to Exchange Online.

      Screenshot that shows the CSV on which the details of mailboxes to move are entered.

    • Copy the following script and change the first 3 lines. After that, run the script.

      $Mailboxes = Import-Csv "C:\Migration\Users.csv"
      $RemoteHostName = "mail.contoso.com"
      $TargetDeliveryDomain = "<domain>.mail.onmicrosoft.com"
      $OnPremCred = (Get-Credential)
      
      # Move mailboxes in CSV file to Exchange Online
      foreach ($Mailbox in $Mailboxes) {
      $params = @{
      Identity               = $mailbox.EmailAddress
      Remote                 = $true
      RemoteHostName         = $RemoteHostName
      TargetDeliveryDomain   = $TargetDeliveryDomain
      RemoteCredential       = $OnPremCred
             }
      
      New-MoveRequest @params
      
         }
      
  6. Move primary mailbox only to Exchange Online using PowerShell

    There's a scenario wherein the archive mailbox location is in Exchange Online and the primary mailbox location is in Exchange on-premises, and you run the following command:

    $Mailboxes = Import-Csv "C:\Migration\Users.csv"
    $RemoteHostName = "mail.contoso.com"
    $TargetDeliveryDomain = "<domain>.mail.onmicrosoft.com"
    $OnPremCred = (Get-Credential)
    
    # Move mailboxes in CSV file to Exchange Online
    foreach ($Mailbox in $Mailboxes) {
    $params = @{
    Identity               = $mailbox.EmailAddress
    Remote                 = $true
    RemoteHostName         = $RemoteHostName
    TargetDeliveryDomain   = $TargetDeliveryDomain
    RemoteCredential       = $OnPremCred
           }
    
    New-MoveRequest @params
    
       }
    

    The result is that you receive the following error message which is part of the bigger command syntax that is shown after the error message:

    You must specify the PrimaryOnly parameter
    Target user ‘XXXXXX’ already has an archive mailbox.
    
    PS C:\> New-MoveRequest -Identity "Maisha.Lee@contoso.com" -Remote -RemoteHostName "mail.contoso.com" -TargetDeliveryDomain "<domain>.mail.onmicrosoft.com" -RemoteCredential (Get-Credential)
    You must specify the PrimaryOnly parameter.
    Target user 'Maisha Lee' already has an archive mailbox.
    + CategoryInfo          : NotSpecified: (:) [New-MoveRequest], MailboxReplicationPermanentException
    + FullyQualifiedErrorId : [Server=PAXP190MB1743,RequestId=3f8179c3-aa93-453f-9e14-d824968f34c4,TimeStamp=5/28/2022
    7:19:13 AM] [FailureCategory=Cmdlet-MailboxReplicationPermanentException] FE8B9422,Microsoft.Exchange.Management.
    Migration.MailboxReplication.MoveRequest.NewModernMoveRequest
    + PSComputerName        : outlook.office365.com
    

    Once you see the error message, perform the following steps:

    • Add the -PrimaryOnly parameter to the preceding command syntax to resolve the error when you create a new move request to move the primary mailbox only to Exchange Online.

    • Fill in the following details:

      • Identity: Mailbox name or email address.
      • RemoteHostName: The remote server that you copied in Step 2.
      • PrimaryOnly: Keep value empty.
      • TargetDeliveryDomain: Primary SMTP domain used for the Exchange Online organization mailboxes.
      • RemoteCredential: On-premises administrator account with privileges.

      After running the command for a new move request, a credential sign-in request shows up as shown in the following command syntax:

      New-MoveRequest -Identity "Maisha.Lee@contoso.com" -Remote -RemoteHostName "mail.contoso.com" -PrimaryOnly -TargetDeliveryDomain "<domain>.mail.onmicrosoft.com" -RemoteCredential (Get-Credential)
      
    • Fill in the password of the on-premises credentials (RemoteCredential).

  7. Move only archive mailbox to Exchange Online using PowerShell

    PS C:\> New-MoveRequest -Identity "Maisha.Lee@contoso.com" -Remote -RemoteHostName "mail.contoso.com" -TargetDeliveryDomain "<domain>.mail.onmicrosoft.com" -RemoteCredential (Get-Credential)
    You must specify the PrimaryOnly parameter.
    Target user 'Maisha Lee' already has an archive mailbox.
    + CategoryInfo          : NotSpecified: (:) [New-MoveRequest], MailboxReplicationPermanentException
    + FullyQualifiedErrorId : [Server=PAXP190MB1743,RequestId=3f8179c3-aa93-453f-9e14-d824968f34c4,TimeStamp=5/28/2022
    7:19:13 AM] [FailureCategory=Cmdlet-MailboxReplicationPermanentException] FE8B9422,Microsoft.Exchange.Management.
    Migration.MailboxReplication.MoveRequest.NewModernMoveRequest
    + PSComputerName        : outlook.office365.com
    
    • Add the ArchiveOnly parameter to the preceding command syntax to resolve the error when you create a new move request to move the archive mailbox only to Exchange Online.
    • Fill in the following details:
      • Identity: Mailbox name or email address.
      • RemoteHostName: The remote server that you copied in Step 2.
      • ArchiveOnly: Keep value empty.
      • TargetDeliveryDomain: Primary SMTP domain used for the Exchange Online organization mailboxes.
      • RemoteCredential: On-premises administrator account with privileges.

    After running the command for a new move request, a credential sign-in request shows up, as shown in the following command syntax:

    New-MoveRequest -Identity "Maisha.Lee@contoso.com" -Remote -RemoteHostName "mail.contoso.com" -ArchiveOnly -TargetDeliveryDomain "<domain>.mail.onmicrosoft.com" -RemoteCredential (Get-Credential)
    

    Fill in the password of the on-premises credentials (RemoteCredential).

  8. Get mailbox move status

    • Get the status of the mailbox move request by using the Get-MoveRequest cmdlet.

      Get-MoveRequest -Identity "Maisha.Lee@contoso.com" | Get-MoveRequestStatistics
      
    • Run the following command to get all the mailbox move requests:

      Get-MoveRequest | Get-MoveRequestStatistics
      

      The output shows the mailbox move status as Completed status, as shown in the following screenshot:

      Screenshot that shows the command that enables the user to get the mailbox move status.

      If that isn't the case and you can't complete the mailbox move request, you can suspend and resume the move request.

Move Exchange Online mailboxes to an on-premises organization

To move an Exchange Online mailbox to the on-premises organization using PowerShell, perform the following steps:

  1. Connect to Exchange Online PowerShell: Start PowerShell as administrator and Connect to Exchange Online PowerShell by running the following command:

    PS C:\> Connect-ExchangeOnline
    

    Note

    You aren't pulling the Exchange Online mailbox to on-premises. In fact, you are pushing the Exchange Online mailbox to on-premises. That's why you need to connect to Exchange Online and run the commands from Exchange Online PowerShell.

  2. Find migration endpoint remote server URL: Get the remote server URL by using the Get-MigrationEndpoint cmdlet.

    Get-MigrationEndpoint | Format-List Identity, RemoteServer
    

    The following output appears:

    Identity     : Hybrid Migration Endpoint - EWS (Default Web Site)
    RemoteServer : mail.contoso.com
    

    Note

    The RemoteServer value in the preceding command syntax output is generated by running Hybrid Configuration Wizard (HCW).

  3. Copy the RemoteServer URL value as you need it in the next part.

  4. Create a new move request to move primary and archive mailboxes from Exchange Online using PowerShell

    • Fill in the following details as part of creating a new move request to move the primary mailbox and archive mailbox from Exchange Online:

      • Identity: Mailbox name or email address.
      • RemoteTargetDatabase: Exchange on-premises mailbox database.
      • RemoteHostName: The remote server that you copied in Step 2.
      • TargetDeliveryDomain: Primary SMTP domain used for the Exchange Online organization mailboxes.
      • RemoteCredential: On-premises administrator account with privileges.

      The command to run to create a new move request is:

      New-MoveRequest -OutBound -RemoteTargetDatabase "DB01" -RemoteHostName "mail.contoso.com" -TargetDeliveryDomain "contoso.com" -RemoteCredential (Get-Credential)
      
    • Fill in the password of the on-premises credentials (RemoteCredential) for the credential sign-in request that displays as shown in the following command syntax once the command is run:

      PS C:\> Get-Mailbox -Identity "Jordy.Twin@contoso.com" | New-MoveRequest -OutBound -RemoteTargetDatabase "DB01" -RemoteHostName "mail.contoso.com" -TargetDeliveryDomain "contoso.com" -RemoteCredential (Get-Credential exoip\administrator)
      
      DisplayName Status TargetDatabase
      ----------- ------ --------------
      Jordy Twin  Queued
      

      After running the preceding command that includes the password of the on-premises credentials, you can get the following errors:

      • Cannot find a recipient that has mailbox GUID
      • The archive GUIDs on source and target recipients don't match
  5. Move only primary mailbox from Exchange Online using PowerShell

    • If the primary mailbox and archive mailbox locations are in Exchange Online, and you want to move the primary mailbox only, add -PrimaryOnly and -ArchiveDomain parameters to the command that you run to create a new move, and in the command syntax, fill in the following details:

      • Identity: Mailbox name or email address.
      • OutBound: Keep value empty.
      • RemoteTargetDatabase: Exchange on-premises mailbox database.
      • RemoteHostName: The remote server that you copied in Step 2.
      • PrimaryOnly: Keep value empty.
      • ArchiveDomain: Primary SMTP domain used for the Exchange Online organization mailboxes.
      • TargetDeliveryDomain: Primary SMTP domain used for the Exchange Online organization mailboxes.
      • RemoteCredential: On-premises administrator account with privileges.

      The command to run to create a new move request is:

      New-MoveRequest -OutBound -RemoteTargetDatabase "DB01" -RemoteHostName "mail.contoso.com" -PrimaryOnly -ArchiveDomain "<domain>.mail.onmicrosoft.com" -TargetDeliveryDomain "contoso.com" -RemoteCredential (Get-Credential)
      

      After running the command, a credential sign-in request displays as shown in the following command syntax:

      PS C:\> Get-Mailbox -Identity "Jordy.Twin@contoso.com" | New-MoveRequest -OutBound -RemoteTargetDatabase "DB01" -RemoteHostName "mail.contoso.com" -PrimaryOnly -ArchiveDomain "<domain>.mail.onmicrosoft.com" -TargetDeliveryDomain "contoso.com" -RemoteCredential (Get-Credential exoip\administrator)
      
      DisplayName Status TargetDatabase
      ----------- ------ --------------
      Jordy Twin  Queued
      

      Fill in the password of the on-premises credentials (RemoteCredential).

  6. Get mailbox move status

    • Get the status of the mailbox move request by using the Get-MoveRequest cmdlet.

      PS C:\> Get-MoveRequest -Identity "Jordy.Twin@contoso.com" | Get-MoveRequestStatistics | ft DisplayName,StatusDetail,TotalMailboxSize,TotalArchiveSize,PercentComplete
      
      DisplayName StatusDetail TotalMailboxSize             TotalArchiveSize PercentComplete
      ----------- ------------ ----------------             ---------------- ---------------
      Jordy Twin  Completed    231.6 MB (242,877,775 bytes) 0 B (0 bytes)                100
      

      The mailbox move completes. If that isn't the case and you can't complete the mailbox move request, you can suspend and resume the move request.

To implement the next step of removing the completed migrated batches, see Remove completed migration batches.