add support for external, removable drive backup
- select backup source by drive label, device name, or serial number - fix forget policy to be safe for multiple drives (group by host,tags) - tag each backup source with drive/source name
This commit is contained in:
83
backup.ps1
83
backup.ps1
@@ -17,6 +17,51 @@ $Script:ResticStateRepositoryInitialized = $null
|
||||
$Script:ResticStateLastMaintenance = $null
|
||||
$Script:ResticStateLastDeepMaintenance = $null
|
||||
$Script:ResticStateMaintenanceCounter = $null
|
||||
|
||||
# Returns all drive letters which exactly match the serial number, drive label, or drive name of
|
||||
# the input parameter. Returns all drives if no input parameter is provided.
|
||||
# inspiration: https://stackoverflow.com/questions/31088930/combine-get-disk-info-and-logicaldisk-info-in-powershell
|
||||
function Get-Drives {
|
||||
Param($ID)
|
||||
|
||||
foreach($disk in Get-CimInstance Win32_Diskdrive) {
|
||||
$diskMetadata = Get-Disk | Where-Object { $_.Number -eq $disk.Index } | Select-Object -First 1
|
||||
$partitions = Get-CimAssociatedInstance -ResultClassName Win32_DiskPartition -InputObject $disk
|
||||
|
||||
foreach($partition in $partitions) {
|
||||
|
||||
$drives = Get-CimAssociatedInstance -ResultClassName Win32_LogicalDisk -InputObject $partition
|
||||
|
||||
foreach($drive in $drives) {
|
||||
|
||||
$volume = Get-Volume |
|
||||
Where-Object { $_.DriveLetter -eq $drive.DeviceID.Trim(":") } |
|
||||
Select-Object -First 1
|
||||
|
||||
if(($diskMetadata.SerialNumber.trim() -eq $ID) -or
|
||||
($disk.Caption -eq $ID) -or
|
||||
($volume.FileSystemLabel -eq $ID) -or
|
||||
($null -eq $ID)) {
|
||||
|
||||
[PSCustomObject] @{
|
||||
DriveLetter = $drive.DeviceID
|
||||
Number = $disk.Index
|
||||
Label = $volume.FileSystemLabel
|
||||
Manufacturer = $diskMetadata.Manufacturer
|
||||
Model = $diskMetadata.Model
|
||||
SerialNumber = $diskMetadata.SerialNumber.trim()
|
||||
Name = $disk.Caption
|
||||
FileSystem = $volume.FileSystem
|
||||
PartitionKind = $diskMetadata.PartitionStyle
|
||||
Drive = $drive
|
||||
Partition = $partition
|
||||
Disk = $disk
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# restore backup state from disk
|
||||
function Get-BackupState {
|
||||
@@ -123,19 +168,39 @@ function Invoke-Backup {
|
||||
|
||||
Write-Output "[[Backup]] Start $(Get-Date)" | Tee-Object -Append $SuccessLog
|
||||
$return_value = $true
|
||||
$drive_count = $BackupSources.Count
|
||||
$starting_location = Get-Location
|
||||
ForEach ($item in $BackupSources.GetEnumerator()) {
|
||||
|
||||
# Get the source drive letter and set as the root path
|
||||
# Get the source drive letter or identifier and set as the root path
|
||||
$root_path = $item.Key
|
||||
$tag = $item.Key
|
||||
|
||||
# Avoid storing the drive letter in the backup path if only backing up a single drive
|
||||
# FIXME: this doesn't really work. "C:\" still gets stored
|
||||
if($drive_count -eq 1) {
|
||||
Set-Location $root_path
|
||||
$root_path = "."
|
||||
$vss_option = "--use-fs-snapshot"
|
||||
|
||||
# Test if root path is a valid path, if not assume it is an external drive identifier
|
||||
if(-not (Test-Path $root_path)) {
|
||||
# attempt to find a drive letter associated with the identifier provided
|
||||
$drives = Get-Drives $root_path
|
||||
if($drives.Count -gt 1) {
|
||||
Write-Output "[[Backup]] Fatal error - external drives with more than one partition are not currently supported." | Tee-Object -Append $SuccessLog | Tee-Object -Append $ErrorLog
|
||||
return $false
|
||||
}
|
||||
elseif ($drives.Count -eq 0) {
|
||||
# TODO: Silently fails if an entire drive is missing. This is good for occasionally mounted external drives, but bad for
|
||||
# drives that are always expected to be here. May want to make this an optional error.
|
||||
Write-Output "[[Backup]] Warning - backup path $root_path not found." | Tee-Object -Append $SuccessLog #| Tee-Object -Append $ErrorLog
|
||||
# $return_value = $false
|
||||
continue
|
||||
}
|
||||
|
||||
$root_path = Join-Path $drives[0].DriveLetter ""
|
||||
|
||||
# disable VSS / file system snapshot for external drives
|
||||
# TODO: would be best to just test for VSS compatibility on the drive, rather than assume it won't work
|
||||
$vss_option = $null
|
||||
}
|
||||
|
||||
Write-Output "[[Backup]] Start $(Get-Date) [$tag]" | Tee-Object -Append $SuccessLog
|
||||
|
||||
# Build the new list of folders from settings (if there are any)
|
||||
$folder_list = New-Object System.Collections.Generic.List[System.Object]
|
||||
@@ -150,11 +215,13 @@ function Invoke-Backup {
|
||||
}
|
||||
|
||||
# Launch Restic
|
||||
& $ResticExe backup $folder_list --use-fs-snapshot --exclude-file=$WindowsExcludeFile --exclude-file=$LocalExcludeFile 3>&1 2>> $ErrorLog | Tee-Object -Append $SuccessLog
|
||||
& $ResticExe backup $folder_list $vss_option --tag "$tag" --exclude-file=$WindowsExcludeFile --exclude-file=$LocalExcludeFile 3>&1 2>> $ErrorLog | Tee-Object -Append $SuccessLog
|
||||
if(-not $?) {
|
||||
Write-Output "[[Backup]] Completed with errors" | Tee-Object -Append $ErrorLog | Tee-Object -Append $SuccessLog
|
||||
$return_value = $false
|
||||
}
|
||||
|
||||
Write-Output "[[Backup]] End $(Get-Date) [$tag]" | Tee-Object -Append $SuccessLog
|
||||
}
|
||||
|
||||
Set-Location $starting_location
|
||||
|
||||
@@ -12,7 +12,7 @@ $GlobalRetryAttempts = 4
|
||||
|
||||
# maintenance configuration
|
||||
$SnapshotMaintenanceEnabled = $true
|
||||
$SnapshotRetentionPolicy = @("--group-by", "host", "--keep-daily", "30", "--keep-weekly", "52", "--keep-monthly", "24", "--keep-yearly", "10")
|
||||
$SnapshotRetentionPolicy = @("--group-by", "host,tags", "--keep-daily", "30", "--keep-weekly", "52", "--keep-monthly", "24", "--keep-yearly", "10")
|
||||
$SnapshotPrunePolicy = @("--max-unused", "1%")
|
||||
$SnapshotMaintenanceInterval = 7
|
||||
$SnapshotMaintenanceDays = 30
|
||||
@@ -30,3 +30,6 @@ $BackupSources["C:\"] = @(
|
||||
#$BackupSources["D:\"] = @(
|
||||
# 'Software'
|
||||
#)
|
||||
#$BackupSources["DRIVE_LABEL_NAME_OR_SERIAL_NUMBER"] = @(
|
||||
# 'FolderName'
|
||||
#)
|
||||
|
||||
Reference in New Issue
Block a user