Quest recently announced that the On Demand Migration (ODM) PowerShell API module is now available in the PowerShell gallery. To help get you started, we have compiled a few example scripts that demonstrate how to perform common migration activities using the ODM API.
The examples below assume you have already connected to ODM and selected your Organization, Project, and ProjectWorkload, as described in the ODM API New Feature Spotlight. Note that these scripts are provided as-is for example purposes only, and you may need to modify them to work for your specific project.
Table of Contents
- Discover Accounts - Create task, start task, monitor task status
- Migrate Accounts - Create multiple tasks with a defined number of objects
- Migrate Mailboxes - Create task from collection, schedule task start time
- Migrate OneDrive - Create task, filter by size, schedule task start time
- Monitor Tasks - Return status and details for In Progress tasks
- Auto Start Tasks - Auto-start tasks, limit number of concurrent parallel tasks
Discover Accounts - Create task, start task, monitor task status
This example demonstrates how to create a task to discover all accounts, start the task and monitor the status of the task until it is no longer In Progress.
# Discover objects in Accounts Project #
#########################################
$SleepMinute = 1 # Defines the wait time in minutes between querying the task status
$TaskName = "Discover All Objects"
# Defines the tasks settings
$ACCDiscoverParam = @{Name = $Taskname
DiscoverUsingCSV = $false
FilePath = $null
DiscoverUsingGroups = $false
DiscoveryGroupsFilePath = $null
CreateApplicationAccessPolicy = $false
NotifyOnTaskCompletion = $true
NotifyOnlyOnTaskFailure = $false
NotificationRecipientEmail = "example@domain.com"
ScheduledStartTime = $null
}
# Create the task
$Task = New-OdmDiscoveryTask @ACCDiscoverParam
# Run the task
Start-OdmTask $Task
# Monitor task until no longer In Progress
Do {
Clear-Host
$Running = Get-OdmTask -All -TaskId $Task.Id
$Running | Sort-Object Name | Select-Object Name, Progress, Status | Format-Table *
If ($Running.Status -eq "In Progress") { Start-Sleep ($SleepMinute * 60) }
}While ($Running.Status -eq "In Progress")
#########################################
Migrate Accounts - Create multiple tasks with a defined number of objects
This example demonstrates how to create multiple tasks with the defined number of objects. For example, if you need to migrate 2000 accounts, you can split the migration into 10 tasks with 200 accounts each. Note: This example creates the tasks, but does not run them.
# Create task(s) for migrating user accounts #
#############################################
# The below script will create tasks based on the setting in NumberOfObjects variable.
# Using Type to filter for User objects only.
$TaskName = "Migrate User Accounts"
$NumberOfObjects = 50 # Defines the number of accounts added to a single task
# Download every object from project
$AllObjects = Get-OdmObject -All
Write-Host "All Objects count:"$AllObjects.Count
# Filter for objects where the Type is User
$Objects = $AllObjects | Where-Object { $_.Type -eq "User" }
Write-Host "Available Objects to create task count:"$Objects.Count
$SegmentCount = 1; $SegmentStart = 0
# Calculate how many tasks will be created
$WillCreate = [math]::ceiling($Objects.Count / $NumberOfObjects)
Do {
$Objects2Add = $Objects | Select-Object -Skip $SegmentStart -First $NumberOfObjects
$CurrTaskName = ($TaskName + " " + $SegmentCount + " / " + $WillCreate)
Write-Host $SegmentCount" / "$WillCreate
# Defines the tasks settings
$ACCMigParam = @{Name = $CurrTaskName
TargetUpnSuffix = $null
CustomForwardingDomain = $null
SendInvitation = $true
InviteRedirectUrl = $null
NotifyOnTaskCompletion = $true
NotifyOnlyOnTaskFailure = $false
NotificationRecipientEmail = "example@domain.com"
ScheduledStartTime = $null
}
# Create task
$CurrTask = New-OdmMigrationTask @ACCMigParam
# Adding the defined number of accounts to the task
$CurrTask | Add-OdmObject -object $Objects2Add
$SegmentStart = $SegmentStart + $NumberOfObjects
$SegmentCount = $SegmentCount + 1
}While ($Objects.Count -gt $SegmentStart)
#########################
Migrate Mailboxes - Create task from collection, schedule task start time
This example script demonstrates how to create a task from a collection and schedule the task to start after a defined number of minutes.
# Create task for Migrating mailbox(es) from a Collection #
#######################################################
# Create and start a mailbox migration task based on Collection members and schedule the start
$CollectionName = "Example" # Defines the name of Collection
$TaskName = "MBX Migration of " + $CollectionName + " Collection"
$ScheduleFromNowMinutes = 60 # Defines the task start delay from current time
# Get collection
$Coll = Get-OdmCollection -WildcardFilter @{name = $CollectionName }
# Get the mailboxes from collection
$Objects = Get-OdmCollection -WildcardFilter @{name = $CollectionName } | Get-OdmObject -All
Write-Host "Object(s) in Collection:"$Objects.Count
# Options to migrate
$MBXMigParam = @{ Name = $TaskName
MigrateFromArchive = $false
MigrateToArchive = $false
MigrateMail = $true
MigrateCalendar = $true
MigrateContacts = $true
MigrateTasks = $true
MigrateRules = $true
MigrateDelegates = $true
MigrateRecoverableItems = $true
EnableAutomapping = $false
MigrateFolderPermissions = $true
MigrateAutoReplyState = $true
SkipO365LicenseAssignment = $true
# O365LicenseToAssign = $null
O365LicenseAssignmentType = "Keep"
MigrateMailFrom = $null
MigrateMailUntil = $null
# ExcludeDeletedItems = $false
# ExcludeJunkEmail = $false
# ExcludeDrafts = $false
# ExcludeConversationHistory = $false
# ExcludeSentItems = $false
# ExcludeInbox = $false
# ExcludeMailFolders = $false
# IncludeInbox = $true
# IncludeSentItems = $true
# IncludeDrafts = $true
# IncludeDeletedItems = $true
# IncludeMailFolders = $true
MailForwarding = "Ignore"
SwitchDirection = "SourceToTarget"
TargetForwardingDomain = $null
AllowFolderMapping = $False
InboxMappingFolderName = $null
DeletedMappingFolderName = $null
ArchiveMappingFolderName = $null
SentItemsMappingFolderName = $null
MigrateLitigationHoldSettings = $true
MigrateToCustomFolder = $false
CustomFolderName = ""
DisableReporting = $false
ResetMigration = $false
NotifyOnTaskCompletion = $false
NotifyOnlyOnTaskFailure = $false
NotificationRecipientEmail = $null
# OverrideUsageLocation = $false
# UsageLocation = "NL"
ScheduledStartTime = (Get-Date).AddMinutes($ScheduleFromNowMinutes)
}
# Create the task
$CurrTask = New-OdmMailMigrationTask @MBXMigParam
# Add the mailboxes to the task
$CurrTask | Add-OdmObject -object $Objects
# Add the task to the collection; otherwise the task is not displayed when the collection is selected and you navigate to Tasks
Add-OdmTask -Tasks $CurrTask -To $Coll
#######################
Migrate OneDrive - Create task, filter by size, schedule task start time
This example script demonstrates how to create a migration task for OneDrives sized between 1 GB and 10 GB that have not previously been migrated and schedule the task to start at a specific date and time.
# OneDrive Migration #
#######################
# This example creates OneDrive migration task for OneDrives sized between 1 GB and 10 GB which have not been previously migrated
# Start the task at specific scheduled time "01/23/2024 1:30 PM"
$TaskName = "OD Migration"
$MinSizeGB = 1
$MaxSizeGB = 10
$ScheduleTime = "01/23/2024 1:30 PM" # "MM/DD/YYYY HH:MM" - 24 hour, "MM/DD/YYYY HH:MM AM/PM" - 12 hour
# Get every item
$AllObjects = Get-OdmObject -All
Write-Host "All Objects count:"$AllObjects.Count
# Filter for New OneDrives only
$NewObjects = $AllObjects | Where-Object { $_.OneDriveMigrationState -eq "Discovered" } # Discovered the status for New OneDrives
Write-Host "New OneDrives count:"$NewObjects.Count
# Filter minimum size
$MinObjects = $NewObjects | Where-Object { $_.OneDriveSourceTotalSize -gt ($MinSizeGB * 1024 * 1024 * 1024) }
Write-Host ("OneDrives above " + $MinSizeGB + " GB count: " + $MinObjects.Count)
# Filter maximum size
$MaxObjects = $MinObjects | Where-Object { $_.OneDriveSourceTotalSize -lt ($MaxSizeGB * 1024 * 1024 * 1024) }
Write-Host ("OneDrives between " + $MinSizeGB + " GB and " + $MaxSizeGB + " GB count: " + $MaxObjects.Count)
$Objects = $MaxObjects
# Migration task options
$ODMigParam = @{ Name = $TaskName
MigrationAction = "Skip" # KeepBoth Overwrite
DestinationFolderPath = $null
TaskPriority = "High" # Highest Low Lowest Medium
FileVersions = "All" # Latest LatestAndPrevious MoreVersions
# FileVersionsMaxTotalCount = 0
# FileVersionsPriority = "Latest" # LatestPerDay
FileVersionMaxSize = 512
Author = "TargetAccount" # SystemAccount
PermissionBehaviour = "All" # MigratedContentOnly NoPermission
PermissionsInRerun = $True
MigrateLinkPermission = $True
O365LicenseToAssign = $False
O365LicenseAssignmentType = "Keep" # Replace
FilterItems = "AllItems" # ItemsToExclude ItemsToInclude
# ExcludeFolders = $null
# ExcludeFileTypes = $null
# ExcludeCreatedBefore = $null
# ExcludeModifiedAfter = $null
# ExcludeBiggerThan = $null
# IncludeFolders = $null
# IncludeFileTypes = $null
# IncludeCreatedBefore = $null
# IncludeModifiedAfter = $null
# IncludeBiggerThan = $null
RerunIfMissingItems = $True
EnableReporting = $True
# OverrideUsageLocation = $False
# UsageLocation = "NL"
ScheduledStartTime = $ScheduleTime
}
# Create task
$CurrTask = New-OdmOneDriveMigrationTask @ODMigParam
# Add OneDrives to task
$CurrTask | Add-OdmObject -object $Objects
#######################
Monitor Tasks - Return status and details for In Progress tasks
This example script demonstrates how to monitor running tasks and return detailed info, utilizing filters such as Wildcardfilter, tasktype filters, and Get-OdmEvent filters.
# Monitor In Progress tasks #
#############################
# Define the task type to monitor or set to ALL to monitor every In Progress task
$TaskType = "All" # use ALL to monitor every running task, Types for example, "Mail Migration", "OneDrive Migration"
$SleepMinute = 5 # Wait time in minutes before getting task info as it’s looped
Do {
# Check the tasks to monitor
If ($TaskType -eq "All") {
$MonTasks = Get-OdmTask -All | Where-Object { $_.Status -eq "In Progress" }
}
else {
$MonTasks = Get-OdmTask -All -Type $TaskType | Where-Object { $_.Status -eq "In Progress" }
}
# Check if any running tasks; if not, exit
If ($MonTasks.Count -lt 1) {
Write-Host "No In Progress tasks to monitor"
Break
}
# Get details of each running task
Foreach ($MTask in $MonTasks) {
# Searching for the first task event, because the task created time and the task real start can be different if the task is scheduled
# You can use Wildcardfilter for a quick search in events on server side
# Message and details (lower case) are available for Get-OdmEvent, see the sample below
$FirstEvent = Get-OdmEvent -All -Filterobject $MTask -WildcardFilter @{message = "Task has been started (*" } | Sort-Object Timestamp | Select-Object -Last 1
# Download the first 1000 errors (by not using -All switch) of the task, using Severity filter
# When not using -All switch, only the first 1000 results are returned
$Errors = Get-OdmEvent -Filterobject $MTask -Severity Error
# If 1000 errors were downloaded, add =< to mark that the count is at least 1000
If ($Errors.Count -eq 1000) {
$Erroutput = [string]$Errors.Count
$Erroutput = $Erroutput + " =<"
}
Else {
$Erroutput = [string]$Errors.Count
}
# Download the first 1000 warnings (by not using -All switch) of the task, using Severity filter
# When not using -All switch, only the first 1000 results are returned
$Warnings = Get-OdmEvent -Filterobject $MTask -Severity Warning
# If 1000 warnings were downloaded, add =< to mark that the count is at least 1000
If ($Warnings.Count -eq 1000) {
$Warnoutput = [string]$Warnings.Count
$Warnoutput = $Warnoutput + " =<"
}
Else {
$Warnoutput = [string]$Warnings.Count
}
# Calculating how long the task ran, based on when the Task actually started
# Need to convert to UTC time, because every timestamp returns in UTC
$TaskDurHours = ((New-TimeSpan -Start $FirstEvent.Timestamp -End (Get-Date).ToUniversalTime()).TotalHours).ToString("N2")
# Adding the collected info to the task properties
Add-Member -InputObject $MTask -MemberType NoteProperty -Name TaskStartUTC -Value $FirstEvent.Timestamp -Force
Add-Member -InputObject $MTask -MemberType NoteProperty -Name TaskDurHours -Value $TaskDurHours -Force
Add-Member -InputObject $MTask -MemberType NoteProperty -Name ErrInTask -Value $Erroutput -Force
Add-Member -InputObject $MTask -MemberType NoteProperty -Name WarnInTask -Value $Warnoutput -Force
}
# Display the taskinformation
Clear-Host
$MonTasks | Sort-Object Name | Select-Object Id, Name, Type, Progress, LastResult, Created, TaskStartUTC, TaskDurHours, ErrInTask, WarnInTask | Format-Table *
# Inform when last query ran
Write-Host ("Last query ran at: " + (Get-Date))
# Wait before getting next task info
Write-Host ("Sleeping for " + $SleepMinute + " Minutes")
Start-Sleep ($SleepMinute * 60)
}While ($True)
####################################
Auto Start Tasks - Auto-start tasks, limit number of concurrent parallel tasks
This example script demonstrates how to automatically start tasks based on how many parallel tasks you want to run for a specific task type.
# Automatically Start New tasks #
#################################
# When New tasks are created (without scheduled start time), this example will start them based on the variables defined
# For example, you created multiple tasks for mailbox migration and wish to run 10 tasks in parallel
$TaskType2Run = "Mail Migration" # Types for example, "Mail Migration", "OneDrive Migration"
$MaxRunningTasks = 10
$SleepMinute = 5 # Wait time before getting task info as it's looped
Do {
# Get the current running task based on the tasktype
$TotalRunnning = Get-OdmTask -All -Type $TaskType2Run | Where-Object { $_.Status -eq "In Progress" }
# Get New tasks based on the tasktype and sort by creation date
$QueuedTask = Get-OdmTask -All -Type $TaskType2Run | Where-Object { $_.Status -eq “New” } | Sort-Object Created
# If no more New tasks, then exit
If ($QueuedTask.Count -eq 0) { Break }
# Display In Progress task info
Clear-Host
$TotalRunnning | Sort-Object Name | Select-Object Id, Name, Type, Progress, LastResult | Format-Table *
# Start next task based on MaxRunningTasks variable
If ($TotalRunnning.Count -lt $MaxRunningTasks) {
Start-OdmTask $QueuedTask[0]
Write-Host "Started task:"($QueuedTask[0].Name)
}
# Display info
Write-Host ("Running tasks count: " + $TotalRunnning.Count)
Write-Host ("Queued tasks count: " + $QueuedTask.Count)
# Inform when last query ran
Write-Host ("Last query ran at: " + (Get-Date))
# Wait before getting the next task info
Write-Host ("Sleeping for " + $SleepMinute + " Minutes")
Start-Sleep ($SleepMinute * 60)
}While ($true)
##################################
Further Information
For more information on this and many other features within On Demand Migration, check out the ODM User Guide Appendix A: Using PowerShell. We welcome your feedback and suggestions below and invite you to visit us at Quest.com.