The MigrateDatasourceDataFromDPM script can have many formats one of which is to migrate a source disk to a target disk or array of disks. How much space do you need to migrate? You need at least as much as the source disk size of course but what if 1 or more volumes span to another disk? Take the sample below; you have Disk-1 and Disk-2 (both 750GB) with 4 volumes, note that volume V3 (green) spans Disk-1 and Disk-2.
If you want to migrate Disk-1 you have to migrate V1, V2 and all of V3 which totals to more than the size of Disk-1. Given possible spanning scenarios this is more challenging than you might expect. If all involved volumes are replica volumes it is fairly straight forward (“Get-DPMdisk” gives you all replicas) but if 1 or more are recovery point volumes it becomes a different ballgame. The script below figures that out and the synopsis explains how it does that. Note that the script is not tested with colocated datasources.
#begin script
#--------------
param()
# SYNOPSIS
# We first get lists we need to select from and reference against
# Feed all DPM disks to GetMigSizeByDisk()
# GetMigSizebyDisk()
# walk all PGmembers on given disk
# need to check if recovery point volumes are on same disk (PGmember[] are only replicas)
# get recovery point volume from volume-list by VolumesetId (from member) and size not equal to replica
# get recovery point extents from extents-list and see if any DiskId matches current disk identifier
# when it does, we need to account for replica + shadowcopyarea sizes else just replica
# next member until all members on disk done
# return total size
function GetMigSizeByDisk {
param($disk, $extents, $dss, $Vols )
[int64]$size = 0
#For all data source members on current disk
foreach ($m in $disk.PgMember) {
#we use ds to take sizes from rather than selects and sum proper extents
$ds = $dss | ? {$m.DatasourceId -eq $_.id}
#isolate the recovery pount volume and extents by size (we assume not same as replica size)
$expr = "VolumeSetId='{0}' and VolumeSize <> '{1}'" -f $m.VolumeSetID, $ds.ReplicaSize
$RecoVolume = @($Vols.Select("$expr"))
$RecoExpr = "Guidname='{0}'" -f $RecoVolume[0].GuidName
$RecoExtents = @($extents.Select("$RecoExpr"))
$MatchingDisks = @($RecoExtents | ? {$_.DiskId.Guid -eq $disk.Identifier})
if ($MatchingDisks.Count > 0) {
# At least 1 recovery point volume extent lives on same disk as replica
# We must now add shadowcopy size to total
$size += $ds.ReplicaSize + $ds.ShadowCopyAreaSize #$includes all extents whereever they are
}
else {
# Count replica size only
$size += $ds.ReplicaSize
}
}
return $size
}
$version = "v1.0"
$global:MB = 1024 * 1024
$global:GB = $MB * 1024
$global:dpmservername = @(hostname)
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") >> $null
#get sqlserver and instane from registry
$reg = Get-ChildItem "HKLM:\Software\Microsoft\Microsoft Data Protection Manager"
$sqlservername = $reg.GetValue(5).getvalue("sqlserver")
$instance = $reg.GetValue(5).getvalue("instancename")
$servername = "$sqlservername\$instance"
$srvr = new-object ("Microsoft.SqlServer.Management.Smo.Server") $servername
$db = $srvr.Databases["DPMDB"]
#get disks, volume, extents and datasource lists once
$VolTable = $db.ExecutewithResults(" select * from tbl_SPM_Volume where VolumeSetID is not null ").Tables[0]
$extentlist = $db.ExecutewithResults(" select * from tbl_SPM_Extent").Tables[0]
$disks = @(Get-DPMDisk "$dpmservername" ) | sort -Property NtDiskId
$datasourcelist = Get-Datasource "$dpmservername"
#Now go to work
Write-Host ("`nMigrateSpaceNeeded $version evaluating {0} DPM disks...`n" -f $disks.count) -ForegroundColor yellow
foreach ($d in $disks) {
$MigSize = ( (GetMigSizeByDisk $d $extentlist $datasourcelist $Voltable)/ $GB).Tostring("N2")
Write-Host (" ==> to migrate Disk-{0} you need $MigSize GB on the destination" -f $d.NtDiskID) -ForegroundColor cyan
}
Write-Host "`nDone!`n" -ForegroundColor white
#--------------
#end script