Skip to content

Commit 5de3584

Browse files
authored
Merge pull request #81 from VeritasOS/clientbackup
Clientbackup script
2 parents 6f8283a + fcc1cd8 commit 5de3584

3 files changed

Lines changed: 627 additions & 0 deletions

File tree

Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
<#
2+
.SYNOPSIS
3+
This sample script demonstrates the use of NetBackup REST API for launching a manual backup from a Windows client system
4+
.DESCRIPTION
5+
This script will query the master server for policy information and existing client backup images. If the latest full backup
6+
is older than the frequency defined within the policy schedule a full backup will be launched; otherwise, an incremental will
7+
be performed.
8+
.EXAMPLE
9+
.\ClientBackup.ps1 -p "ExampleClientBackup-Win" -k "AybRCz3UE_YOpCFD7_5mzQQfJsRXj_pN6WXLA7boX4EAuKD_kwBfXWQ5bFNWDiuJ"
10+
#>
11+
12+
<#
13+
Requirements and comments for running this script
14+
* Tested with PowerShell 5.1 but should work with PowerSell 3.0 or later
15+
* Tested with NetBackup 8.3
16+
* NetBackup client software already installed, configured and tested
17+
* A policy must be defined on the master server with the following details
18+
* Policy type must be MS-Windows
19+
* At least 2 schedules define with no backup windows
20+
* one full
21+
* one incremental
22+
* Client name added to Clients tab
23+
* Use command line parameters to specify the following parameters
24+
* -policy (to reference above policy)
25+
* -apikey (generated through NetBackup web UI)
26+
* API key uesr must have following privileges assigned to it's role:
27+
* Minimum specific privileges:
28+
* Global -> NetBackup management -> NetBackup images -> View
29+
* Global -> Protection -> Policies -> View
30+
* Global -> Protection -> Policies -> Manual Backup
31+
* PowerShell Execution Policy needs to be opened
32+
#>
33+
34+
35+
param (
36+
[string]$p = $(throw "Please specify the policy name using -p parameter."),
37+
[string]$k = $(throw "Please specify the password using -k parameter."),
38+
[switch]$v = $false,
39+
[switch]$t = $false
40+
)
41+
$policy=$p
42+
$apikey=$k
43+
$verbose=$v
44+
$testmode=$t
45+
46+
#####################################################################
47+
# Initial Setup
48+
# Note: This allows self-signed certificates and enables TLS v1.2
49+
#####################################################################
50+
51+
function InitialSetup()
52+
{
53+
# Allow self-signed certificates
54+
if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy')
55+
{
56+
Add-Type -TypeDefinition @"
57+
using System.Net;
58+
using System.Security.Cryptography.X509Certificates;
59+
public class TrustAllCertsPolicy : ICertificatePolicy {
60+
public bool CheckValidationResult(
61+
ServicePoint srvPoint, X509Certificate certificate,
62+
WebRequest request, int certificateProblem) {
63+
return true;
64+
}
65+
}
66+
"@
67+
[System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy
68+
69+
# Force TLS v1.2
70+
try {
71+
if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') {
72+
[Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12
73+
}
74+
}
75+
catch {
76+
Write-Host $_.Exception.InnerException.Message
77+
}
78+
}
79+
}
80+
81+
InitialSetup
82+
83+
#####################################################################
84+
# Looking in the registry for NetBackup details
85+
#####################################################################
86+
$a = Get-ItemPropertyValue -path HKLM:\SOFTWARE\VERITAS\NetBackup\CurrentVersion\Config -name Server
87+
$b = $a.Split(" ")
88+
if ( $b -is [system.array] ) {
89+
$nbmaster=$b[0]
90+
} else {
91+
$nbmaster=$b
92+
}
93+
$clientname = Get-ItemPropertyValue -path HKLM:\SOFTWARE\VERITAS\NetBackup\CurrentVersion\Config -name Client_Name
94+
95+
if ( $verbose ) {
96+
Write-Host "Looking at local NetBackup configuration for client name and master server"
97+
Write-Host "nbmaster=$nbmaster"
98+
Write-Host "clientname=$clientname"
99+
Write-Host
100+
}
101+
102+
#####################################################################
103+
# Global Variables
104+
#####################################################################
105+
$port = 1556
106+
$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup"
107+
$content_type = "application/vnd.netbackup+json;version=4.0"
108+
$days2lookback = 30
109+
$fullname = "FULL"
110+
$incrname = "INCR"
111+
if ( $verbose ) {
112+
Write-Host "Base URI = $basepath"
113+
Write-Host "Looking back $days2lookback days for previous backups"
114+
Write-Host
115+
}
116+
117+
#####################################################################
118+
# Getting the policy details
119+
#####################################################################
120+
$uri = $basepath + "/config/policies/"+$policy
121+
if ( $verbose ) {
122+
Write-Host "Getting $policy policy details"
123+
Write-Host "Using URI $uri"
124+
}
125+
126+
$headers = @{
127+
"Authorization" = $apikey
128+
"X-NetBackup-Policy-Use-Generic-Schema" = "true"
129+
}
130+
131+
$response = Invoke-WebRequest `
132+
-Uri $uri `
133+
-Method GET `
134+
-Body $query_params `
135+
-ContentType $content_type `
136+
-Headers $headers
137+
138+
if ($response.StatusCode -ne 200)
139+
{
140+
throw "Unable to get the list of Netbackup images!"
141+
}
142+
143+
# Converting JSON output into PowerShell object format
144+
$content = (ConvertFrom-Json -InputObject $response)
145+
146+
# Determining backup frequency for full backup and getting
147+
# the full and incr schedule names
148+
for ( $i=0; $i -lt $content.data.attributes.policy.schedules.count; $i++ ) {
149+
if ( $content.data.attributes.policy.schedules[$i].schedulename -eq $fullname ) {
150+
$fullfrequency = $content.data.attributes.policy.schedules[$i].frequencyseconds
151+
$fullschedule = $content.data.attributes.policy.schedules[$i].schedulename
152+
}
153+
if ( $content.data.attributes.policy.schedules[$i].schedulename -like $incrname ) {
154+
$incrfrequency = $content.data.attributes.policy.schedules[$i].frequencyseconds
155+
$incrschedule = $content.data.attributes.policy.schedules[$i].schedulename
156+
}
157+
}
158+
159+
if ( $verbose ) {
160+
Write-Host "Incremental schedule $incrschedule frequency is $incrfrequency seconds"
161+
Write-Host "Full schedule $fullschedule frequency is $fullfrequency seconds"
162+
Write-Host
163+
}
164+
165+
#####################################################################
166+
# Get NetBackup Images from last days2lookback (30 default) days for this client
167+
#####################################################################
168+
$uri = $basepath + "/catalog/images"
169+
if ( $verbose ) {
170+
Write-Host "Looking for most recent backup images to see what kind of backup to run"
171+
Write-Host "Using URI $uri "
172+
}
173+
174+
$headers = @{
175+
"Authorization" = $apikey
176+
}
177+
178+
# Note that currentDate and lookbackDate are DateTime objects while
179+
# backupTimeStart and backupTimeEnd are string date in ISO 8601 format
180+
# using Zulu (Greenwich Mean Time) time: YYYY-MM-DDThh:mm:ssZ
181+
# Date/Time format example: November 13, 1967 at 3:22:00 PM = 1967-11-13T15:22:00Z
182+
# Getting current date
183+
$a = Get-Date
184+
$currentDate=$a.ToUniversalTime()
185+
# Set starting date to 30 days from current date
186+
$lookbackDate = (Get-Date).AddDays(-$days2lookback)
187+
$backupTimeStart = (Get-Date -format s -date $lookbackDate) + "Z"
188+
189+
$query_params = @{
190+
"page[limit]" = 50 # This changes the default page size to 50
191+
# The following filter variable adds a filter to only show for this client in past 30 days
192+
"filter" = "clientName eq '$clientname' and backupTime ge $backupTimeStart"
193+
}
194+
if ( $verbose ) {
195+
Write-Host "backupTimeStart = $backupTimeStart"
196+
}
197+
198+
$response = Invoke-WebRequest `
199+
-Uri $uri `
200+
-Method GET `
201+
-Body $query_params `
202+
-ContentType $content_type `
203+
-Headers $headers
204+
205+
if ($response.StatusCode -ne 200)
206+
{
207+
throw "Unable to get the list of Netbackup images!"
208+
}
209+
210+
# Convert the JSON output into PowerShell object format
211+
$content = (ConvertFrom-Json -InputObject $response)
212+
213+
# Converting the JSON data for the image attributes into an array for looping through
214+
$imageinfo = %{$content.data.attributes}
215+
216+
# Setting values to validation variables
217+
$schedulerun = "none"
218+
$fulltime = 0
219+
$incrtime = 0
220+
221+
# Looping through all the images found for this client looking for most recent
222+
# full and incr backup image. We just need to capture the first instance of either backup type
223+
# Handling 3 scenarios of returned images counts:
224+
# 1 image doesn't create an array of objects so need to process
225+
# 2 or more images create array of objects to process in a loop
226+
if ( $content.meta.pagination.count -eq 1 ) {
227+
if ( $imageinfo.scheduleName -eq $fullname ) {
228+
$fulltime = (Get-Date $imageinfo.backuptime)
229+
} elseif ( $imageinfo.scheduleName -eq $incrname ) {
230+
$incrtime= (Get-Date $imageinfo.backuptime)
231+
}
232+
} else {
233+
for ( $i=0; $i -lt $content.meta.pagination.count; $i++ ) {
234+
# Depending upon the schedule name, what to perform
235+
if ( $imageinfo[$i].schedulename -eq $fullname ) {
236+
$a = Get-Date $imageinfo[$i].backuptime
237+
if ( $a -gt $fulltime ) {
238+
$fulltime=$a
239+
}
240+
} elseif ( $imageinfo[$i].schedulename -eq $incrname ) {
241+
$a = Get-Date $imageinfo[$i].backuptime
242+
if ( $a -gt $incrtime ) {
243+
$incrtime=$a
244+
}
245+
}
246+
}
247+
}
248+
249+
250+
# Define the full and incr window by subtracting the schedule frequency from
251+
# the current time.
252+
$fullwindow=$currentDate.AddSeconds(-$fullfrequency)
253+
$incrwindow=$currentDate.AddSeconds(-$incrfrequency)
254+
255+
# Now, run through the logic to determine what kind of backup to run
256+
if ( $fulltime -eq 0 ) {
257+
# No recent backup images found for this client, run full backup
258+
$schedulerun = $fullname
259+
} elseif ( $fullwindow -ge $fulltime ) {
260+
# Found a FULL backup older than current full window
261+
$schedulerun = $fullname
262+
} elseif ( $fulltime -ne 0 -AND $incrtime -eq 0 ) {
263+
# Full backup found but less than window and no incremental
264+
$schedulerun = $incrname
265+
} elseif ( $incrwindow -ge $incrtime ) {
266+
# Full backup less than window and incremental older than window
267+
$schedulerun = $incrname
268+
} else {
269+
$schedulerun = "none"
270+
}
271+
272+
if ( $verbose ) {
273+
Write-Host "schedulerun=$schedulerun"
274+
Write-Host "fulltime=$fulltime"
275+
Write-Host "incrtime=$incrtime"
276+
Write-Host "fullwindow=$fullwindow"
277+
Write-Host "incrwindow=$incrwindow"
278+
}
279+
280+
# If schedulerun is equal to none, then skip running anything
281+
if ( $schedulerun -eq "none" ) {
282+
Write-Host "Too soon to take a backup"
283+
exit
284+
}
285+
286+
# Running this in testing mode which means we don't want to run a backup,
287+
# just see what wwould be run
288+
if ( $testmode ) {
289+
exit
290+
}
291+
292+
#####################################################################
293+
# Launch the backup now
294+
#####################################################################
295+
$uri = $basepath + "/admin/manual-backup"
296+
if ( $verbose ) {
297+
Write-Host "Launching the backup now"
298+
Write-Host "Using URI $uri"
299+
}
300+
301+
$headers = @{
302+
"Authorization" = $apikey
303+
}
304+
305+
$backup_params = @{
306+
data = @{
307+
type = "backupRequest"
308+
attributes = @{
309+
policyName = $policy
310+
scheduleName = $schedulerun
311+
clientName = $clientname
312+
}
313+
}
314+
}
315+
316+
$body = ConvertTo-Json -InputObject $backup_params
317+
318+
$response = Invoke-WebRequest `
319+
-Uri $uri `
320+
-Method POST `
321+
-Body $body `
322+
-ContentType $content_type `
323+
-Headers $headers
324+
325+
if ($response.StatusCode -ne 202)
326+
{
327+
# Backup job did not start successfully
328+
"API StatusCode = "+$response.StatusCode
329+
#Write-Host $response.errorResponse
330+
#$content = (ConvertFrom-Json -InputObject $response)
331+
#"NetBackup error code = "+$content.errorResponse.errorCode
332+
#"NetBackup error message ="+$content.errorResponse.errorMessage
333+
throw "Unable to start the backup for "+$clientname+" with schedule "+$schedulerun+" for policy "+$policy
334+
}
335+
336+
if ( $verbose ) {
337+
Write-Host "Backup $schedulerun successfully started"
338+
}

recipes/powershell/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
### ClientBackup: initiate policy based backup from client
2+
3+
These scripts are designed to initiate a backup from the client using a specified policy and API key. The program logic in the script works like this:
4+
5+
* Look at the local NetBackup configuration for the client name and the master server
6+
* Using the /netbackup/config/policies API, get the details of the specified policy
7+
* Look for the presence of an INCR and FULL schedule
8+
* Get backup frequency of the INCR and FULL schedules
9+
* Using /netbackup/catalog/images API, get the last 30 days of backup images for this client
10+
* Compare the last backups to the schedule frequencies to determine what level (FULL or INCR) backup to run.
11+
* Initiate the backup using the /netbackup/admin/manual-backup API
12+
13+
#### Disclaimer
14+
15+
These scripts are only meant to be used as a reference. If you intend to use them in production, use them at your own risk.
16+
17+
#### Pre-requisites
18+
19+
* Tested with NetBackup 8.3
20+
* For Windows clients, tested with the following
21+
* PowerShell version 5.1
22+
* Windows Server 2016
23+
* NetBackup client software already installed on client
24+
* Policy defined on master server with following specifics
25+
* Scheduled name Full defined as full backup type
26+
* Schedule named Incr defined as incremental backup type
27+
* Source clients added to Clients
28+
* API user with key generated associated with role having these permissions
29+
* Global -> NetBackup management -> NetBackup backup images -> View
30+
* Global -> Protection -> Policies -> View
31+
* Global -> Protection -> Policies -> Manual backup
32+
33+
#### Executing ClientBackup.ps1
34+
35+
This PowerShell script is not signed so you may encounter errors trying to run this. You can use the PowerShell cmdlet [Set-Execution Policy](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7) to adjust your environment to allow running unsigned PowerShell scripts.
36+
37+
To execute, run the command like this:
38+
39+
```
40+
ClientBackup.ps1 -p "POLICY" -k "APIKEY" [-v]
41+
```
42+
43+
Replace POLICY with the NetBackup policy to use and replace APIKEY with the API key generated through the NetBackup web UI. The optional -v option will provide additional information during the processing. Without the -v option, ClientBackup.ps1 will run silently.

0 commit comments

Comments
 (0)