Skip to main content
<#
.Synopsis
For VB365 will migrate all data from one repository to another, based on the Veeam KB 3067. This version brings some
sanity to the selection of proxies and repos while also providing information on what is to be moved (storage and user counts).
.Notes
Version: 1.0
Author: Jim Jones, @k00laidIT
Modified Date: 5/23/2022

.EXAMPLE
.\iland-kb3067.ps1
#>

Import-Module Veeam.Archiver.PowerShell

#Organization selection
$orgs=Get-vboorganization | Sort-Object Name
for($i=0; $i -lt $orgs.count; $i++){write-host $i. $orgs[$i].name}
$organisationNum = Read-Host "Enter organisation number"
$vboOrg = $orgs[$organisationNum]

$orgjobs = $vboOrg | get-vbojob
[System.Collections.ArrayList]$orgrepos = @()
foreach ($orgjob in $orgjobs) {
$repo = $orgjob.repository
$output = [PSCustomObject]@{
repoName = $repo
}
$orgrepos += $output
}

#Source Repository selection
$sourcerepo = $orgrepos
for($i=0; $i -lt $sourcerepo.count; $i++){write-host $i. $sourcerepo[$i].repoName}
$sourcerepoNum = Read-Host "Enter Source repository number"
$fromRepo = Get-VBORepository -Name $sourcerepo.repoName[$sourcerepoNum]

#Backup proxy selection
$proxies=Get-VBOProxy | Sort-Object Name
for($i=0; $i -lt $proxies.count; $i++){write-host $i. $proxies[$i].hostname}
$proxyNum = Read-Host "Enter proxy number"
#$vboProxyTarget = $proxies[$proxyNum]
$vboProxyTarget = Get-VBOProxy -Id $fromRepo.ProxyID

#Target Repository selection
$targetrepo=Get-VBORepository -Proxy $vbProxyTarget | Sort-Object Name
for($i=0; $i -lt $targetrepo.count; $i++){write-host $i. $targetrepo[$i].name}
$targetrepoNum = Read-Host "Enter Target repository number"
$destinationRepo = $targetrepo[$targetrepoNum]

#Gather Data on storage use prior to move
$usage = Get-VBOUsageData -Repository $fromRepo -Organization $vboOrg

#Limiting migrations sessions to a half of Backup Proxy threads
$jobs_for_move=($vboProxyTarget.ThreadsNumber)/2

#Disabling all jobs for selected organization
$vboJobs = Get-VBOJob -Organization $vboOrg | where-object {$_.Repository -eq $fromRepo.Name}
$vboJobs | ?{$_.IsEnabled} | Disable-VBOJob > $null

#finding all users and migrating them
$users = Get-VBOEntityData -Type User -Repository $fromRepo | Where-Object {$_.Organization.DisplayName -eq $vboOrg.Name}

foreach ($user in $users)
{
Write-Host $user.displayname
Move-VBOEntityData -From $fromRepo -To $destinationRepo -User $user -Mailbox -ArchiveMailbox -OneDrive -Sites -Confirm:$false -RunAsync
while((Get-VBODataManagementSession | ? {$_.Status -eq "Running"}).Count -ge $jobs_for_move){sleep 10}
}

#finding all sites and migrating them
$sites = Get-VBOEntityData -Type Site -Repository $fromRepo | Where-Object {$_.Organization.DisplayName -eq $vboOrg.Name}

foreach ($site in $sites) {
Write-Host $site.title
Move-VBOEntityData -From $fromRepo -To $destinationRepo -Site $site -Confirm:$false -RunAsync
while((Get-VBODataManagementSession | ? {$_.Status -eq "Running"}).Count -ge $jobs_for_move){sleep 10}
}

#finding all groups and migrating them
$groups = Get-VBOEntityData -Type Group -Repository $fromRepo | Where-Object {$_.Organization.DisplayName -eq $vboOrg.Name}

foreach ($group in $groups) {
Write-Host $group.displayname
Move-VBOEntityData -From $fromRepo -To $destinationRepo -Group $group -Mailbox -ArchiveMailbox -OneDrive -Sites -GroupMailbox -GroupSite -Confirm:$false -RunAsync
while((Get-VBODataManagementSession | ? {$_.Status -eq "Running"}).Count -ge $jobs_for_move){sleep 10}
}

#finding all Teams and migrating them
$teams = Get-VBOEntityData -Type Team -Repository $fromRepo | Where-Object {$_.Organization.DisplayName -eq $vboOrg.Name}

foreach ($team in $teams) {
Write-Host $team.displayname
Move-VBOEntityData -From $fromRepo -To $destinationRepo -Team $team -Confirm:$false -RunAsync
while((Get-VBODataManagementSession | ? {$_.Status -eq "Running"}).Count -ge $jobs_for_move){sleep 10}
}


#reconfiguring the job to use new repository and enabling it
foreach ($job in $vboJobs)
{

Set-VBOJob -Job $job -Repository $destinationRepo > $null
Enable-VBOJob -Job $job > $null

}

Write-Host "All migration jobs started. You can check each job state in UI (History->Jobs->Data Management)"
Write-Host ""
Write-Host "Processed Selections"
Write-Host "Organization: $vboOrg.Name ($organisationNum)"
Write-Host "Proxy: $vboProxyTarget ($proxyNum)"
Write-Host "Source Repo: $fromRepo ($sourcerepoNum)"
Write-Host "Destination Repo: $destinationRepo ($targetrepoNum)"
Write-Host ""
Write-Host "Summary of sources:"
Write-Host "Storage use prior to move: $usage"
Write-Host "Users: $users"
Write-Host "Groups: $groups"
Write-Host "Sites: $sites"
Write-Host "Teams: $teams"

& cmd /c pause
exit

 

Thanks for sharing, Jim!

 

As mentioned in the script synopsis, this is an alternative script to the one provided in Veeam KB3067.

 

@k00laidIT Can you please confirm the version of Veeam Backup for Microsoft 365 this script was tested with?

 


Hey @Chris.Arceneaux this was tested with the latest build of v5 but should work just as well with v6. I think the Get-VBOUsageData cmdlet came in v5 so that would be the earliest version supported.


Nice script Jim. Will take a look at this one for sure to help move data.


Hi all, wanted to give a heads up that I’ve updated this and moved it to github. The latest version moves the logic to per job rather than per repository. https://github.com/k00laidIT/Veeam/blob/master/kb3067.ps1


Hi k00laidIT,

Thanks for sharing this script.

I was wondering if you could help me out trying to automate this process a little bit more. I’ve been using the original script several times with success. But I need to migrate several hundreds organisations on different VBM365 machines, 5 to be exact.

Because those machines have multiple backup proxies (ranges from 10 to 15), I was thinking of automating this process but limiting it to a specific proxy at a time. But although I understand what the script does when I’m reading it, I’m not great at creating one. So I’m hoping you or someone else can help me get started.

Thanks!


Comment