]> git.p6c8.net - dsmonrot.git/blob - dsmonrot.ps1
c0ee230622cea573cbd3bdca81315f6036d80aa2
[dsmonrot.git] / dsmonrot.ps1
1 # DSMonRot
2 # Script for rotating Drive Snapshot backups monthly
3 #
4 # Author: Patrick Canterino <patrick@patrick-canterino.de>
5 # WWW: https://www.patrick-canterino.de/
6 # https://github.com/pcanterino/dsmonrot
7 # License: 2-Clause BSD License
8 #
9 # Drive Snapshot is copyright by Tom Ehlert
10 # http://www.drivesnapshot.de/
11
12 # Config
13
14 # Path to backup directory
15 [String]$backupDir = "Z:\"
16 # Keep backup for this amount of months (excluding the current month),
17 # -1 for indefinite
18 [Int32]$keepMonths = 2
19 # Rotate BEFORE the beginning of a full backup (default is after a successful
20 # full backup)
21 # WARNING: If this option is set to $True and the full backup fails you could
22 # have NO backup
23 $rotateBeforeBackup = $False
24 # Path to Drive Snapshot
25 [String]$dsPath = "C:\Users\Patrick\Desktop\DSMonRot\snapshot.exe"
26 # Path to Drive Snapshot log file (specify only the file name if you set
27 # $dsLogFileToBackup to $True)
28 #[String]$dsLogFile = "C:\Users\Patrick\Desktop\DSMonRot\snapshot.log"
29 [String]$dsLogFile = "snapshot.log"
30 # Set to $True if you want to put the log file of Drive Snapshot into the same
31 # directory as the backup
32 [Boolean]$dsLogFileToBackup = $True
33 # Disks to backup, see http://www.drivesnapshot.de/en/commandline.htm
34 [String]$disksToBackup = "HD1:1"
35 # Path to DSMonRot log file
36 [String]$logFile = "C:\Users\Patrick\Desktop\DSMonRot\dsmonrot.log"
37
38 # Map network share to this drive letter, comment out if you don't want to use it
39 [String]$smbDrive = "Z"
40 # Path to network share
41 [String]$smbPath = "\\192.168.0.3\ds"
42 # User and password for connecting to network share, comment out if you don't want to use it
43 # (for example if you want to pass current Windows credentials)
44 [String]$smbUser = "patrick"
45 [String]$smbPassword = ""
46
47 # Send an email if an error occured
48 [Boolean]$emailOnError = $True
49 # From address of email notification
50 [String]$emailFromAddress = "alarm@test.local"
51 # To address of email notification
52 [String]$emailToAddress = "patrick@test.local"
53 # Subject of email notification
54 [String]$emailSubject = "DSMonRot on $env:computername"
55 # Mail server
56 [String]$emailMailserver = "localhost"
57 # SMTP Port
58 [Int32]$emailPort = 25
59 # Use SSL?
60 [Boolean]$emailSSL = $False
61 # Use SMTP Auth?
62 [Boolean]$emailAuth = $False
63 # SMTP Auth User
64 [String]$emailUser = ""
65 # SMTP Auth Password
66 [String]$emailPassword = ""
67
68 # End of config
69
70 $dsAdditionalArgs = @("--UseVSS")
71
72 # Allow SMTP with SSL and SMTP Auth
73 # see: http://petermorrissey.blogspot.de/2013/01/sending-smtp-emails-with-powershell.html
74 function Send-Email([String]$body) {
75 Write-Host "Sending email: $emailToAddress, $body"
76
77 try {
78 $smtp = New-Object System.Net.Mail.SmtpClient($emailMailServer, $emailPort)
79
80 $smtp.EnableSSL = $emailSSL
81
82 if($emailAuth) {
83 $smtp.Credentials = New-Object System.Net.NetworkCredential($emailUser, $emailPassword)
84 }
85
86 $smtp.Send($emailFromAddress, $emailToAddress, $emailSubject, $body)
87 }
88 catch {
89 Write-Host "Could not send email: $_.Exception.Message"
90 }
91 }
92
93 function Rotate-Backup {
94 if($keepMonths -lt 0) {
95 return
96 }
97
98 Write-Host "Rotating"
99
100 $keepMonthsCount = $keepMonths
101
102 Get-ChildItem $backupDir -Directory | Where-Object {($_.Name -ne $currMonth) -and ($_.Name -match "^\d{4,}-\d{2}$")} | Sort-Object -Descending |
103 Foreach-Object {
104 Write-Host $_ "=>" $_.FullName
105
106 if($keepMonthsCount -ge 0) {
107 $keepMonthsCount--
108 }
109
110 if($keepMonthsCount -eq -1) {
111 Write-Host "Deleting $_"
112 Remove-Item -Recurse -Force $_.FullName
113 }
114 }
115 }
116
117 $startTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
118 Write-Host "Started at $startTime"
119
120 $errorMessages = @()
121
122 $smbConnected = $False
123 $success = $False
124 $isDiff = $False
125 $dsCommand = ""
126
127 if($smbDrive) {
128 try {
129 Write-Host "Connecting network drive"
130
131 if($smbUser -and $smbPassword) {
132 Write-Host "With credentials"
133
134 $secSmbPassword = $smbPassword | ConvertTo-SecureString -asPlainText -Force
135 $smbCredential = New-Object System.Management.Automation.PSCredential($smbUser, $secSmbPassword)
136
137 New-PSDrive -Name $smbDrive -PSProvider "FileSystem" -Root $smbPath -Credential $smbCredential -Persist -ErrorAction Stop | Out-Null
138 }
139 else {
140 Write-Host "Without credentials"
141
142 New-PSDrive -Name $smbDrive -PSProvider "FileSystem" -Root $smbPath -Persist -ErrorAction Stop | Out-Null
143 }
144
145 $smbConnected = $True
146 }
147 catch {
148 Write-Host "Could not connect to network drive $smbDrive`: $_.Exception.Message"
149 $errorMessages += "Could not connect to network drive $smbDrive`: $_.Exception.Message"
150 }
151 }
152
153 if(!(Test-Path $backupDir)) {
154 Write-Host "Directory $backupDir does not exist!"
155 $errorMessages += "Directory $backupDir does not exist!"
156 }
157
158 if($errorMessages.Count -eq 0) {
159 $currMonth = Get-Date -format "yyyy-MM"
160 $currDay = Get-Date -format "yyyy-MM-dd"
161
162 Write-Host $currMonth
163
164 $backupTarget = $backupDir + "\" + $currMonth
165 $backupTargetFull = $backupTarget + "\" + "Full"
166
167 $backupTargetDiff = $backupTarget + "\" + "Diff-" + $currDay
168
169 Write-Host $backupTarget
170
171 if((Test-Path $backupTarget) -and (Test-Path $backupTargetFull) -and (Test-Path "$backupTargetFull\*.hsh")) {
172 Write-Host "Differential backup"
173
174 $isDiff = $True
175
176 if(!(Test-Path $backupTargetDiff)) {
177 Write-Host "Creating directory $backupTargetDiff"
178
179 try {
180 New-Item -ItemType directory -Path $backupTargetDiff -ErrorAction Stop | Out-Null
181 }
182 catch {
183 Write-Host "Could not create directory $backupTargetDiff`: $_.Exception.Message"
184 $errorMessages += "Could not create directory $backupTargetDiff`: $_.Exception.Message"
185 }
186
187 if($errorMessages.Count -eq 0) {
188 $dsLogPath = if($dsLogFileToBackup) { "$backupTargetDiff\$dsLogFile" } else { $dsLogFile }
189
190 $dsArgs = @($disksToBackup, "--logfile:$dsLogPath", "$backupTargetDiff\`$disk.sna", "-h$backupTargetFull\`$disk.hsh") + $dsAdditionalArgs
191 Write-Host $dsPath ($dsArgs -join " ")
192
193 $dsCommand = "$dsPath $dsArgs"
194
195 & $dsPath $dsArgs
196
197 if($LastExitCode -ne 0) {
198 Write-Host "Drive Snapshot failed to backup! Exit code: $LastExitCode"
199 $errorMessages += "Drive Snapshot failed to backup! Exit code: $LastExitCode"
200 }
201 else {
202 $success = $True
203 }
204 }
205 }
206 else {
207 Write-Host "Directory $backupTargetDiff already exists!"
208 $errorMessages += "Directory $backupTargetDiff already exists!"
209 }
210 }
211 else {
212 Write-Host "Full backup"
213
214 if(!(Test-Path $backupTarget)) {
215 Write-Host "Creating directory $backupTarget"
216
217 try {
218 New-Item -ItemType directory -Path $backupTarget -ErrorAction Stop | Out-Null
219 }
220 catch {
221 Write-Host "Could not create directory $backupTarget`: $_.Exception.Message"
222 $errorMessages += "Could not create directory $backupTarget`: $_.Exception.Message"
223 }
224 }
225
226 if($errorMessages.Count -eq 0) {
227 if(!(Test-Path $backupTargetFull)) {
228 Write-Host "Creating directory $backupTargetFull"
229
230 try {
231 New-Item -ItemType directory -Path $backupTargetFull -ErrorAction Stop | Out-Null
232 }
233 catch {
234 Write-Host "Could not create directory $backupTargetFull`: $_.Exception.Message"
235 $errorMessages += "Could not create directory $backupTargetFull`: $_.Exception.Message"
236 }
237 }
238
239 if($errorMessages.Count -eq 0) {
240 if($rotateBeforeBackup) {
241 Rotate-Backup
242 }
243
244 $dsLogPath = if($dsLogFileToBackup) { "$backupTargetFull\$dsLogFile" } else { $dsLogFile }
245
246 $dsArgs = @($disksToBackup, "--logfile:$dsLogPath", "$backupTargetFull\`$disk.sna") + $dsAdditionalArgs
247 Write-Host $dsPath ($dsArgs -join " ")
248
249 $dsCommand = "$dsPath $dsArgs"
250
251 & $dsPath $dsArgs
252
253 if($LastExitCode -ne 0) {
254 Write-Host "Drive Snapshot failed to backup! Exit code: $LastExitCode"
255 $errorMessages += "Drive Snapshot failed to backup! Exit code: $LastExitCode"
256 }
257 else {
258 $success = $True
259 }
260
261 if($rotateBeforeBackup -eq $False -and $success -eq $True) {
262 Rotate-Backup
263 }
264 }
265 }
266 }
267 }
268
269 if($smbConnected) {
270 Write-Host "Disconnecting network drive"
271
272 try {
273 Remove-PSDrive $smbDrive -ErrorAction Stop
274 }
275 catch {
276 Write-Host "Could not disconnect network drive $smbDrive`: $_.Exception.Message"
277 $errorMessages += "Could not disconnect network drive $smbDrive`: $_.Exception.Message"
278 }
279 }
280
281 if($emailOnError -and $errorMessages.Count -gt 0) {
282 $emailBody = "This is DSMonRot on $env:computername, started at $startTime.`n"
283 $emailBody += "An error occured while performing a backup. Below are the error messages and some status information.`n`n"
284 $emailBody += "Backup directory: $backupDir`n"
285 $emailBody += "Differential backup: $isDiff`n"
286 $emailBody += "Backup successful: $success`n"
287 $emailBody += "Drive Snapshot command: $dsCommand`n`n"
288 $emailBody += ($errorMessages -join "`n")
289
290 Send-Email ($emailBody)
291 }
292
293 $endTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
294 Write-Host "Ended at $endTime"

patrick-canterino.de