The Official System Center Data Protection Manager Team Blog

Your official source for all the latest news and tech tips for System Center Data Protection Manager.

Replacing tape drive assignments

Imagine you got a replacement library for a broken one, or one with larger capacity to partition or share between DPM servers but anyway shows up as another tape drive. For discussion sake we say everything is fine with the new library but you now got all those protection groups on one or more DPM servers pointing to the old library!? You need to re-assign those; protection tab, “Modify protection group” after couple of “Next” to select the new library and commit the change to the group. How many groups and servers did you have? Right, the script below comes to some rescue.

The “DPMswitchTape” script facilitates switching protection groups from using one tape library to another by individually re-assigning the ‘primary backup’ and ‘copy backup’ tape libraries. This script will ask to select source and target libraries and means that only the intended library assignments will change for all protection groups.

The number of drives to assign is kept the same by default and can optionally be specified. If the new drive has not enough drives the script defaults to 1 drive.
Likewise tape options (encryption, compression, data verification) are kept the same and can optionally be changed which will cause the script to ask new values for each group.

Source and target library can be the same which effectively just changes options when used with –ChangeOptions

Note: compression and encryption are mutually exclusive and is also enforced by the script.

Usage: DPMswitchTape.ps1 [-dpmserver <server name>] [-drives #] [-ChangeOptions ]

The script takes the following optional parameters;

  • -dpmservername <server name>, DPM server to manage, uses the local host by default
  • -drives <#>, the number of drives to assign
  • -ChangeOptions switch

Script begin

    [string]$dpmserver = “”,

function writelog
    param([string]$msg, $color=”Green”)
    $msg =  “[{0}] {1}” -f ((get-date).tostring($format)), $msg
    $msg >> $logfile
    Write-Host $msg -ForegroundColor $color
function SelectLibrary
    #get, present and return user selected library
    param([string]$title, $srv)
    # KEEP the where filter, there can be many old libraries definitions no longer present
    $libs = @(Get-DPMLibrary -DPMServerName $srv | where {$_.isoffline -eq $false})
    writelog “`nCurrent online library list…”
    $i = 0
    for ($i = 0; $i -le $libs.count-1; $i ++ ) {
        write-host (“[{0}] {1} ({2} drives, {3} slots)” -f $i,$libs[$i].userfriendlyname, $libs[$i].getdrivecollection().count,$libs[$i].getslotcollection().count)
    [int]$l_index = read-host “`nSelect $title from indexed list  ”
    if (!$libs[$l_index]) {Throw “Incorrect selection!”} else {
        $msg = “Selected  -> [” + $libs[$l_index].userfriendlyname + “]”
        writelog $msg
    return $libs[$l_index]
function SetOptions
    # initialize and get library options or keep current
    param ([string]$title, $ChangeOptions, $pg)
    $tp = @{“OnsiteComp”=[boolean]$false; “OnsiteEnc”=[boolean]$false; “OffsiteComp”=[boolean]$false; “OffsiteEnc”=[boolean]$false;”DataVer”=[boolean]$false}
    if ($ChangeOptions) {
        writelog “`nConfigure $title library”
        writelog “WARNING: Encryption and Compression are mutually exclusive, enabling compression disables encryption!`n”
        if ((read-host “Do you want SHORT term protection ENCRYPTION enabled [y/N] “) -imatch “Y”) {$tp.item(“OnsiteEnc”)=$true}
        if ((read-host “Do you want SHORT term protection COMPRESSION enabled [y/N] “) -imatch “Y”) {
            if ($tp.item(“OnsiteEnc”)) { writelog “`t<<< disabling short term encryption >>>”}
        if ((read-host “Do you want LONG  term protection ENCRYPTION enabled [y/N] “) -imatch “Y”) {$tp.item(“OffsiteEnc”)=$true}
        if     ((read-host “Do you want LONG  term protection COMPRESSION enabled [y/N] “) -imatch “Y”) {
            if ($tp.item(“OffsiteEnc”)) { writelog “`t<<< disabling long term encryption >>>”}
        if ((read-host “Do you want to enable backup data verification [y/N] “) -imatch “Y”) {$tp.item(“DataVer”)=$true}
    else {
        $tp.Item(“OnsiteComp”)    = $pg.ArchiveIntent.OnsiteCompression
        $tp.Item(“OnsiteEnc”)    = $pg.ArchiveIntent.OnsiteEncryption
        $tp.Item(“OffsiteComp”)    = $pg.ArchiveIntent.OffsiteCompression
        $tp.Item(“OffsiteEnc”)    = $pg.ArchiveIntent.OffsiteEncryption
        $tp.Item(“DataVer”)    = $pg.ArchiveIntent.DatasetVerificationIntent
    return $tp
trap [Exception] {
    # generic trap routine writing to event log and logf file
    writelog “<<< ERROR >>>”
    writelog $(“TRAPPED: ” + $_.Exception.GetType().FullName);
    #writelog $(“TRAPPED: ” + $_.Exception.Message);
    writelog “<<< end >>>”
    $log = Get-EventLog -List | Where-Object { $_.Log -eq “Application” }
    $log.Source = “DPMswitchTape”
    $log.WriteEntry(“TRAPPED: $error”, [system.Diagnostics.EventLogEntryType]::Error,9911)
    exit 1 ;

Disconnect-DPMServer #make sure we have no lingering connections
if ($dpmserver -eq “”) {$dpmserver = hostname}
$logfile = “DPMswitchTape.LOG”
$maxlog = 5 * 1024 * 1024
# set some commonly used
$global:format = “HH:mm:ss”
$version = “V2.0″
$c = “`,”; $q = “`'” ; $qq = “`””
if ($drives  -lt 1) {$drives =1}
#set to false for no console output
$Debug = $true

if ($Args.Count -eq 0) {
    writelog “`nUsage: DPMswitchTape.ps1  [-dpmserver <server name>] [-drives #] [-ChangeOptions 0/1]`n”
#display intro
writelog “DPMswitchTape $version using server $dpmserver”
$msg= “`n`tChanges protection group library assignment and options”
$msg= $msg + “`n`t`DPMswitchTape.Ps1 [-DPMserver <servername>]  [-drives #] [-ChangeOptions `$true]`n”
$msg= $msg + “`n`t`Parameter -drives # defaults to previous or 1 drive if target library has less drives than requested”
$msg= $msg + “`n`tSwitch -ChangeOptions `$true indicates you want to change library options, have to specify each group `n”
$msg=$msg + “`n`t(a) Select source of BACKUP and COPY library to be replaced”
$msg=$msg + “`n`t(b) Select target of BACKUP and COPY library to be assigned”
$msg=$msg + “`n`t(c) Select library options (defaults to current definitions)”
$msg=$msg + “`n`t(d) Confirm to modify all groups or exit without changes`n”
writelog $msg “White”

#ensure logfile does not keep growing endlessly
if ((Get-Item $logfile).length -gt $maxlog) {Remove-Item -path $logfile – confirm:$false}

#get backup libs to re-assigned
$sourcelib = SelectLibrary “OLD BACKUP source library to re-assing” $dpmserver
$targetlib = SelectLibrary “NEW BACKUP target library to assign” $dpmserver

#get copy libs to re-assign
$copysourcelib = SelectLibrary “OLD COPY source library to re-assign” $dpmserver
$copytargetlib = SelectLibrary “NEW COPY target library to assign” $dpmserver

if ((read-host “`nContinue and actually modify groups [Y/n] ” ) -inotmatch “Y”) {
    writelog “Done, exiting without changes!”
    exit 0
writelog “Modifying groups…`n”
$grps = @(Get-ProtectionGroup -DPMServerName $dpmserver | ? {$_.GetDatasources().Count -gt 0})
#Now go modify the groups
foreach ($group in $grps) {
    #skip if not selected source backup library
       if ($group.ArchiveIntent.LibraryId.Equals($sourcelib.Id)) {
           writelog (“Processing group {0}” -f  $group.friendlyname)
        #do library parameters (there is only 1 set of options for both drives)
        $libparams = SetOptions “long term parameters” $ChangeOptions $group
        $libparams >> $logfile
        if  ($targetlib.GetDriveCollection().count -lt $drives) {
            $drives = 1 #possibly set to max available drives instead?
            writelog “Target library has less than requested number of drives, setting drive pool to $drives”
        $mpg=Get-ModifiableProtectionGroup $group
        $mpg.ArchiveIntent.NumberOfDrives= $drives
        Set-ProtectionGroup -ProtectionGroup $mpg
        $msg=”Modified BACKUP library of protection group ” + $group.FriendlyName + ” from [” + $sourcelib.UserFriendlyName + “] to [” + $targetlib.UserFriendlyName + “]”
        writelog $msg
          $msg = “Skipping BACKUP library for protection group ” + $group.friendlyname + ”  because the curren does not match source selection!”
        writelog $msg
    #skip if not selected source copy library
   if ($group.ArchiveIntent.SecondaryLibraryId.Equals($copysourcelib.Id)) {
        $mpg=Get-ModifiableProtectionGroup $group
        $mpg.ArchiveIntent.NumberOfDrives= $drives
        Set-ProtectionGroup -ProtectionGroup $mpg
        $msg=”Modified COPY library of protection group ” + $group.FriendlyName + ” from [” + $copysourcelib.UserFriendlyName + “] to [” + $copytargetlib.UserFriendlyName + “]”
        writelog $msg
          $msg = “Skipping COPY library for protection group ” + $group.friendlyname + ”   because the current does not match source selection!”
        writelog $msg
writelog “`nDone!”
exit 0