-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathBootstrap.ps1
More file actions
195 lines (168 loc) · 7.31 KB
/
Bootstrap.ps1
File metadata and controls
195 lines (168 loc) · 7.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
param (
# Params allow for manually launching the script for debugging
[Parameter(Mandatory = $false)]
[string]$JobId = $null,
[Parameter(Mandatory = $false)]
[string]$SessionId = $null
)
function FinishBootstrap {
param(
[switch]$Failed
)
if ($config.logging.enabled) {
Stop-Logging
if ($newLogfile) {
# Rename log file to include the job name.
try {
Rename-Item -Path $logFile -NewName "$(Split-Path $newLogfile -Leaf)" -ErrorAction Stop
}
catch {
Write-Output "ERROR: Failed to rename log file: $_" | Out-File $logFile -Append
}
}
}
if ($Failed) {
exit 1
}
else {
exit 0
}
}
# Import modules
Import-Module Veeam.Backup.PowerShell -DisableNameChecking
Import-Module "$PSScriptRoot\resources\Logger.psm1"
Import-Module "$PSScriptRoot\resources\JsonValidator.psm1"
Import-Module "$PSScriptRoot\resources\VBRSessionInfo.psm1"
$IsDebug = $false
if ($JobId -and -not $SessionId) {
Write-Output 'INFO: JobId is provided but not SessionId. Attempting to retrieve the last session ID for the job.'
$SessionId = (Get-VBRBackupSession | Where-Object {$_.JobId -eq $JobId} | Sort-Object EndTimeUTC -Descending | Select-Object -First 1).Id.ToString()
if ($null -eq $SessionId) {
Write-Output 'ERROR: Failed to retrieve the session ID for the provided job ID. Please check the job ID.'
FinishBootstrap -Failed
}
}
elseif ($SessionId -and -not $JobId) {
Write-Output 'INFO: SessionId is provided but not JobId. Attempting to retrieve the last job ID for the session.'
$JobId = (Get-VBRBackupSession -Id $SessionId | Sort-Object EndTimeUTC -Descending | Select-Object -First 1).JobId.ToString()
if ($null -eq $JobId) {
Write-Output 'ERROR: Failed to retrieve the job ID for the provided session ID. Please check the session ID.'
FinishBootstrap -Failed
}
}
if ($JobId -and $SessionId) {
Write-Output 'INFO: JobId and SessionId found. Using them to start the script.'
$IsDebug = $true
}
# Set vars
$configFile = "$PSScriptRoot\config\conf.json"
$date = (Get-Date -UFormat %Y-%m-%d_%T).Replace(':', '.')
$logFile = "$PSScriptRoot\log\$($date)_Bootstrap.log"
$idRegex = '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}'
$supportedTypes = 'Backup', 'EpAgentBackup', 'Replica', 'BackupToTape', 'FileToTape'
# Start logging to file
Start-Logging -Path $logFile
# Log version
Write-LogMessage -Tag 'INFO' -Message "Version: $(Get-Content "$PSScriptRoot\resources\version.txt" -Raw)"
# Retrieve configuration.
## Pull config to PSCustomObject
$config = Get-Content -Raw $configFile | ConvertFrom-Json # TODO: import config from param instead of later as file. Can then improve logging flow.
# Stop logging and remove log file if logging is disable in config.
if (-not $config.logging.enabled) {
Stop-Logging
Remove-Item $logFile -Force -ErrorAction SilentlyContinue
}
## Pull raw config and format for later.
## This is necessary since $config as a PSCustomObject was not passed through correctly with Start-Process and $powershellArguments.
$configRaw = (Get-Content -Raw $configFile).Replace('"', '\"').Replace("`n", '').Replace("`t", '').Replace(' ', ' ')
## Test config.
$validationResult = Test-JsonValid -JsonPath $configFile -SchemaPath "$PSScriptRoot\config\schema.json"
if ($validationResult.IsValid) {
Write-LogMessage -Tag 'INFO' -Message 'Configuration validated successfully.'
}
else {
Write-LogMessage -Tag 'ERROR' -Message "Failed to validate configuration: $($validationResult.Message)"
}
if ($IsDebug) {
Write-LogMessage -Tag 'INFO' -Message "JobId: $JobId"
Write-LogMessage -Tag 'INFO' -Message "SessionId: $SessionId"
}
else {
Write-LogMessage -Tag 'INFO' -Message 'Attempting to retrieve job ID and session ID from the parent process.'
# Get the command line used to start the Veeam session.
$parentPid = (Get-CimInstance Win32_Process -Filter "processid='$PID'").parentprocessid.ToString()
$parentCmd = (Get-CimInstance Win32_Process -Filter "processid='$parentPID'").CommandLine
# Get the Veeam job and session IDs
$JobId = ([regex]::Matches($parentCmd, $idRegex)).Value[0]
$SessionId = ([regex]::Matches($parentCmd, $idRegex)).Value[1]
}
# Get the Veeam job details and hide warnings to mute the warning regarding deprecation of the use of some cmdlets to get certain job type details.
# At time of writing, there is no alternative way to discover the job time.
Write-LogMessage -Tag 'INFO' -Message 'Getting VBR job details'
$job = Get-VBRJob -WarningAction SilentlyContinue | Where-Object {$_.Id.ToString() -eq $JobId}
if ($job) {
$JobType = $job.JobType
}
else {
# Can't locate non-tape job so check if it's a tape job
Write-LogMessage -Tag 'DEBUG' -Message "Job with ID $JobId not found in VBR jobs. Checking for tape jobs."
$job = Get-VBRTapeJob -WarningAction SilentlyContinue | Where-Object {$_.Id.ToString() -eq $JobId}
if ($job) {
$JobType = $job.Type
}
else {
Write-LogMessage -Tag 'ERROR' -Message "Job with ID $JobId not found in tape jobs. Exiting."
FinishBootstrap -Failed
}
}
# Get the session information and name.
Write-LogMessage -Tag 'INFO' -Message 'Getting VBR session information'
try {
$sessionInfo = Get-VBRSessionInfo -SessionId $SessionId -JobId $JobId -JobType $JobType
}
catch {
Write-LogMessage -Tag 'ERROR' -Message "Failed to retrieve session information: $_"
FinishBootstrap -Failed
}
$jobName = $sessionInfo.JobName
$vbrSessionLogger = $sessionInfo.Session.Logger
$vbrLogEntry = $vbrSessionLogger.AddLog('[VeeamNotify] Parsing job & session information...')
# Quit if job type is not supported.
if ($JobType -notin $supportedTypes) {
Write-LogMessage -Tag 'ERROR' -Message "Job type '$($JobType)' is not supported."
FinishBootstrap -Failed
}
Write-LogMessage -Tag 'INFO' -Message "Bootstrap script for Veeam job '$jobName' (job $JobId session $SessionId) - Session & job detection complete."
# Set log file name based on job
## Replace spaces if any in the job name
if ($jobName -match ' ') {
$logJobName = $jobName.Replace(' ', '_')
}
else {
$logJobName = $jobName
}
$newLogfile = "$PSScriptRoot\log\$($date)-$($logJobName).log"
# Build argument string for the alert sender script.
$powershellArguments = "-NoProfile -File $PSScriptRoot\AlertSender.ps1", `
"-JobId `"$JobId`"", `
"-SessionId `"$SessionId`"", `
"-JobType `"$JobType`"", `
"-Config `"$configRaw`"", `
"-Logfile `"$newLogfile`""
$vbrSessionLogger.UpdateSuccess($vbrLogEntry, '[VeeamNotify] Parsed job & session information.') | Out-Null
# Start a new new script in a new process with some of the information gathered here.
# This allows Veeam to finish the current session faster and allows us gather information from the completed job.
try {
$powershellExePath = (Get-Command -Name 'powershell.exe' -ErrorAction Stop).Path
Write-LogMessage -Tag 'INFO' -Message 'Launching AlertSender.ps1...'
$vbrLogEntry = $vbrSessionLogger.AddLog('[VeeamNotify] Launching Alert Sender...')
Start-Process -FilePath "$powershellExePath" -Verb runAs -ArgumentList $powershellArguments -WindowStyle hidden -ErrorAction Stop
Write-LogMessage -Tag 'INFO' -Message 'AlertSender.ps1 launched successfully.'
$vbrSessionLogger.UpdateSuccess($vbrLogEntry, '[VeeamNotify] Launched Alert Sender.') | Out-Null
}
catch {
Write-LogMessage -Tag 'ERROR' -Message "Failed to launch AlertSender.ps1: $_"
$vbrSessionLogger.UpdateErr($vbrLogEntry, '[VeeamNotify] Failed to launch Alert Sender.', "Please check the log: $newLogfile") | Out-Null
FinishBootstrap -Failed
}
FinishBootstrap