Skip to content

Commit 2d83610

Browse files
tcsimersonrkennedy
authored andcommitted
Clientbackup script
ClientBackup.ps1 is a PowerShell script designed to backup a Windows client using a command line specified policy name and API key. Didn't exactly fit into the directory structure so put in powershell directory.
1 parent 7cace45 commit 2d83610

File tree

2 files changed

+386
-0
lines changed

2 files changed

+386
-0
lines changed

recipes/powershell/ClientBackup.ps1

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
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 speicfy 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+
if ( $verbose ) {
110+
Write-Host "Base URI = $basepath"
111+
Write-Host "Looking back $days2lookback days for previous backups"
112+
Write-Host
113+
}
114+
115+
#####################################################################
116+
# Getting the policy details
117+
#####################################################################
118+
$uri = $basepath + "/config/policies/"+$policy
119+
if ( $verbose ) {
120+
Write-Host "Getting $policy policy details"
121+
Write-Host "Using URI $uri"
122+
}
123+
124+
$headers = @{
125+
"Authorization" = $apikey
126+
"X-NetBackup-Policy-Use-Generic-Schema" = "true"
127+
}
128+
129+
$response = Invoke-WebRequest `
130+
-Uri $uri `
131+
-Method GET `
132+
-Body $query_params `
133+
-ContentType $content_type `
134+
-Headers $headers
135+
136+
if ($response.StatusCode -ne 200)
137+
{
138+
throw "Unable to get the list of Netbackup images!"
139+
}
140+
141+
# Converting JSON output into PowerShell object format
142+
$content = (ConvertFrom-Json -InputObject $response)
143+
144+
# Determining backup frequency for full backup and getting
145+
# the full and incr schedule names
146+
for ( $i=0; $i -lt $content.data.attributes.policy.schedules.count; $i++ ) {
147+
if ( $content.data.attributes.policy.schedules[$i].schedulename -eq "FULL" ) {
148+
$fullfrequency = $content.data.attributes.policy.schedules[$i].frequencyseconds
149+
$fullschedule = $content.data.attributes.policy.schedules[$i].schedulename
150+
}
151+
if ( $content.data.attributes.policy.schedules[$i].schedulename -like "INCR" ) {
152+
$incrfrequency = $content.data.attributes.policy.schedules[$i].frequencyseconds
153+
$incrschedule = $content.data.attributes.policy.schedules[$i].schedulename
154+
}
155+
}
156+
157+
if ( $verbose ) {
158+
Write-Host "Incremental schedule $incrschedule frequency is $incrfrequency seconds"
159+
Write-Host "Full schedule $fullschedule frequency is $fullfrequency seconds"
160+
Write-Host
161+
}
162+
163+
#####################################################################
164+
# Get NetBackup Images from last days2lookback (30 default) days for this client
165+
#####################################################################
166+
$uri = $basepath + "/catalog/images"
167+
if ( $verbose ) {
168+
Write-Host "Looking for most recent backup images to see what kind of backup to run"
169+
Write-Host "Using URI $uri "
170+
}
171+
172+
$headers = @{
173+
"Authorization" = $apikey
174+
}
175+
176+
# Note that currentDate and lookbackDate are DateTime objects while
177+
# backupTimeStart and backupTimeEnd are string date in ISO 8601 format
178+
# using Zulu (Greenwich Mean Time) time: YYYY-MM-DDThh:mm:ssZ
179+
# Date/Time format example: November 13, 1967 at 3:22:00 PM = 1967-11-13T15:22:00Z
180+
# Getting current date
181+
$a = Get-Date
182+
$currentDate=$a.ToUniversalTime()
183+
$backupTimeEnd = (Get-Date -format s -date $currentDate) + "Z"
184+
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 and backupTime le $backupTimeEnd"
193+
"filter" = "clientName eq '$clientname'"
194+
}
195+
if ( $verbose ) {
196+
Write-Host "backupTimeEnd = $backupTimeEnd"
197+
Write-Host "backupTimeStart = $backupTimeStart"
198+
}
199+
200+
$response = Invoke-WebRequest `
201+
-Uri $uri `
202+
-Method GET `
203+
-Body $query_params `
204+
-ContentType $content_type `
205+
-Headers $headers
206+
207+
if ($response.StatusCode -ne 200)
208+
{
209+
throw "Unable to get the list of Netbackup images!"
210+
}
211+
212+
#Write-Host "response=$response"
213+
#Write-Host "Response JSON"
214+
#$response | ConvertFrom-Json | ConvertTo-Json
215+
216+
# Convert the JSON output into PowerShell object format
217+
$content = (ConvertFrom-Json -InputObject $response)
218+
219+
# Converting the JSON data for the image attributes into an array for looping through
220+
$imageinfo = %{$content.data.attributes}
221+
#Write-Host "Image info JSON"
222+
#$imageinfo | ConvertTo-Json
223+
#Get-Member -InputObject $imageinfo
224+
225+
# Setting values to validation variables
226+
$schedulerun = "none"
227+
$fulltime = "no"
228+
$incrtime = "no"
229+
230+
# Looping through all the images found for this client looking for most recent
231+
# full and incr backup image. Image data is listed in date descending order, i.e.,
232+
# newest to oldest. We just need to capture the first instance of either backup type
233+
# Handling 3 scenarios of returned images counts:
234+
# 1 image doesn't create an array of objects so need to process
235+
# 2 or more images create array of objects to process in a loop
236+
if ( $content.meta.pagination.count -eq 1 ) {
237+
if ( $imageinfo.scheduleName -eq "FULL" ) {
238+
$fulltime= [datetime]::Parse($imageinfo.backuptime)
239+
} else {
240+
$incrtime= [datetime]::Parse($imageinfo.backuptime)
241+
}
242+
} else {
243+
for ( $i=0; $i -lt $content.meta.pagination.count; $i++ ) {
244+
# Can skip if we've identified that we don't need to run any backups
245+
if ( $fulltime -ne "no" -AND $incrtime -ne "no" ) {
246+
continue
247+
} elseif ( $imageinfo[$i].scheduleName -eq "FULL" ) {
248+
$fulltime = [datetime]::Parse($imageinfo[$i].backuptime)
249+
} elseif ( $imageinfo[$i].scheduleName -eq "INCR" ) {
250+
$incrtime = [datetime]::Parse($imageinfo[$i].backuptime)
251+
}
252+
}
253+
}
254+
255+
# Define the full and incr window by subtracting the schedule frequency from
256+
# the current time.
257+
$fullwindow=$currentDate.AddSeconds(-$fullfrequency)
258+
$incrwindow=$currentDate.AddSeconds(-$incrfrequency)
259+
260+
# Now, run through the logic to determine what kind of backup to run
261+
if ( $fulltime -eq "no" ) {
262+
# No recent backup images found for this client, run full backup
263+
$schedulerun = "FULL"
264+
} elseif ( $fullwindow -ge $fulltime ) {
265+
# Found a FULL backup older than current full window
266+
$schedulerun = "FULL"
267+
} elseif ( $fulltime -ne "no" -AND $incrtime -eq "no" ) {
268+
# Full backup found but less than window and no incremental
269+
$schedulerun = "INCR"
270+
} elseif ( $incrwindow -ge $incrtime ) {
271+
# Full backup less than window and incremental older than window
272+
$schedulerun = "INCR"
273+
} else {
274+
$schedulerun = "none"
275+
}
276+
277+
if ( $verbose ) {
278+
Write-Host "schedulerun=$schedulerun"
279+
Write-Host "fulltime=$fulltime"
280+
Write-Host "incrtime=$incrtime"
281+
Write-Host "fullwindow=$fullwindow"
282+
Write-Host "incrwindow=$incrwindow"
283+
}
284+
285+
# If schedulerun is equal to none, then skip running anything
286+
if ( $schedulerun -eq "none" ) {
287+
Write-Host "Too soon to take a backup"
288+
exit
289+
}
290+
291+
# Running this in testing mode which means we don't want to run a backup,
292+
# just see what wwould be run
293+
if ( $testmode ) {
294+
exit
295+
}
296+
297+
#####################################################################
298+
# Launch the backup now
299+
#####################################################################
300+
$uri = $basepath + "/admin/manual-backup"
301+
if ( $verbose ) {
302+
Write-Host "Launching the backup now"
303+
Write-Host "Using URI $uri"
304+
}
305+
306+
$headers = @{
307+
"Authorization" = $apikey
308+
}
309+
310+
$backup_params = @{
311+
data = @{
312+
type = "backupRequest"
313+
attributes = @{
314+
policyName = $policy
315+
scheduleName = $schedulerun
316+
clientName = $clientname
317+
}
318+
}
319+
}
320+
321+
$body = ConvertTo-Json -InputObject $backup_params
322+
323+
$response = Invoke-WebRequest `
324+
-Uri $uri `
325+
-Method POST `
326+
-Body $body `
327+
-ContentType $content_type `
328+
-Headers $headers
329+
330+
if ($response.StatusCode -ne 202)
331+
{
332+
# Backup job did not start successfully
333+
"API StatusCode = "+$response.StatusCode
334+
#Write-Host $response.errorResponse
335+
#$content = (ConvertFrom-Json -InputObject $response)
336+
#"NetBackup error code = "+$content.errorResponse.errorCode
337+
#"NetBackup error message ="+$content.errorResponse.errorMessage
338+
throw "Unable to start the backup for "+$clientname+" with schedule "+$schedulerun+" for policy "+$policy
339+
}
340+
341+
if ( $verbose ) {
342+
Write-Host "Backup $schedulerun successfully started"
343+
}

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)