There are times when DPM fails to remove expired recovery points. PruneVSS.ps1 can remove excessive disk (i.e., not tape) based recovery points.
#Author : Ruud Baars
#Date : 11/09/2008
#Edited : 11/15/2012 By: Wilson S.
#edited : 11:27:2012 By: Mike J.
#Edited : 3/25/2014 By: Steven J.
# $VerbosePreference = "Continue"
# NOTE: Update script to only remove recovery points on Disk. Recovery points removed will be from the oldest one up to the date
# entered by the user while the script is running
#deletes all recovery points before 'now' on selected data source.
$version="V4.7"
$ErrorActionPreference = "silentlycontinue"
add-pssnapin sqlservercmdletsnapin100
Add-PSSnapin -Name Microsoft.DataProtectionManager.PowerShell
#display RP's to delete and ask to continue.
#Check & wait data source to be idle else removal may fail (in Mojito filter on 'intent' to see the error)
#Fixed prune default and logfile name and some logging lines (concatenate question + answer)
#Check dependent recovery points do not pass BEFORE date and adjust selection to not select those ($reselect)
#--- Fixed reselect logic to keep adjusting reselect for as long as older than BEFORE date
#--- Fixed post removal rechecking logic to match what is done so far (was still geared to old logic)
#--- Modified to remove making RP and ask for pruning, fixed logic for removal rechecking logic
$MB=1024*1024
$logfile="DPMdeleteRP.LOG"
$wait=10
#seconds
$confirmpreference = "None"
function Show_help
{
cls
$l="=" * 79
write-host $l -foregroundcolor magenta
write-host -nonewline "`t<<<" -foregroundcolor white
write-host -nonewline " DANGEROUS :: MAY DELETE MANY RECOVERY POINTS " -foregroundcolor red
write-host ">>>" -foregroundcolor white
write-host $l -foregroundcolor magenta
write-host "Version: $version" -foregroundcolor cyan
write-host "A: User Selects data source to remove recovery points for" -foregroundcolor green
write-host "B: User enters date / time (using 24hr clock) to Delete recovery points" -foregroundcolor green
write-host "C: User Confirms deletion after list of recovery points to be deleted is displayed." -foregroundcolor green
write-host "Appending to log file $logfile`n" -foregroundcolor white
write-host "User Accepts all responsibilities by entering a data source or just pressing [Enter] " -foregroundcolor white -backgroundcolor blue
}
"**********************************" >> $logfile
"Version $version" >> $logfile
get-date >> $logfile
show_help
$DPMservername=&"hostname"
"Selected DPM server = $DPMservername" >> $logfile
write-host "`nConnnecting to DPM server retrieving data source list...`n" -foregroundcolor green
$pglist = @(Get-ProtectionGroup $DPMservername) # WILSON - Created PGlist as array in case we have a single protection group.
$ds=@()
$tapes=$null
$count = 0
$dscount = 0
foreach ($count in 0..($pglist.count - 1))
{
# write-host $pglist[$count].friendlyname
$ds += @(get-datasource $pglist[$count]) # WILSON - Created DS as array in case we have a single protection group.
# write-host $ds
# write-host $count -foreground yellow
}
if ( Get-Datasource $DPMservername -inactive) {$ds += Get-Datasource $DPMservername -inactive}
$i=0
write-host "Index Protection Group Computer Path"
write-host "---------------------------------------------------------------------------------"
foreach ($l in $ds)
{
"[{0,3}] {1,-20} {2,-20} {3}" -f $i, $l.ProtectionGroupName, $l.psinfo.netbiosname, $l.logicalpath
$i++
}
$DSname=read-host "`nEnter a data source index from list above - Note co-located datasources on same replica will be effected"
if (!$DSname)
{
write-host "No datasource selected `n" -foregroundcolor yellow
"Aborted on Datasource name" >> $logfile
exit 0
}
$DSselected=$ds[$DSname]
if (!$DSselected)
{
write-host "No datasource selected `n" -foregroundcolor yellow
"Aborted on Datasource name" >> $logfile
exit 0
}
$rp=get-recoverypoint $DS[$dsname]
$rp
# $DoTape=read-host "`nDo you want to remove when recovery points are on tape ? [y/N]"
# "Remove tape recovery point = $DoTape" >> $logfile
write-host "`nCollecting recoverypoint information for datasource $DSselected.name" -foregroundcolor green
if ($DSselected.ShadowCopyUsedspace -gt 0)
{
while ($DSSelected.TotalRecoveryPoints -eq 0)
{ # "still 0"
}
#this is on disk
$oldShadowUsage=[math]::round($DSselected.ShadowCopyUsedspace/$MB,1)
$line=("Total recoverypoint usage {0} MB on DISK in {1} recovery points" -f $oldShadowUsage ,$DSselected.TotalRecoveryPoints )
$line >> $logfile
write-host $line`n -foregroundcolor white
}
#this is on tape
#$trptot=0
#$tp= Get-RecoveryPoint($dsselected) | where {($_.Datalocation -eq "Media")}
#foreach ($trp in $tp) {$trptot += $trp.size }
#if ($trptot -gt 0 )
#{
# $line=("Total recoverypoint usage {0} MB on TAPE in {1} recovery points" -f ($trptot/$MB) ,$DSselected.TotalRecoveryPoints )
# $line >> $logfile
# write-host $line`n -foregroundcolor white
#}
[datetime]$afterdate="1/1/1980"
#$answer=read-host "`nDo you want to delete recovery points from the beginning [Y/n]"
#if ($answer -eq "n" )
#{
# [datetime]$afterdate=read-host "Delete recovery points AFTER date [MM/DD/YYYY hh:mm]"
#}
[datetime]$enddate=read-host "Delete ALL Disk based recovery points BEFORE and Including date/time entered [MM/DD/YYYY hh:mm]"
"Deleting recovery points until $enddate" >>$logfile
write-host "Deleting recovery points until and $enddate" -foregroundcolor yellow
$rp=get-recoverypoint $DSselected
if ($DoTape -ne "y" )
{
$RPselected=$rp | where {($_.representedpointintime -le $enddate) -and ($_.Isincremental -eq $FALSE)-and ($_.DataLocation -eq "Disk")}
}
else
{
$RPselected=$rp | where {($_.representedpointintime -le $enddate) -and ($_.Isincremental -eq $FALSE)}
}
if (!$RPselected)
{
write-host "No recovery points found!" -foregroundcolor yellow
"No recovery points found, aborting...!" >> $logfile
exit 0
}
$reselect = $enddate
$adjustflag = $false
foreach ($onerp in $RPselected)
{
$rtime=[string]$onerp.representedpointintime
$rsize=[math]::round(($onerp.size/$MB),1)
$line= "Found {0}, RP size= {1} MB (If 0 MB, co-located datasource cannot be computed), Incremental={2} "-f $rtime, $rsize,$onerp.Isincremental
$line >> $logfile
write-host "$line" -foregroundcolor yellow
#
#Get dependent rp's for data source
#
$allRPtbd=$DSselected.GetAllRecoveryPointsToBeDeleted($onerp)
foreach ($oneDrp in $allRPtbd)
{
if ($oneDrp.IsIncremental -eq $FALSE) {continue}
$rtime=[string]$oneDrp.representedpointintime
$rsize=[math]::round(($oneDrp.size/$MB),1)
$line= ("`t...is dependancy for {0} size {1} `tIncremental={2}" -f $rtime, $rsize, $oneDrp.Isincremental)
$line >> $logfile
if ($oneDrp.representedpointintime -ge $enddate)
{
#stick to latest full ($oneDrp = dependents, $onerp = full)
$adjustflag = $true
$reselect = $onerp.representedpointintime
"<< Dependents newer than BEFORE date >>>" >> $logfile
Write-Host -nonewline "`t <<< later than BEFORE date >>>" -foregroundcolor white -backgroundcolor red
write-host "$line" -foregroundcolor yellow
}
else
{
#Ok, include current latest incremental
$reselect = $oneDrp.representedpointintime
write-host "$line" -foregroundcolor yellow
}
}
}
if ($reselect -lt $oneDrp.representedpointintime)
{
#we adjusted further backward than latest incremental within selection
$reselect = $rtime
$line = "Adjusted BEFORE date to be $reselect to include dependents to $enddate"
$line >> $logfile
Write-Host $line -foregroundcolor white -backgroundcolor blue
}
$line="`n<<< SECOND TO LAST CHANCE TO ABORT - ONE MORE PROMPT TO CONFIRM. >>>"
write-host $line -foregroundcolor white -backgroundcolor blue
$line >> $logfile
$line="Above recovery points within adjusted range will be permanently deleted !!!"
write-host $line -foregroundcolor red
$line >> $logfile
$line="These RP's include dependent recovery points and may contain co-located datasource(s)"
write-host $line -foregroundcolor red
$line >> $logfile
$line="Data source activity = " + $DSselected.Activity
$line >> $logfile
write-host $line -foregroundcolor white
$DoDelete=""
while (($DoDelete -ne "N" ) -and ($DoDelete -ne "Y"))
{
$line="Continue with deletion (must answer) Y/N? "
write-host $line -foregroundcolor white
$DoDelete=read-host
$line = $line + $DoDelete
$line >> $logfile
}
if (!$DSselected.Activity -eq "Idle")
{
$line="Data source not idle, do you want to wait Y/N ? "
write-host $line -foregroundcolor yellow
$Y=read-host
$line = $line + $Y
$line >> $logfile
if ($Y -ieq "Y")
{
Write-Host "Waiting for data source to become idle..." -foregroundcolor green
while ($DSselected.Activity -ne "Idle")
{
("Waiting {0} seconds" -f $wait) >>$logfile
Write-Host -NoNewline "..." -ForegroundColor blue
start-sleep -s $wait
}
}
}
if ($DoDelete -eq "Y")
{
foreach ($onerp in $RPselected)
{
#reselect is adjusted to safe range relative to what was requested
#--- if adjustflag not set then all up to including else only older because we must keep the full
if ((($onerp.representedpointintime -le $reselect) -and ($adjustflag -eq $false)) -or ($onerp.representedpointintime -lt $reselect))
{
$rtime=[string]$onerp.representedpointintime
write-host `n$line -foregroundcolor red
$line >>$logfile
if (($onerp ) -and ($onerp.IsIncremental -eq $FALSE)) { remove-recoverypoint -RecoveryPoint $onerp -recurse -force -confirm:$False} # >> $logfile}
$line =("---`nDeleting recoverypoint -> " + $rtime)
$line >>$logfile
}
}
}
"All Done!" >> $logfile
write-host "`nAll Done!`n`n" -foregroundcolor white
$line="Do you want to View DPMdeleteRP.LOG file Y/N ? "
write-host $line -foregroundcolor white
$Y=read-host
$line = $line + $Y
$line >> $logfile
if ($Y -ieq "Y")
{
Notepad DPMdeleteRP.LOG}
Hello Steven,
ReplyDeleteI believe this script is what I'm looking for as I moved our Exchange databases to new underlying storage and didn't copy the data in the System Volume Information folder, therefore now I have stranded VSS snapshots in DPM that will not purge.
I tried running the script and get the following error:
PS C:\users\rparlee\desktop> .\prunevss.ps1
Unexpected token 'Version $version' in expression or statement.
At C:\users\rparlee\desktop\prunevss.ps1:23 char:958
+ function Show_help { cls $l="=" * 79 write-host $l -foregroundcolor magenta w
rite-host -nonewline "`t<<<" -foregroundcolor white write-host -nonewline " DAN
GEROUS :: MAY DELETE MANY RECOVERY POINTS " -foregroundcolor red write-host ">>
>" -foregroundcolor white write-host $l -foregroundcolor magenta write-host "Ve
rsion: $version" -foregroundcolor cyan write-host "A: User Selects data source
to remove recovery points for" -foregroundcolor green write-host "B: User enter
and it goes on to list out the entire rest of the script.
I copied the code from your post, pasted into notepad and saved is a prunevss.ps1 and executed it.
I'm running DPM 2010 with all the latest updates/rollups.
Thank you,
Ryan
I think copying and pasting loses a lot of the original line breaks - any chance of the original file?
ReplyDelete