DPM 2010 Deleting Old Restore Points


Ok, so for the most part this happens automagically and you won’t have to mess with it at all. However, for some reason I found that a few recovery points I had manually created with Microsoft Support while troubleshooting an issue were not going away. How do I know? Here’s the script for determining if you have expired but not pruned recovery points (source):

#displays all RP for data sources and shows which RP’s would be deleted by the regular pruneshadowcopies.ps1
# Outputs to a logfile: C:\Program Files\Microsoft DPM\DPM\bin\SHOW-PRUNESHADOWCOPIES.LOG

#Author : Mike J
#Date : 02/24/2009
$version=”V1.0″

$date=get-date
$logfile=”SHOW-PRUNESHADOWCOPIES.LOG.txt”

function GetDistinctDays([Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.ProtectionGroup] $group,
[Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.Datasource] $ds)
{
if($group.ProtectionType -eq [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.ProtectionType]::DiskToTape)
{
return 0
}
$scheduleList = get-policyschedule -ProtectionGroup $group -ShortTerm
if($ds -is [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.FileSystem.FsDataSource])
{
$jobType = [Microsoft.Internal.EnterpriseStorage.Dls.Intent.JobTypeType]::ShadowCopy
}
else
{
$jobType = [Microsoft.Internal.EnterpriseStorage.Dls.Intent.JobTypeType]::FullReplicationForApplication
if($ds.ProtectionType -eq [Microsoft.Internal.EnterpriseStorage.Dls.Intent.ReplicaProtectionType]::ProtectFromDPM)
{
return 2
}
}
write-host “Look for jobType $jobType”

foreach($schedule in $scheduleList)
{
write-host(“schedule jobType {0}” -f $schedule.JobType)
if($schedule.JobType -eq $jobType)
{
return [Math]::Ceiling(($schedule.WeekDays.Length * $ds.RecoveryRangeinDays) / 7)
}
}

return 0
}

function IsShadowCopyExternal($id)
{
$result = $false;

$ctx = New-Object -Typename Microsoft.Internal.EnterpriseStorage.Dls.DB.SqlContext
$ctx.Open()

$cmd = $ctx.CreateCommand()
$cmd.CommandText = “select COUNT(*) from tbl_RM_ShadowCopy where shadowcopyid = ‘$id’”
write-host $cmd.CommandText
$countObj = $cmd.ExecuteScalar()
write-host $countObj
if ($countObj -eq 0)
{
$result = $true
}
$cmd.Dispose()
$ctx.Close()

return $result
}

function IsShadowCopyInUse($id)
{
$result = $true;

$ctx = New-Object -Typename Microsoft.Internal.EnterpriseStorage.Dls.DB.SqlContext
$ctx.Open()

$cmd = $ctx.CreateCommand()
$cmd.CommandText = “select ArchiveTaskId, RecoveryJobId from tbl_RM_ShadowCopy where ShadowCopyId = ‘$id’”
write-host $cmd.CommandText
$reader = $cmd.ExecuteReader()
while($reader.Read())
{
if ($reader.IsDBNull(0) -and $reader.IsDBNull(1))
{
$result = $false
}
}
$cmd.Dispose()
$ctx.Close()

return $result
}

“**********************************” > $logfile
“Version $version” >> $logfile
get-date >> $logfile

$dpmservername = &”hostname”

$dpmsrv = connect-dpmserver $dpmservername

if (!$dpmsrv)
{
write-host “Unable to connect to $dpmservername”
exit 1
}

write-host $dpmservername
“Selected DPM server = $DPMservername” >> $logfile
$pgList = get-protectiongroup $dpmservername
if (!$pgList)
{
write-host “No PGs found”
disconnect-dpmserver $dpmservername
exit 2
}

write-host(“Number of ProtectionGroups = {0}” -f $pgList.Length)
$replicaList = @{}
$latestScDateList = @{}

foreach($pg in $pgList)
{
$dslist = get-datasource $pg
if ($dslist.length -gt 0)
{
write-host(“Number of datasources in this PG = {0}” -f $dslist.length)
(“Number of datasources in this PG = {0}” -f $dslist.length) >> $logfile
}
Foreach ($ds in $dslist)
{
write-host(“DS NAME= $ds”)
(“DS NAME= $ds”) >>$logfile
}
foreach ($ds in $dslist)
{
$rplist = get-recoverypoint $ds | where { $_.DataLocation -eq ‘Disk’ }
write-host(“Number of recovery points for $ds {0}” -f $rplist.length)
(“Number of recovery points for $ds {0}” -f $rplist.length) >>$logfile
$countDistinctDays = GetDistinctDays $pg $ds
write-host(“Number of days with fulls = $countDistinctDays”)
(“Number of days with fulls = $countDistinctDays”) >>$logfile
if($countDistinctDays -eq 0)
{
write-host “D2T PG. No recovery points to delete”
“D2T PG. No recovery points to delete” >>$logfile
continue;
}
$replicaList[$ds.ReplicaPath] = $ds.RecoveryRangeinDays
$latestScDateList[$ds.ReplicaPath] = new-object DateTime 0,0
$lastDayOfRetentionRange = ([DateTime]::UtcNow).AddDays($ds.RecoveryRangeinDays * -1);
write-host(“Distinct days to count = {0}. LastDayOfRetentionRange = {1} ” -f $countDistinctDays, $lastDayOfRetentionRange)
(“Distinct days to count = {0}. LastDayOfRetentionRange = {1} ” -f $countDistinctDays, $lastDayOfRetentionRange) >>$logfile
$distinctDays = 0;
$lastDistinctDay = (get-Date).Date
$numberOfRecoveryPointsDeleted = 0

if ($rplist)
{
foreach ($rp in ($rplist | sort-object -property UtcRepresentedPointInTime -descending))
{
if ($rp)
{
if ($rp.UtcRepresentedPointInTime.Date -lt $lastDistinctDay)
{
$distinctDays += 1
$lastDistinctDay = $rp.UtcRepresentedPointInTime.Date
}
write-host(” $ds”)
(” $ds”) >>$logfile
write-host(” Recovery Point #$distinctdays RPtime={0}” -f $rp.UtcRepresentedPointInTime)
(” Recovery Point #$distinctdays RPtime={0}” -f $rp.UtcRepresentedPointInTime) >>$logfile
if (($distinctDays -gt $countDistinctDays) -and ($rp.UtcRepresentedPointInTime -lt $lastDayOfRetentionRange))
{
write-host (“Recovery Point would be deleted ! – RPtime={0}” -f $rp.UtcRepresentedPointInTime) -foregroundcolor red
(“Recovery Point would be deleted ! – RPtime={0} <<<<<<>$logfile
#remove-recoverypoint $rp -ForceDeletion -confirm:$true | out-null
$numberOfRecoveryPointsDeleted += 1
}
else
{
write-host ” Recovery point not expired yet”
” Recovery point not yet expired” >>$logfile
}
}
else
{
write-host “Got a NULL rp”
“Got a NULL rp” >>$logfile
}
}

write-host “Number of RPs that would be deleted = $numberOfRecoveryPointsDeleted”
“Number of RPs that would be deleted = $numberOfRecoveryPointsDeleted” >>$logfile
}
}
}

disconnect-dpmserver $dpmservername
write-host “Exiting from script”

exit

Now, you could run the prune script in the DPB/bin folder but for me that didn’t resolve the recovery points that were sitting out there and long past their expiration date. So, here’s the script which does that for you (source):
#############################################
# Script will delete ALL recovery points from all protection groups over X days old.
# Takes server name and days as input arguements:
# RemoveRecoveryPoints.ps1 "DPMServername" Days
#############################################

param([string] $dpmname, [int32] $days )

function Usage()

{
write-host
write-host “Usage::”
write-host “RemoveRecoveryPoints.ps1 “DPMServername” Days(In int)”
write-host
}

if((“-?”,”-help”) -contains $args[0])
{
Usage
exit 0
}

if(!$dpmname)
{
$dpmname = read-host “DPMServerName:”
}

if(!$days)
{
$days = read-host “Number of Days”
}

$pgList = Get-ProtectionGroup $dpmname

Foreach($pg in $pgList)
{
$Name = $pg.FriendlyName
Write-Host “Getting Data Source list for PG $Name…”
$dsList = Get-Datasource $pg

Foreach($ds in $dsList)
{
$Name = $ds.Name
Write-Host “Getting Recovery point list for Data-Source $Name …”
$rpList = Get-RecoveryPoint $ds

Foreach($rp in $rpList)
{
$date = Get-Date
$datediff = $date – $rp.RepresentedPointInTime
$rpDays = $datediff.Days
Write-Host “Recovery Point is $rpDays days old ”

if($rpDays -ge $days)
{
Write-Host “Removing Recovery Point older than $rpDays”
Remove-RecoveryPoint -RecoveryPoint $rp
}

}

}

}

Don’t worry about running the script and having it remove data you don’t want it to. You will be prompted for each and asked if you want to remove them. Expect some errors as the script runs. What I did was run the script, get some errors, run it a second time get some more errors, then on the third run I had no points left to remove.

It’s not a perfect solution, but it works.

Advertisements

4 thoughts on “DPM 2010 Deleting Old Restore Points

  1. Brandon, you save my day! Thanks alot for this post.. with this solution i reallocated the full storage pool from a MBR Disk.. to a GPT Disk. After the retention days, my dpm havn’t ereased the old disk.. thanks to this post, with the last script i resolved this issue manually after hours of testing. now all is working fine!!

    Greets Mike

  2. I know this is an old thread, but I’m wondering if I can get a copy of the original pruneshadowcopies.ps1. I accidentally saved the show-pruneshadowcopies.ps1 over the original file!

  3. Hi Brandon,
    We do have the same problem, but unfortunately can not solve it vith your script. We always get a failure: “Remove-RecoverPoint : Length cannot be less than zero” and the recovery point is not getting reoved. Do you have any idea?

Comments are closed.