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
+ }
0 commit comments