Sunday, November 24, 2019

Script to move On-Premise users mailboxes to Office 365 (Exchange Online) Automated

Migrating mailboxes to Office 365 was a quite challenging Project, primarily due third party software that we use as MDM and the customization of tools and access. Once  we completed our planned migration tasks by 500 mailbox each (this was the recommended number by Microsoft) we decided to keep one On-Prem Exchange 2016 server for some shared mailboxes used by Service accounts applications that are not compatible with Office 365. Also, because our Hybrid environment and our mailbox provision process, we decided to create new users mailboxes on-Prem and move them to Office 365 on daily basis. 
For we I develop a Script that makes the Job, just schedule it in  MS Orchestrator or Tasks Scheduler and that it, a report with the users to migrate will be delivered to the specified admin mailbox or DL.

Hope this script helps you make your life easier, please send me comments or questions.


##################################
<#PSScriptInfo

.VERSION 1.0

.AUTHOR "ralbertomx@gmail.com"

#>

<#

.DESCRIPTION
Script to move On-Premise users mailboxes to Office 365. The script can be run interactive or schedule in regulat basis to move new mailboxes.
The following 5 variables are the only ones you need to modify.
Place the "format4.css" (provided as example) and "creds\EOPCreds.txt" in the same folder, or modify paths if not.

#>


# variables to modify
$adminmail = "admin@emaildomain.com"  # Modify the recipient of the report
$frommail = "Office365@maildomain.com"  # Modify the sender of the report
$smtphost = "smtp.maildomain.com"  # Modify your SMTP host
$UPNsufix = "maildomain.com"  # Modify your UPN sufix in case is different from DNS AD domain, without the "@" character
$TenantDomain = "Company123.mail.onmicrosoft.com" # Modify your Tenant Domain, without the "@" character


#-------Migration Script, define Job name and CSS format
$JName = "DailyMigrationJob"
$head = Get-Content ".\format4.css"


# Specifu the file to be used as input for the migration
$txtfile = ".\mails.csv"
Set-Content $txtfile "EmailAddress"

# Connect to you Exchange on Prem
$exchangeser = "EXCHANGECAS01"  #Specify CAS server
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI http://$exchangeser/powershell/ -Authentication kerberos
import-PSSession $session -AllowClobber

#Connect to AD module
Import-Module ActiveDirectory

# Get User mailboxes and identify its location 
$table = Get-ADUser -Filter {Enabled -eq "True"} -Properties distinguishedName,samaccountname,mail,userprincipalname,employeeType,msExchRecipientTypeDetails `
| where {($_.msExchRecipientTypeDetails)} `
| select @{Label="Location";Expression={
    If ($_.msExchRecipientTypeDetails -eq "1") {"On-Prem"}
    ElseIf ($_.msExchRecipientTypeDetails -eq "4") {"On-Prem"}
    ElseIf ($_.msExchRecipientTypeDetails -eq "2147483648") {"Office365"}
    ElseIf ($_.msExchRecipientTypeDetails -eq "34359738368") {"Office365"}
    Else {"OtherLocation"}
    }},samaccountname,mail,userprincipalname,employeeType

# Filter the users mailboxes that are On-Prem only
$csvData = $table | where {$_.Location -eq "On-Prem" }


# Notify about mailbox migration
If ($csvData) {
    ## Connect to EOP
    If ($session2.state -ne "Opened") { 
        Write-Host "Opennig EOP Session.." -ForegroundColor Cyan
        <# Use this session to input your credentials manually
        #$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Authentication Basic -AllowRedirection -Credential $(Get-Credential)
        #Import-PSSession $session
        #>
        # Use this section to save the credential password inside a file named ".\creds\EOPCreds.txt" and automate the Job, 
        $AdminName = "upn@ad-domain.local" 
        $Pass = Get-Content ".\creds\EOPCreds.txt" | ConvertTo-SecureString
        $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminName, $Pass
        $Session2 = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $cred -Authentication Basic -AllowRedirection
        Import-PSSession $Session2
    }
    Else {
        Write-Host "Session to EOP is opened.." -ForegroundColor Green
    }

 # removing previous mig job
    $MigJob = Get-MigrationBatch -Identity $JName -ErrorAction SilentlyContinue

    If ($MigJob) {
        If ($MigJob.Status.Value -like "*Completed*") {  # Removing a previous Job if completed or completed with errors
            Write-Host "Job Exists and completed, removing" -ForegroundColor Green
            Remove-MigrationBatch -Identity $JName -Confirm:$false
            Start-Sleep -Seconds 360
        }
        ElseIf ($MigJob.Status.Value -eq "Syncing") {  # If job is Syncing, exit the script
            Write-Host "Exists but not completed, exiting script" -ForegroundColor Magenta 
            Exit 
        }
    }
    Else {Write-Host "Job Doesnt exist, continue creating job" -ForegroundColor Yellow}
    Write-Host "Script continues.." -ForegroundColor Green

    $count = $csvData.Count
    $strBody = $csvData |  ConvertTo-Html -Title "Office 365 DailyMigrationJob" -head $head -PreContent "The listed mailboxes will be scheduled to be migrated:"
    Send-MailMessage -To $adminmail -From $frommail -Subject "Office 365 DailyMigrationJob, Total: $count mailboxes" `
    -SmtpServer $smtphost -BodyAsHtml -Body "$strBody"

    # Add Onmicrosoft email address
    foreach ($mbx in $csvData){
        $pri = $mbx.mail
        $newaddress = ($mbx.mail -split "@")[0] + "@" + $TenantDomain
        If ($mbx.EmailAddresses -like "*$TenantDomain*") { #--TargetAddress--
            #Write-Host "`t $usr Email contains herbalife663.mail.onmicrosoft.com" -ForegroundColor Green
            #Write-Host $mbx.EmailAddresses
        }
        Else {
            Write-Host "`t Mail.OnMicrosoft.com address missing for user $pri, adding: $newaddress" -ForegroundColor Yellow
            Set-Mailbox $pri -EmailAddresses @{add=$newaddress}
        }


    # UPN correction
        $newUPN = ($mbx.userPrincipalName -split "@")[0] + "@" + $UPNsufix
        If ($user.userPrincipalName -like "*$UPNsufix") {
            #Write-Host "`t $($user.samAccountName) UPN is herbalife.com" -ForegroundColor Green
        }
        Else {
            Write-Host "`t UPN is not correct for user $($mbx.samAccountName), setting: $newUPN" -ForegroundColor Yellow
            Set-aduser $mbx.samAccountName -userPrincipalName $newUPN
        }
    }
$currtime = Get-date
    Write-host "$currtime - Waiting 45 minutes for ADConnect sync.." -foregroundcolor gray  
    Start-Sleep -Seconds 2700  # If your ADSync schedule is different, you can change this value in seconds
    
    Write-host "Continuing with Job.." -foregroundcolor gray

    ##CSV file population
    $csvdata | foreach {
        $mails = $_.mail
        Add-Content $txtfile $mails
    }

    # Move Mailbox
    $csvfile=[System.IO.File]::ReadAllBytes($txtfile)
    New-MigrationBatch -CSVData $csvfile -Timezone "Pacific Standard Time" -Name "$JName" `
    -SourceEndpoint amer-owa.hrbl.com -TargetDeliveryDomain $TenantDomain `
    -AutoStart -AutoComplete -BadItemLimit 100 -NotificationEmails $adminmail -confirm:$false
}

#########################################

C.R.