I use this script in migrations from on-premises Exchange server to Exchange Online (Office 365, M365) mailboxes. Many times, I will just kick off all the migrations, let them sync up. Come back later and set the completion time/date in groups according to whatever schedule my customer creates. This script reads a list of users from a text file, sets a specific completion time for their move requests, and initiates the move requests with additional settings to handle bad items and potential data loss.

What It Looks Like

User migration script

The List Format

The list containing users should be formatted as: (using user ID’s pulled from AD)


Save it as a CR/LF text file.

Technical Details

The details of the script actions:

  1. It reads the contents of a text file named “migrate_user.txt” located at “C:\temp” and assigns the content to the variable $User.
  2. It gets the current date and assigns it to the variable $day in the format “MM/dd/yyyy”.
  3. It concatenates the value of $day with the string ” 5:00 AM” and assigns the resulting datetime string to the variable $date.
  4. It iterates over each item in the $User variable using a foreach loop, assigning each item to the variable $UItem.
  5. Within the loop, it executes the cmdlet Set-MoveRequest to initiate a move request for the identity specified by $UItem.
    – The -Identity parameter specifies the identity of the object to be moved (user or mailbox).
    – The -CompleteAfter parameter sets the completion time for the move request to the date and time specified by $date, converted to Universal Time.
    – The -BadItemLimit parameter sets the maximum number of corrupted or bad items to be skipped during the move.
    – The -AcceptLargeDataLoss parameter allows the move request to proceed even if there is a potential for data loss.
    – The -Confirm:$False parameter suppresses the confirmation prompt for each move request.

Get the Script

Copy and paste from below or download the txt version here.

$User = Get-Content "c:\temp\migrate_user.txt"
$day = Get-Date -Format "MM/dd/yyyy"
$date = $day + " 5:00 AM"
ForEach ($UItem in $User){
#(complete move, change date to today)
Set-MoveRequest -Identity $Uitem -CompleteAfter (Get-Date "$date").ToUniversalTime() -BadItemLimit 1000 -AcceptLargeDataLoss -Confirm:$False}