Quantcast
Channel: System Center Data Protection Manager
Viewing all 119 articles
Browse latest View live

CLI script: Create protection groups for Disk based backups

$
0
0

The following script creates a protection group with disk based protection, for a simple folder. It can be easily extended to add more data sources of different kinds – like Microsoft Exchange, SQL, Sharepoint, System state or Virtual Servers. The Synchronization frequency and retention ranges etc. can be easily modified to suit your needs.  Also, since we are protecting a sub-folder in a volume, we are using the CalculateSize parameter in Get-DataSourceDiskAllocation, which would calculate the exact size needed for all the items in that folder. This is not needed when protecting an application like Exchange/SQL or protection the entire File system volume.

 

---------------------------------------------- Start of Script ---------------------------------------------------

# To D2D create PG and do the initial replication

# This script is for creating Disk to Disk PG for File System

# For details contact mukuls[at]microsoft[dot]com

# Create a .ps1 file with this script and run under DPM Management Shell

 

# Customize these values as per your environment

 

$dpmname = "DPMServername.somedomain.com"

$psname = "PSservername.somedomain.com"

$dsname = "G:\"

$poname = "G:\ProtectableFolder"

$pgname = "MyCLIPG"

 

function CreatePG

{

                param($dpmname, $psname, $dsname, $poname, $pgname)

 

                write-host "Creating a D->D PG --> $pgname..."

 

                trap{"Error in execution... ";break}

                &{           

                                Write-Host "Getting PS: $psname from DPM: $dpmname"

                                $ps = Get-ProductionServer -DPMServerName $dpmname | where { ($_.machinename,$_.name) -contains $psname }

                               

                                Write-Host "Running Inquiry on PS: $psname for datasource $dsname"

                                $ds = Get-Datasource -ProductionServer $ps -Inquire | where { ($_.logicalpath,$_.name) -contains $dsname }

                               

                                Write-Host "Getting Child-datasource $poname from datasource $dsname"

                                $po = Get-ChildDatasource -ChildDatasource $ds -Inquire | where { ($_.logicalpath,$_.name) -contains $poname }

 

                                write-host "Create New PG ..."

                                $pg = New-ProtectionGroup -DPMServerName $dpmname -Name $pgname

 

                                write-host "Adding child datasource..."

                                Add-childDatasource -ProtectionGroup $pg -ChildDatasource $po

 

                                write-host "Setting Protection Type..."

                                Set-ProtectionType -ProtectionGroup $pg -ShortTerm disk

 

                                write-host "Setting Policy Objective...retention range - 10Days, synchronizationFrequency 15"

                                Set-PolicyObjective -ProtectionGroup $pg -RetentionRangeInDays 10 -SynchronizationFrequency 15

 

                                write-host "Setting Policy Schedules ..."

                                $ShadowCopysch = Get-PolicySchedule -ProtectionGroup $pg -ShortTerm| where { $_.JobType -eq "ShadowCopy" }

                                Set-PolicySchedule -ProtectionGroup $pg -Schedule $ShadowCopysch -DaysOfWeek mo -TimesOfDay 02:00

 

                                write-host "Setting Disk Allocation, with optimization (will take a few minutes to complete)"

                                Get-DatasourceDiskAllocation -Datasource $ds -Calculatesize

                                Set-DatasourceDiskAllocation -Datasource $ds -ProtectionGroup $pg

 

                                write-host "Setting Replica Creation Method ..."

                                Set-ReplicaCreationMethod -ProtectionGroup $pg -NOW

 

                                write-host "Commiting PG"

                                Set-protectiongroup $pg

                }

}

 

 

function waitforIRtoComplete

{

                param($waittime)

 

                write-host "Wait for IR to complete"

               

                $val = $waittime/30

                while($val -gt 0)

                {

                                Write-host "Wait for IR to complete... $val"

                                start-sleep 30

                                $val--

                }

               

}

 

Connect-DPMServer -DPMServerName $dpmname;

createPG $dpmname $psname $dsname $poname $pgname;

waitforIRtoComplete 120;

 

---------------------------------------------- End of Script ----------------------------------------------

 

- Mukul Singh Shekhawat, Balaji Hariharan


DPM PowerShell Script -- invoking a Consistency Check

$
0
0

By design, DPM 2007 should be ‘fire and forget’ – meaning that after initial replication, data changes will automatically and routinely replicate. 

However, due to a variety of external factors, the data set may become inconsistent.  Usually, DPM will correct itself within a replication cycle.  Depending on how often you have configured replication, this may not be soon enough.  One resolution to this is to have one’s management solution (e.g. System Center Operations Manager) see the alert that a data set is inconsistent and then automatically run this ‘consistency check’ to revalidate the data in a more timely manner.

Attached is a sample PowerShell script to invoke a consistency check of on a DPM data source.

# This script do a consistency check on the file system data source. The parameters have to be initialized first as given below.  Please give the values of parameters as appropriate for your environment.  You can customize this easily as per your needs. Save the attached file as a .ps1 file and invoke through the DPM Management Shell.

$dpmname = "DPM Server Name";
$pgname = "My PG";
$dsname = "G:\";

function StartDatasourceConsistencyCheck
{
    param($dpmname, $pgname, $dsname, $isheavyweight)

    write-host "Start consistency check on $dsname "

    trap{"Error in execution... $_";break}
    &{
        write-host "Getting protection group $pgname in $dpmname..."
        $clipg = Get-ProtectionGroup $dpmname | where { $_.FriendlyName -eq $pgname }

         if($clipg -eq $abc)
          {
              Throw "No PG found"
          }

        write-host "Getting $dsname from PG $pgname..."
        $ds = Get-Datasource $clipg | where { $_.logicalpath -eq $dsname }

        if($ds -eq $abc)
         {
              Throw "No Data Source found"
         }

        if( $isheavyweight -ne "true")
        {
            write-host "Starting light weight consistency check..."
            $j = Start-DatasourceConsistencyCheck -Datasource $ds
            $jobtype = $j.jobtype
            if(("Validation") -notcontains $jobtype)
                {
                    Throw "Shadow Copy job not triggered"
                }
            while (! $j.hascompleted ){ write-host "Waiting for $jobtype job to complete..."; start-sleep 5}
            if($j.Status -ne "Succeeded") {write-host "Job $jobtype failed..." }
            Write-host "$jobtype job completed..."
        }
        else
        {
            write-host "Starting Heavy weight consistency check..."
            $j = Start-DatasourceConsistencyCheck -Datasource $ds -HeavyWeight
            $jobtype = $j.jobtype
            if(("Validation") -notcontains $jobtype)
                {
                    Throw "Shadow Copy job not triggered"
                }
            while (! $j.hascompleted ){ write-host "Waiting for $jobtype job to complete..."; start-sleep 5}
            if($j.Status -ne "Succeeded") {write-host "Job $jobtype failed..." }
            Write-host "$jobtype job completed..."
        }

    }
}

#Example for usage

StartDatasourceConsistencyCheck $dpmname $pgname $dsname "false"
StartDatasourceConsistencyCheck $dpmname $pgname $dsname "true"

-- Mukul

CLI Script: To remove all datasources in inactive protection state

$
0
0

The attached script removes all inactive datasources under a given DPM server. It provides options to remove inactive datasources on disk/tape/both. Save this as a .ps1 file and invoke it from inside the DPM Management Shell. Please contact us if you need any further assistance in running the script or face any issues.

 

- Madhan S

CLI Script: To recover a DPM replica volume from data stored in tape

$
0
0

When a disaster occurs, and you lose your replica volume for any datasource, you could re-seed the replica from the backed-up data you have in tape. This little script initializes replica from a tape recovery point. The parameters have to be customized for your environment first as given below. 

Save the attached file as a .ps1 file and invoke through the DPM Management Shell.

 

- Madhan S

DPM CLI Tips 'n Tricks: Powershell Basics

$
0
0

The scripts posted in this blog require knowledge of Powershell and DPM cmdlets. So we thought we would present some tips ‘n tricks to become power users!

 

Introduction

The first difference between any normal Command Line Interface (CLI) (typically, Windows cmd.exe based environment) & Powershell is that, Powershell is a full blown .Net environment and is object oriented. In other words, it treats all input/output parameters as objects and when you pipe one command to another, objects flow instead of plain text as in old shells. Similarly, DPM Management Shell also takes inputs in the form of objects – for example, DPM, Protection Group, Datasource, Library, Tape, Tape Drive, Disk etc. are all .Net objects. Let’s now move on to more interesting stuff.

 

Finding cmdLets (Get-Command or gcm)

For knowing all the cmdLets present in the Powershell instance, use Get-Command (or gcm in short). When run, the output will be something like this:

 

PS D:\ > Get-command

 

CommandType   Name                  Definition

-----------       ----                   ----------

Cmdlet              Add-Content       Add-Content [-Path] <String[...

Cmdlet              Add-DPMDisk       Add-DPMDisk [-DPMDisk] <Disk...

Cmdlet              Add-History         Add-History [[-InputObject] ...

Cmdlet              Add-Member        Add-Member [-MemberType]

Cmdlet              Add-PSSnapin      Add-PSSnapin [-Name] <String...

Cmdlet              Add-Tape            Add-Tape [-DPMLibrary] <Libr...

Cmdlet              Clear-Content      Clear-Content [-Path] <Strin...

 

Finding DPM cmdLets (Get-DPMCommand)

Similarly for getting all the cmdLets belonging to only DPM, use the Get-DPMCommand.

 

PS D:\ > Get-DPMCommand

 

CommandType  Name                      Definition

-----------      ----                        ----------

Cmdlet            Add-DPMDisk             Add-DPMDisk [-DPMDisk] <Disk...

Cmdlet            Add-Tape                 Add-Tape [-DPMLibrary] <Libr...

Cmdlet            Connect-DPMServer   Connect-DPMServer [-DPMServe...

Cmdlet            Disable-DPMLibrary     Disable-DPMLibrary [-DPMLibr...

Cmdlet            Disable-TapeDrive      Disable-TapeDrive [-TapeDriv...

 

How to use a cmdlet?

 

1. Understanding the cmdlet parameters (Get-Command and Format-List)

There are two parts to understanding a cmdlet. First, to look at the various input parameters and various usages, you can use the Get-Command itself on a specific cmdlet, in the following fashion – Get-Command <cmdlet> | format-list (or gcm <cmdlet> | fl, in short).

 

PS C:\> gcm Set-Alias | fl

 

Name                     : Set-Alias

CommandType         : Cmdlet

Definition                : Set-Alias [-Name] <String> [-Value] <String> [-Description <String>] [-Option <ScopedItemOptions>] [-PassThru] [-Scope <String>] [-Force] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]

 

 

2. Reading Help documentation for a cmdlet (Get-Help or help)

For reading the Help documentation for any cmdlet use the following (Get-Help or help)

 

Get-Help <cmdlet>

 

For example:

 

PS D:\ > Get-Help Add-Tape

 

NAME

    Add-Tape

 

SYNOPSIS

    Adds a tape to a DPM library.

 

 

SYNTAX

    Add-Tape [-DPMLibrary] <Library> [-Async] [-JobStateChangedEventHandler <Jo

    bStateChangedEventHandler>] [<CommonParameters>]

…..

 

3. Getting detailed help, and seeing sample scripts

For seeing additional information on each of the cmdLets, you can use the –Full or –Detailed parameters in Get-Help.

 

e.g.    Get-Help Add-Tape –Detailed

Get-Help Add-Tape –Full

 

DPM Object Properties (Get-Member or gm)

 

The DPM cmdlets are logically divided in three groups Protection (Backup), Recovery and Management related (Library & Disk). All the tasks that can be done from the DPM UI in these areas, can be done from the cmdLets in these areas. Infact, the CLI provides additional features than the UI, in some scenarios.

 

You can get the member properties of any object by pipelining the output to Get-Member:

 

For example:

 

$lib = Get-DPMLibrary -DPMServerName “Testing Server Name”

$lib | Get-Member

 

Will give all the members of $lib (Library object).

 

PS D:\ > $lib | get-member

 

TypeName: Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.LibraryMan

agement.Library

 

Name              MemberType    Definition

----                ----------       ---------

ClearCache       Method            System.Void ClearCache()

Dispose            Method            System.Void Dispose()

 

We hope this was useful, feel free to add comments as feedback to this post. And in the next version, we can add more tricks!

 

- Mukul Shekawat, Balaji Hariharan

CLI Script: Auto re-running consistency checks

$
0
0

Some customers had non-DPM issues, like network issues because of which consistency check (CC) jobs failed too often. For the benefit of them, we have added a script that would re-try CC until it succeeds. Note: In some cases, CC would impact the protected computer’s performance and hence use this script appropriately.

 

- Vikash Jain

DPM CLI: Quick reference help

$
0
0

While using the DPM Management Shell, one would like to have a list of all cmdlets and its short help for quick reference. Also, we heard it would be useful to group the various cmdlets by the function they do – e.g. Library, Disk, Recovery or Protection related etc. Keeping this in mind, we have published this quick reference for you based on DPM 2007 Management Shell. You could take a print out of this and keep it handy while creating scripts. Btw, new cmdlets or parameters may be introduced in future versions or service packs of DPM, so you might want to update this list manually.

 

- Mukul Shekhawat, Balaji Hariharan

DPM CLI Tips 'n Tricks: Powershell Basics - Part II

$
0
0

Tab Completion

The most fascinating part of DPM Management Shell is Tab Completion of cmdlets. By learning the common verbs in Powershell (like Get, Set, Start etc.), a Windows or an Exchange admin can easily use that knowledge and learn the DPM cmdlets. This is because the same verbs are used in DPM Management Shell too.

 

For example: To get the list of protected servers backed-up by a DPM server, one needs to just type Get-P and keep pressing tab. This would result in Powershell suggesting the various cmdlets, and you can choose the right one needed. The ones that you would see in this example are - Get-Process, Get-ProductionCluster, Get-ProductionServer etc.

 

In addition, if you can also tab complete the various parameter names too in the same way, by typing a “-“ after the cmdlet name and pressing tab.

 

 

Examples of cmdlet usage(Get-Help <cmdlet> -example)

 

Getting directly to the example usage of a cmdlet can be done easily with optional parameters in Get-Help - Get-help <cmdletname> -example. This will directly print only the example usages of the cmdlet:

 

For example:

 

PS D:\> Get-help Get-ProtectionGroup -example

 

NAME

 Get-ProtectionGroup

 

SYNOPSIS

 Retrieves the list of protection groups on the DPM server.

 

EXAMPLE 1

 Get-ProtectionGroup -DPMServerName TestingServer

 

This command returns the protection group on a DPM server.

 

Getting only the cmdlet syntax (Get-Command <cmdlet> -syntax)

Another quick help about the syntax of cmdlet would be get by typing

 

PS D:\> Get-Command Get-Datasource -syntax

 

Get-Datasource [-DPMServerName] <String> [-Inactive] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]

 

Get-Datasource [-ProductionServer] <ProductionServer> [-Async] [-Inquire] [-Replica] [-Tag <Object>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]

 

Get-Datasource [-ProtectionGroup] <ProtectionGroup> [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]

 

Get-Datasource [-DPMServerName] <String> [-SearchPath] <String> [[-ProductionServerName] <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]

 

 

Using the object member properties (Get-Member)

With the help of get-member you can verify/set the property of the object.

 

PS D:\> $pg = Get-ProtectionGroup “MyDPMServerName”

PS D:\> $pg | get-member

 

TypeName: Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.ProtectionGroup

 

Name                                  MemberType    Definition

----                                    ----------       ----------

AddProtectableObject             Method           System.Void AddProtecta...

AddProtectionOptions             Method           System.Void AddProtecti...

.

.

FriendlyName                        Property           System.String FriendlyN...

InitializationType                   Property           Microsoft.Internal.Ente...

 

Now these properties can be used to filter and get a specific PG.

 

For Example:

 

$clipg = Get-ProtectionGroup $dpmname | where { $_.FriendlyName -eq $pgname }

 

 

CLI Help Updates and Errata

Any additional help information or errata gets updated per cmdlet and is available at http://go.microsoft.com/fwlink/?LinkId=95130.

 

- Mukul Shekhawat, Balaji Hariharan


CLI Script: To generate status reports

$
0
0
The attached script generates a comprehensive report of the status of all backups and the storage utilization for each Exchange Server that is protected by DPM on a per SG basis.

CLI Script: DPM status report

$
0
0

The following script generates a comprehensive report of failures and the storage utilization for each Exchange Server that is protected by DPM on a per SG basis.

CLI Script: Script to generate DPM configuration report

$
0
0

The attached script generates a report of the mapping between each Exchange Server, the backup Protection Groups and its associated SGs.

 

Krishna Mangipudi

Hyper-V Protection with DPM 2010 Beta - How to automatically protect new Virtual Machines

$
0
0

System Center Data Protection Manager 2010

We had a great question come into the DPM Newsgroup recently. How do I automatically protect new VMs added to a Hyper-V host using DPM?

In any virtualized environment, adding new VMs is a frequent operation. While backup administrators can protect an entire Hyper-V host using the DPM Management Console, the protection group had to be modified manually to include the new virtual machines that have come up on the Hyper-V host.

This blog post aims to make this an automated task by adding new virtual machines to protection on the given Hyper-V hosts using simple PowerShell scripts. These scripts are expected to work with DPM 2010 Beta. By using the information in this blog post, you should be able to quickly put together a script that can enable the auto protection of your hyper-v hosts.

Download Scripts :  AddNewClusteredVM.ps1  and AddNewStandAloneVM.ps1

Note: These scripts work on an existing protection group and do not create a fresh protection group.

 

The attached scripts automate the task of adding any new virtual machines recognized in the Hyper-V hosts protected by the DPM server into existing protection groups. There are different scripts for Hyper-V clusters (AddNewClusteredVM.ps1) and standalone Hyper-V hosts (AddNewStandAloneVM.ps1). You would still use the script for standalone servers to automatically protect the non-clustered virtual machines of any Hyper-V host that is part of a cluster.

 

Let us now walk you through the scenario and the scripts...

Walk Through

Protecting standalone Hyper-V hosts

The script for standalone servers (AddNewStandAloneVM.ps1) takes as input the following two values in order:

VariableExplanationExample
Server NameFully Qualified Domain Name of the Hyper-V host server.hyperv01.contoso.com
Protection GroupName of the existing protection group to which we are adding the new virtual machines.Protection Group 3

 

The script performs the following tasks:

1. Takes FQDN of protected server and name of protection group as input.

2. Searches for the protected server and the protection group.

3. Runs inquiry on the Hyper-V host and obtains the list of unprotected virtual machines.

4. Adds the obtained list of virtual machines to the protection group.

5. Saves the changes to the protection group and exits.

 

Example usage:

This example takes the following values as inputs:

hyperv01.contoso.com – replace this with the name of your Hyper-V host

dpm-server01.contoso.com – replace this with the name of your DPM server

PS C:\Program Files\Microsoft DPM\DPM\bin> .\AddNewStandAloneVM.ps1 hyperv01.contoso.com "Protection Group 3"

Name                                                     Domain

----                                                         ------

dpm-server01.contoso.com                CONTOSO.COM

Running Inquiry on hyperv01.contoso.com

Adding data source Backup Using Child Partition Snapshot\StandaloneVM to Protection Group 3

Adding new Hyper-V data sources to Protection Group 3

Exiting from script

Protecting Hyper-V clusters

The script for clustered servers (AddNewClusteredVM.ps1) takes as input the following two values in order:

VariableExplanationExample
Cluster NameFully Qualified Domain Name of the Hyper-V cluster.csv01.contoso.com
Protection GroupName of the existing protection group to which we are adding the new virtual machines.Protection Group 2

 

The script performs the following tasks:

1. Takes FQDN of protected cluster and name of protection group as input.

2. Searches for the protected cluster and the protection group.

3. Runs inquiry on the cluster to get the list of resource groups.

4. Runs parallel inquiry for each resource group and obtains the list of unprotected virtual machines under them.

5. Adds the unprotected virtual machines to the protection group.

6. Saves the changes to the protection group and exits.

The difference in this script is in Step 3 & 4 in AddNewClusteredVM.ps1 where we run inquiry on the cluster to get the list of resource groups, followed by inquiry on the resource groups. Also, inquiry on resource groups is run in parallel unlike what we do for standalone servers. We run inquiry in parallel for the cluster to avoid a performance overhead. Such an overhead is not seen for standalone servers.

Example usage:

This example takes the following values as input:

csv01.contoso.com – replace this with the name of your Hyper-V cluster

dpm-server01.contoso.com – replace this with the name of your DPM server

PS C:\Program Files\Microsoft DPM\DPM\bin> .\AddNewCLusteredVM.ps1 csv01.contoso.com "Protection Group 2"

Name                                                     Domain

----                                                        ------

dpm-server01.contoso.com                CONTOSO.COM

Running Inquiry on csv01.contoso.com

Running Inquiry on Cluster Group

Running Inquiry on Available Storage

Running Inquiry on SQLLoadVM

Running Inquiry on SharepointLoadVM

Running Inquiry on Win7VM

Waiting for inquiry to complete 0 item(s) obtained...

.

Waiting for inquiry to complete 1 item(s) obtained...

.

.

Waiting for inquiry to complete 5 item(s) obtained...

Inquiry listed 5 item(s)...

Adding data source Backup Using Child Partition Snapshot\Win7VM to Protection Group 2

Adding new Hyper-V data sources to Protection Group 2

Exiting from script

You can now write a batch file to call the above scripts one after the other and schedule it using the Windows Task Scheduler to run as frequently as needed.

Important:

· Shared disks that may be listed under the resource groups of your Hyper-V cluster are not Hyper-V data sources, and are not considered for automatic addition using this script.

· Any new virtual machines that are finally added to a protection group are scheduled for immediate replica creation, overriding any existing protection group behavior. You may modify the respective script to change this after referring the specific cmdlet help option.

 

-- Angad Pal Singh | DPM Team (Author)

Recover-Recoverable Item

$
0
0

Its 6:00PM.  You were supposed to leave at 5:00PM.  Your boss catches you as you walk out the door and says he needs a file restored for a presentation first thing in the morning.  You say, “No problem, I will restore it real quick before I head home.”  You head to the DPM server and try and open the console.  To your dismay, the console will not open.  You inform your boss of the situation.  He asks if there is any way at all to restore the file because he cannot wait until the morning.  You remember that when you installed DPM that it required PowerShell.  Maybe there is a way to restore files from the DPM Management Shell?  You are exactly right!  But you have never done it.

This blog will walk you through the steps of doing a simple file restore from Powershell.

From previous blogs you learned some of the fundamentals of Powershell; specifically arrays and index values.  In this PowerShell cmdlet you will put that knowledge to the test.

This is the command as listed in Technet:

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

 

Looks too difficult to attempt at 6:15PM right?  Wife is waiting for you to eat dinner, kids need their baths, etc… Sound familiar?

Let’s simply this cmdlet; you will need some information to do the recovery.

What you will need:

1.       Recoverable Object

2.       Recovery Options

3.       Recovery Point Location

First we need to get a recoverable object. Easy enough right?  Wrong, it requires three variables and those have to be indexed into the get-recoverypoint cmdlet so technically you get two cmdlets for the price of one in this blog.

You will be creating three variables

1.       $pg = get-protectiongroup –dpmservername dpmserver1

a.       This will return an array; assign an index value to the first one you see as 0, the second one will be 1, etc…clip_image002

2.       $ds = get-datasource –protectiongroup[$pg_arrayindexvaluefromabove]

a.       This will return an array

clip_image004

3.       $rp= get-recoverypoint –datasource[$ds_arrayindexvalue]

clip_image006

4.       $gr = get-recoverableitem –recoverableitem $rp[0]

clip_image008

Once you have the above three variables created you can now determine which recovery point you want to restore.  No, we are not done yet but we now have most of the information necessary to perform the recovery.  Just a few more variables and we are done.

Let’s look at recover-recoverableitem again.  This time we will look at the bare minimum that you will need to get your bosses file restored so you can get out the door to go home.

Recover-RecoverableItem [-RecoverableItem] <RecoverableObject[]> [-RecoveryOption] <RecoveryOptions> [-RecoveryPointLocation <RecoverySourceLocation[]>]

 

Recover-recoverableitem requires 3 pieces of information.  We have the recoverable object in the array index value from $rp above.

We also need recovery options ($rop.)  This is another variable.  It takes information that you input and when the item is recovered, it uses these variables to overwrite the file, restore the file, etc…

 $rop

Once we have the $rop variable we can finally restore the file.

Captureend

You can see from the above screenshot that we are now in progress of putting the file back where it came from.

Walt Whitman

Support Escalation Engineer

Microsoft System Center Support

How to create and delete recovery points for DPM via PowerShell

$
0
0

Knowing how to manipulate DPM by way of PowerShell can come in handy in many situations. For example, I had a case to where I was troubleshooting the DPM console that was crashing and there was a concern as to whether or not recovery points where being made for specific protection groups. Using the PowerShell command we could not only verify this, but we could create a recovery point to any protection group we wished. Another example would be if you wanted to delete some recovery points to reclaim some disk space.  Recovery points cannot be deleted by the GUI so you have to use PowerShell to accomplish that goal.

This video covers how to use PowerShell to both create and delete recovery points:

Get Microsoft Silverlight

Shane Brasher | Senior DPM Support Escalation Engineer

Checking LDM database space usage

$
0
0

When should I be concerned with this?

Usually not at all and the DPM2010 RTM release will check actual LDM consumption providing an early warning. Neither will DPM2010 consume all LDM space allowing space for re-consolidation purposes to reduce extents should that be needed.  However, …

…on large scale storage migrations you may want to check what is still possible before migrating hundreds of volumes. For instance with 300 data sources and zero extents you can only migrate 193 data sources at a time because volumes must co-exist for a while. At that point, old migrated volumes will have to be deleted to free-up LDM space.

…upgrading DPM2007 to DPM2010 maintains the storage pool which may already be in a less desirable state due to large number of extends created during the DPM2007 life time. In a bad case you may want to opt for migration rather than in place upgrade.

 

How to check what is still available?

I like to point to a companion script by Sid Ramesh that provides useful information on how many volumes and extents are used and how many more data sources can be added.


How much can I shrink recovery point volumes with DPM2010

$
0
0

The script shown below finds out how much recovery points volumes could be shrunk on DPM2010.
One word of caution though: use the shrink feature with common sense and not as a regular remedy!Repeated small shrinks cause free space fragmentation and increases the number of extents.

The shrink option can be useful if accidental gross over allocation occurred that certainly is not needed. Or if storage pool is depleted, no chance of rapid expansion and urgent need of raw space.

Sample output 

FindShrinkableSpace

#begin script

#----------------

param([string] $DPMServerName)

if(!$args[0])
{
    if(!$DPMServerName)
    {
        $DPMServerName = read-host "DPMServer:"
    }
}
else
{
    if(("-?","-help") -contains $args[0])
    {
        write-host Usage::
        write-host FindShrinkableSpace.ps1 -DPMServerName [dpmserver]
        write-host Help::
        write-host Finds the shrinkable space for all volumes protected on the specified DPM server.
        write-host
        exit 0
    }
    else
    {
        write-host "Usage -? for Help"
        exit 1
    }
}

$dsListAfterCalculatingShrink = @{}

$dpmServer = Connect-DPMServer $DPMServerName
if (!$dpmServer)
{
    Write-Error "Unable to connect to $DpmServerName"
    exit 1
}

$pgList = Get-ProtectionGroup -DPMServerName $DPMServerName
if ($pgList -ne $null)
{
    foreach ($pg in $pgList)
    {
        $dsList = Get-Datasource -ProtectionGroup $pg
        foreach ($ds in $dsList)
        {
            # If we have already stored a datasource for this physical replica, skip this DS and continue (since it will be the same)
            if ($dsListAfterCalculatingShrink.ContainsKey($ds.AssociatedReplica.PhysicalReplicaId))
            {
                continue
            }

            $currentSizeInGb = [System.Math]::Round(($ds.ShadowCopyAreaSize * 1.0) / (1024.0 * 1024.0 * 1024.0), 2);
            $shrinkableSizeInGb = 0;

            #Clear errors, check for any exception during 'CalculateShrinkThresholds' operation
            $prevErrorActionPreference = $ErrorActionPreference;
            $ErrorActionPreference = "SilentlyContinue";
            $Error.Clear()
            $ds2 = Get-DatasourceDiskAllocation -dataSource $ds -CalculateShrinkThresholds
            if ($?)
            {
                $shrinkableSizeInGb = [System.Math]::Round((($ds.ShadowCopyAreaSize - $ds2[0].ShadowCopySizeAfterMaxShrink) * 1.0 ) / (1024.0 * 1024.0 * 1024.0), 2);
            }
            $ErrorActionPreference = $prevErrorActionPreference;

            # Add details about this datasource to a hashmap;
            $dsListAfterCalculatingShrink[$ds.AssociatedReplica.PhysicalReplicaId] =
                @{Name = $ds.ToString("s", $null); ScSizeInGb = $currentSizeInGb; ShrinkableSizeInGb = $shrinkableSizeInGb }
        }
    }
}

# Sort the datasources in descending order of how much it can be shrunk
$dsListAfterCalculatingShrinkSorted = $dsListAfterCalculatingShrink.values | sort { $_.ShrinkableSizeInGb } -desc

# Print results
#write-output (" {0} {1} {2}" -f "Datasource".PadRight(100),"SC-Size(GB)".PadLeft(11),"CanBeShrunkBy(GB)".PadLeft(11))
write-host -ForegroundColor Cyan (" {0} {1} {2}" -f "Datasource".PadRight(100),"SC-Size(GB)".PadLeft(11),"CanBeShrunkBy(GB)".PadLeft(11))
write-host -ForegroundColor Cyan ------------------------------------------------------------------------------------------------------------------------------------
foreach ($ds in $dsListAfterCalculatingShrinkSorted)
{
    write-output (" {0} {1} {2}" -f $ds.Name.PadRight(100), $ds.ScSizeInGb.ToString().PadLeft(11), $ds.ShrinkableSizeInGb.ToString().PadLeft(11))
}

#end script

#-----------

How do I schedule a DPM script from Powershell?

$
0
0

Suppose you found or created one of those valuable scripts but want to run it on a schedule or even schedule itself. Whilst there is this wonderful Powershell Pack that includes a module to utilize the task scheduler from Powershell, this article uses the standard “Schtasks” utility. We assume some familiarity with the task scheduler, use “Schtasks /?” to find more information on its usage.

There are two things to pay attention to; the length of the schedule command and spaces in path names.

A command cannot exceed 260 characters. Running a Powershell command from the DPM binary path requires ~80 character script path, similar for the console initialization file and a few dozen for the complete “Schtasks” command. So we have a ~200 character command line leaving ample room for parameters you may need to pass to the scheduled script. Here are some ways to overcome that;

  • Put the command to schedule in a CMD file and schedule the CMD as command
  • Write script parameters to a file and read that file from inside the script rather than passing those on the command line 
  • Use the Powershell Pack which builds a task using multiple Powershell statements rather than a single command line (but requires installation of the Powershell Pack free download)
  • Reduce the command by facilitating Powershell requirements from within the script itself rather than using the “–PSconsolefile” parameter. This is demonstrated in the sample script below.
    Please note that a console file typically does more than just loading a required snap-in or module like the sample script does. Ensure that this is sufficient for the scheduled script. 

There is a challenge in scheduling commands with spaces in the path names or parameters.  The sample script is best used “as is” with regards to the amount of escaped quotes. These are necessary because quotes get removed during interpretation by the current Powershell, by the task scheduler and again by Powershell at execution time. This sample executes as ‘Local System’ which suites most situations but see also “Schtasks create /?” for other options.

To schedule itself run script with the –schedule switch as;
.\script.ps1 –schedule

To schedule another script run as;
.\script.ps1 –schedule  “<path>\ScriptToSchedule.Ps1”

param ([switch] $schedule, [string]$ScriptToSchedule=””)

# If the snapin is the only thing you need… load DPM snap-in regardless and clear the error
Add-PSSnapin -name Microsoft.DataProtectionManager.PowerShell -erroraction SilentlyContinue
$Error.Clear()

if ($schedule) {

# Note that we do not use –PSconsolefile because we loaded
# the required snap-in ourselves and have no other needs

if ($ScriptToSchedule –eq “”) {
$taskname = $myinvocation.mycommand.definition -replace '\W','_'
$thisscript = "`"`"`"`"powershell`"`"`" -noninteractive -nologo -command `"`"`"&{$($myinvocation.mycommand.definition)}`"`"`""
}
else {
if (!(Test-Path $scripttoschedule)) {Throw "File not found!";exit}
$taskname = $ScriptToSchedule -replace '\W','_'
$thisscript = "`"`"`"`"powershell`"`"`" -noninteractive -nologo -command `"`"`"&{$ScriptToSchedule}`"`"`""
}
$msg = $null
$msg = @(schtasks /create /F /TN $taskname /SC "DAILY" /RU "System" /ST 06:00 /TR "$thisscript")
if ($msg -inotmatch "SUCCESS") {Throw "ERROR: scheduler reported a failure"}
else {
schtasks /Query /TN "$taskname" /V /FO LIST
}
exit
}

Write-Host "Whatever the script is supposed to be doing goes here"

Having dealt with various conditions my personal favorite method is writing a parameter file and read the parameter file from within the scheduled task. This way you can easily stay below 260 characters and no special consideration or limitations on parameter data.

Space needed to migrate a disk

$
0
0

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.

image 
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. 

#begin script
#--------------
param([string] $global:Debug)
# 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 | Sort-Object -Property volumesetid -Unique))
       {
              #we use ds to take sizes from rather than selects and sum proper extents
              $ds = $dss | ? {$m.DatasourceId -eq $_.id}
              $datasource = @($disk.pgmember | ? {$m.volumesetid -eq $_.volumesetid})
              write-host
              if ($datasource.count -gt '1') {write-host "      Datasources below are co-located" -f yellow}
              foreach ($datasource1 in $datasource)
              {
                      $datasource2 = $dss | ? { $datasource1.datasourceid -eq $_.id}
                      write-host "     " $datasource2
              }
              $expr = "VolumeSetId='{0}' and usage = 2" -f $m.VolumeSetID, $vols.usage
              $RecoVolume = @($Vols.Select("$expr"))
              $RecoExpr = "Guidname='{0}'" -f $RecoVolume[0].GuidName
              $RecoExtents = @($extents.Select("$RecoExpr"))
              # 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  
              $expr = "VolumeSetId='{0}' and usage = 1" -f $m.VolumeSetID, $vols.usage
               $Replica = $Vols.Select("$expr")
              $expr = "guidname= '{0}'"  -f $replica[0].guidname
              $replica2 = $extents.select("$expr")
              foreach ($replica1 in $replica2)
              {
                      if ($debug -eq 'DEBUG')
                      {
                              write-host "         Replica volume Size  - $('{0,8:N2}'-f($replica1.extentsize/$GB)) GB - Replica on Disk $('{0,3}'-f($replica1.ntdisknumber)) - Volume GUID " $replica1.Guidname -f green
                      }
                      else
                      {
                              write-host "         Replica volume Size  - $('{0,8:N2}'-f($replica1.extentsize/$GB)) GB - Replica on Disk $('{0,3}'-f($replica1.ntdisknumber))" -f green
                      }

              }
              $expr = "VolumeSetId='{0}' and usage = 2" -f $m.VolumeSetID, $vols.usage
               $Recovery = @($Vols.Select("$expr"))
              $expr = "guidname= '{0}'"  -f $recovery[0].guidname
              $recovery2 = $extents.select("$expr")
              foreach ($recovery1 in $recovery2)
              {
                      if ($debug -eq 'debug')
                      {
                              write-host "         Recovery volume size - $('{0,8:N2}' -f($recovery1.Extentsize/$GB)) GB - Recovey on Disk $('{0,3}' -f($recovery1.ntdisknumber)) - Volume GUID " $recovery1.Guidname -f green
                      }
                      else
                      {
                              write-host "         Recovery volume size - $('{0,8:N2}' -f($recovery1.Extentsize/$GB)) GB - Recovey on Disk $('{0,3}' -f($recovery1.ntdisknumber))" -f green
                      }
              }
       }
       return $size
}

$debug=$debug.ToUpper()
$version = "v1.5"
$global:MB = 1024 * 1024
$global:GB = $MB * 1024
$global:dpmservername = @(hostname)
$ConfirmPreference = 'None'

[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]
$extentlist = $db.ExecutewithResults(" select extent.diskid, extent.DiskOffset, extent.GuidName, extent.ExtentSize,disk.NTDiskNumber  from tbl_SPM_Extent extent join tbl_SPM_Disk disk on extent.DiskID = disk.DiskID").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) -f yellow
foreach ($d in $disks)
{
       write-host (" ==> Checking Datasources on Disk-{0}" -f $d.NtDiskID) -f cyan
       $MigSize = ( (GetMigSizeByDisk $d $extentlist $datasourcelist $Voltable)/ $GB).Tostring("N2")
       write-host; Write-Host (" ==> to migrate Disk-{0} you need $MigSize GB on the destination" -f $d.NtDiskID) -f cyan; write-host
}
Write-Host "`nDone!`n" -f white

#--------------
#end script

Replacing tape drive assignments

$
0
0

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

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

 

The search for DPM tape utilities stops here…

$
0
0

This solution combines several existing tape related scripts with enriched functionality. The short list is shown in the DPMTapeUtil user guide illustration on the right. You can download the script and user guide from here, provided “as is” no rights or warranties implied.

This script is updated to also copy recovery points to disk and to copy only the latest recovery point across media to disk!

The “DPMTapeUtil.Ps1” script performs a variety of tape related functions such as; report recovery points, start inventory, mark free, erase, eject, re-catalog, rescan library,  run a one-off backup and more… These functions can be used individually or in combinations, interactively on the DPM server or scheduled on multiple DPM servers. Tape selection and scheduling are controlled through simple command definitions. For instance to erase tapes that are ‘Recyclable’ every Sunday at 04:00 AM;

-tapeerase –schedule “Enable|Weekly|Sun|04:00” 

This only works with tapes DPM can understand, to erase tapes with an unsupported block size, see this companion post.

Why or when would you use this?

Although the DPM UI has good multi-select features, selecting a larger collection of tapes to perform the same action through this script can be more convenient. This is particularly true with good criteria such as; commonality in displayed label or barcode, a timespan or particular state the tapes can have. For instance; all tapes in all libraries across multiple servers with expired data, or that are offsite ready, or have written less than or at least certain amount of data and so forth…

The UI does not produce raw data about recovery points or tapes that can be easily imported in Excel or other program to process further. Obviously a UI does not return information for automation. This script returns object collections you can use in your own scripts such as selected tapes, triggered jobs, created output files….

Executing multiple actions on the same set of tapes, for instance mark free, erase and eject can be cumbersome when individual steps take a long time and must complete before the next step can be executed. Such activities often also need to happen on predictable times or conditions were this script can be used to automate that. This script can schedule itself using a simplified “Task Manager” specification as shown above that creates jobs on one or more DPM servers running the desired functions.

You would typically not use this script for ad-hoc activities which are just as easily if not easier done through the UI.

Full link: http://cid-b03306b628ab886f.office.live.com/self.aspx/.Public/DPMTapeUtil.zip 

Viewing all 119 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>