OffsiteReady Bänder mit Powershell ausgeben

Wir haben von einem unserer Leser eine Frage bekommen. Er möchte die Bänder, die rausgenommen werden können, per Powershell einfach ausgeben anstatt jedes Mal den Tape Report zu bemühen.

Das lässt sich in Powershell mit wenigen Zeilen erledigen:

$Tapes = Get-Tape -DPMLibrary EureLibraryName
$Tapes | Where-Object {$_.isOffsiteReady} | format-table Location, Barcode, isOffsiteReady

In der ersten Zeile füllen wir die Variable $Tapes mit den Tapeinformationen eurer Library. Habt ihr mehr als eine Library, dann benutzt auch hier eine Variable wie z.B. $Libraries und füllt diese mit den Namen eurer Libraries:

$Libraries = Get-DPMLibrary -dpmservername Servername

In der zweiten Zeile oben geben wir dann nur die Tapes aus, die Offsite Ready sind und formatieren sie nach Location, Bezeichnung und OffsiteReady.

Wollt ihr die Ausgabe sortieren, z.B. nach Slots (Location) oder nach Barcode, dann fügt ihr einfach noch eine Pipe gleich nach der Ausgabe mit dem Befehl:

sort-object Spalte

Um also z.B. nach Slots zu sortieren lautet der volle Befehl:

$Tapes | sort-object Location | Where-Object {$_.isOffsiteReady} | format-table Location, Barcode, isOffsiteReady

Unserem Leser ist damit geholfen und es interessiert sicher noch mehr Leser hier.

Schreibt uns was euch interessiert und wir greifen es gerne auf!

Daten wiederherstellen via Powershell anstelle der Konsole

Einen Restore über die GUI zu machen ist verhältnismäßig einfach. Nun sind einige von uns Admins ja eher Powershell Junkies und fragen sich sicher ob man einen Restore nicht einfach mit Powershell machen kann.

Ja kann man und heute beschreiben wir kurz wie das geht:

Das Powershell CmdLet lautet :

Recover-RecoverableItem [-RecoverableItem] <RecoverableObject[]> [-RecoveryOption] <RecoveryOptions> [-RecoveryPointLocation <RecoverySourceLocation[]>] [-JobStateChangedEventHandler <JobStateChangedEventHandler>] [-RecoveryNotification <Nullable`1>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]

Schaut auf den ersten Blick komplizierter aus als es ist. Um einen Restore zu machen braucht man drei wesentliche Information:

– Was soll wiederhergestellt werden ?
– Mit welchen Optionen soll der Restore laufen ? (Überschreiben, Berechtigungen etc.)
– Welcher Recovery Point soll benutzt werden ?

1. Zunächst müssen wir festlegen aus welcher Protection Group die Datei kommt, die wir  wiederherstellen wollen.
Dazu erstellen wir eine Variable mit allen Protection Groups die unser DPM Server hält:

$pg = Get-ProtectionGroup -dpmservername Servername

Das Ergebnis ist ein Array mit allen Protection Groups. Wir suchen uns eine davon aus. Wie in einem Array üblich beginnt die Nummerierung mit 0. Nehmen wir also gleich die erste Protection Group $pg[0]. Jetzt möchten wir wissen welche Datensourcen enthalten sind:

$ds = Get-DataSource -protectiongroup $pg[0]

Jetzt wählen wir auch eine Datenquelle aus und schauen welche Recoverypoints enthalten sind:

$rp = Get-RecoveryPoint -datasource $ds[0]

Das liefert auch wieder ein Array zurück sortiert nach dem ältesten Recoverypoint und in der Sortierung Disk -> Tape. Also erst eine Liste aller Recoverypoints auf Disk beginnend mit dem ältesten und danach eine Liste aller Recoverypoints auf Tape beginnen mit dem ältesten. Nehmen wir an der aktuellste Recoverypoint auf Disk ist in der Liste auf Platz 6. Also wählen wir $rp[5] aus um daraus den Restore zu machen.

2. Jetzt benötigen wir die Optionen für die Wiederherstellung. Hier legen wir fest, wohin zurückgesichert werden soll, ob überschrieben oder eine Kopie erstellt wird, ob an eine alternative Location zurückgesichert wird etc. :

$options = New-RecoveryOption -targetserver Servername -recoverylocation copytofolder -FileSystem -alternatelocation „D:\Wiederherstellung“ -recoverytype restore -OverwriteType overwrite

3. Jetzt können wir ans Rücksichern gehen:

Recover-RecoverableItem -recoverableitem $rp[5] -recoveryoption $options

In unserem kurzen Überblick haben wir jetzt einen ganzen RecoveryPoint zurückgesichert. Will man nur eine einzelne Datei zurücksichern muss man die Suche benutzen New-SearchOption. Mit der lässt sich dann auch eine ganz bestimmte Datei zurücksichern. Wenn ihr dazu einen detaillierteren Beitrag lesen wollt, dann hinterlasst uns doch einen Kommentar oder schreibt uns über unser Formular.

Tape Library in DPM austauschen

Wir haben eine neue Tape-Library bekommen die LTO5 kann und somit brauchen wir in Zukunft weniger Bänder. Da freuen wir uns natürlich sehr darüber. Aber vor der Freude hat der liebe Gott die Arbeit gesetzt. Auspacken, einbauen, installieren, soweit alles in Ordnung. Nach einem Rescan wird die neue Library auch in DPM korrekt angezeigt und die alte als Offline.

Jetzt stecken aber laut DPM Datenbank in der alten Library noch Tapes drin die Offsite Ready sind und die alte Library taucht natürlich auch im Tape Report auf.

Das liegt daran, dass die alte Tape Library so lange im Management angezeigt wird, so lange sie mit einer Protection Group verknüpft ist. Das heißt, man muss jede Protection  Group modifizieren und Backup & Copy Library ändern. Wenn man nur ein oder zwei Protection Groups hat, ist das ganz einfach. Hat man aber viele, so wie wohl die meisten, dann hilft uns das nachfolgende Powershell Skript.
Vielen Dank an dieser Stelle an Ruud Baars:
http://blogs.technet.com/b/dpm/archive/2010/07/09/replacing-tape-drive-assignments.aspx

Das Skript ruft man plain auf bzw. mit -dpmserver Servername , sofern man es remote ausführt. Es listet dann die online Libraries auf und man wählt dann Quelle und Ziel aus, jeweils für Backup und Copy.

Eine weitere Option ist -drives <#> . Mit dieser legt man die Anzahl der zu benutzenden Laufwerke an. Ist diese nicht angegeben wird der Wert nicht verändert, der bereits eingetragen ist.

Hat man so wie bei uns die alte Library schon abgeschaltet und diese ist offline, wird die natürlich nicht angezeigt. In dem Fall muss man den rot markierten Text aus dem Skript löschen:

param(
 [string]$dpmserver = "",
 [int]$drives=0,
 [switch]$ChangeOptions)
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 >>>"}
 $tp.item("OnsiteComp")=$true
 $tp.item("OnsiteEnc")=$false
 }
 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 >>>"}
 $tp.item("OffsiteComp")=$true
 $tp.item("OffsiteEnc")=$false
 }
 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);
 $Error
 writelog "<<< end >>>"
 $log = Get-EventLog -List | Where-Object { $_.Log -eq "Application" }
 $log.Source = "DPMswitchTape"
 $log.WriteEntry("TRAPPED: $error", [system.Diagnostics.EventLogEntryType]::Error,9911)
 $Error.Clear()
 exit 1 ;
}
#START
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
#confirm
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.Libraryid=$targetlib.Id
 $mpg.ArchiveIntent.NumberOfDrives= $drives
 $mpg.ArchiveIntent.OnsiteCompression=$libparams.Item("OnsiteComp")
 $mpg.ArchiveIntent.OnsiteEncryption=$libparams.Item("OnsiteEnc")
 $mpg.ArchiveIntent.OffsiteCompression=$libparams.Item("OffsiteComp")
 $mpg.ArchiveIntent.OffsiteEncryption=$libparams.Item("OffsiteEnc")
 $mpg.ArchiveIntent.DatasetVerificationIntent=$libparams.Item("DataVer")
 Set-ProtectionGroup -ProtectionGroup $mpg
 $msg="Modified BACKUP library of protection group " + $group.FriendlyName + " from [" + $sourcelib.UserFriendlyName + "] to [" + $targetlib.UserFriendlyName + "]"
 writelog $msg
 }
 else
 {
 $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
 $mpg.Archiveintent.SecondaryLibraryid=$copytargetlib.id
 $mpg.ArchiveIntent.OnsiteCompression=$libparams.Item("OnsiteComp")
 $mpg.ArchiveIntent.OnsiteEncryption=$libparams.Item("OnsiteEnc")
 $mpg.ArchiveIntent.OffsiteCompression=$libparams.Item("OffsiteComp")
 $mpg.ArchiveIntent.OffsiteEncryption=$libparams.Item("OffsiteEnc")
 $mpg.ArchiveIntent.DatasetVerificationIntent=$libparams.Item("DataVer")
 Set-ProtectionGroup -ProtectionGroup $mpg
 $msg="Modified COPY library of protection group " + $group.FriendlyName + " from [" + $copysourcelib.UserFriendlyName + "] to [" + $copytargetlib.UserFriendlyName + "]"
 writelog $msg
 }
 else
 {
 $msg = "Skipping COPY library for protection group " + $group.friendlyname + " because the current does not match source selection!"
 writelog $msg
 }
}
writelog "`nDone!"
exit 0

Überfällige Bänder aus der Datenbank entfernen (DPM 2010)

Oftmals gibt es das Problem, dass Bänder im Tape Report auftauchen, die eigentlich nicht mehr verwendet werden sollen oder können.
Diese tauchen jedoch bei jedem Report erneut auf und können über die GUI nicht gelöscht werden.

Um die Bänder zu entfernen ist es notwendig sie in der Datenbank zu löschen. Bisher habe ich das SQL Command jedoch nur für die MS DPM 2010  Datenbank verwendet. Über eine Info ob es auch im DPM 2012 klappt würden wir uns freuen.
Bitte denkt immer daran vor Eingriffen in die Datenbank ein Backup zu machen 😉

Um das Command aus zu führen öffnet ihr das SQL Management Studio und verbindet euch auf die SQL DB Meist

localhost\MSDPM2010

Als nächstes Müsst ihr eine neue SQL Abfrage ( SQL Query) erstellen:

New SQL Query

Nun einfach die folgende Abfrage kopieren und entsprechend wie folgt anpassen:

den ´TAPE LABEL NAME´ zwischen den 2 ‚ anpassen mit dem Tape Label Namen den ihr löschen wollt.
Es empfiehlt sich den Namen vorher aus dem DPM Tape Report zu kopieren, damit Fehler vermieden werden.

Bitte beachtet das es sich hierbei nicht um den Namen auf dem Tape sondern den Tape Label Namen auf dem Tape Report von DPM handelt der entsprechend gelöscht/eingetragen werden muss.

———- START COPY HERE ————-

— overdue tapes
— for clarity, set up the parameter as a variable
declare @paramTapeLabel as nvarchar(256)
set @paramTapeLabel = N’TAPE LABEL NAME‘

— keys
declare @vMediaId as guid
declare @vGlobalMediaId as guid

— if the delete gives trouble, add keyset after cursor
declare cur_label cursor
for select MediaId, GlobalMediaId
from tbl_MM_Media
where label = @paramTapeLabel;

open cur_label
while (0 = 0)
begin
fetch next from cur_label into @vMediaId, @vGlobalMediaId
— test for being done
if @@fetch_status <> 0 break;

print ‚Deleting MediaId = ‚ + cast(@vMediaId as varchar(36))
— do a set of deletes atomically
begin transaction;
delete from tbl_MM_TapeArchiveMedia
where MediaId = @vMediaId;

delete from tbl_MM_MediaMap
where MediaId = @vMediaId;

delete from tbl_MM_ArchiveMedia
where MediaId = @vMediaId;

delete from tbl_MM_Global_ArchiveMedia
where MediaId = @vGlobalMediaId;

delete from tbl_MM_Global_Media
where MediaId = @vGlobalMediaId;

delete from tbl_MM_Media
where current of cur_label;

commit transaction;

end
close cur_label
deallocate cur_label

————– END COPY HERE ———————-