# # Restic Windows Backup - Installation Script # # =========== start configuration =========== # # load restic configuration parmeters (destination, passwords, etc.) $SecretsScript = Join-Path $PSScriptRoot "secrets.ps1" # load backup configuration variables $ConfigScript = Join-Path $PSScriptRoot "config.ps1" # initialize secrets . $SecretsScript # initialize config . $ConfigScript # apply global configuration $ResticExe = Join-Path $InstallPath $ExeName $LogPath = Join-Path $InstallPath "logs" # make LASTEXITCODE global to enable error checking for Invoke-Expression commands $global:LASTEXITCODE=0 # =========== end configuration =========== # # download restic if(-not (Test-Path $ResticExe)) { $url = $null if([Environment]::Is64BitOperatingSystem){ $url = "https://github.com/restic/restic/releases/download/v0.17.3/restic_0.17.3_windows_amd64.zip" } else { $url = "https://github.com/restic/restic/releases/download/v0.17.3/restic_0.17.3_windows_386.zip" } try { $output = Join-Path $InstallPath "restic.zip" Invoke-WebRequest -Uri $url -OutFile $output Expand-Archive -LiteralPath $output $InstallPath Remove-Item $output Get-ChildItem *.exe | Rename-Item -NewName $ExeName } catch { Write-Error "[[Install]] restic.exe download failed. Check errors and resolve: $_" exit 1 } } # Apply global paramters to $ResticExe, after the $ResticExe has been downloaded/confirmed to exist if(-not [String]::IsNullOrEmpty($GlobalParameters)) { $ResticExe = "$ResticExe $GlobalParameters" } # Invoke restic self-update to check for a newer version # This is enabled by default unless configuration disables self-update if ([String]::IsNullOrEmpty($SelfUpdateEnabled) -or ($SelfUpdateEnabled -eq $true)) { Invoke-Expression "$ResticExe self-update" if($LASTEXITCODE) { Write-Warning "[[Update]] Restic self-update failed. Check errors and resolve." } } # Create log directory if it doesn't exit if(-not (Test-Path $LogPath)) { New-Item -ItemType Directory -Force -Path $LogPath | Out-Null Write-Output "[[Init]] Created log directory: $LogPath" } # Create the local exclude file if(-not (Test-Path $LocalExcludeFile)) { New-Item -Type File -Path $LocalExcludeFile | Out-Null } # Initialize the restic repository Invoke-Expression "$ResticExe --verbose init" if($LASTEXITCODE) { Write-Warning "[[Init]] Repository initialization failed. Check errors and resolve." } else { Write-Output "[[Init]] Repository successfully initialized." } # Scheduled Windows Task Scheduler to run the backup $backup_task_name = "Restic Backup" $backup_task = Get-ScheduledTask $backup_task_name -ErrorAction SilentlyContinue if($null -eq $backup_task) { try { $task_action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-ExecutionPolicy Bypass -NonInteractive -NoLogo -NoProfile -Command ".\backup.ps1; exit $LASTEXITCODE"' -WorkingDirectory $InstallPath $task_user = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest $task_settings = New-ScheduledTaskSettingsSet -RestartCount 4 -RestartInterval (New-TimeSpan -Minutes 15) -ExecutionTimeLimit (New-TimeSpan -Days 3) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -DontStopOnIdleEnd -MultipleInstances IgnoreNew -IdleDuration 0 -IdleWaitTimeout 0 -StartWhenAvailable -RestartOnIdle $task_trigger = New-ScheduledTaskTrigger -Daily -At 4:00am Register-ScheduledTask $backup_task_name -Action $task_action -Principal $task_user -Settings $task_settings -Trigger $task_trigger | Out-Null Write-Output "[[Scheduler]] Backup task scheduled." } catch { Write-Error "[[Scheduler]] Setting up backup task schedule failed: $_" } } else { Write-Warning "[[Scheduler]] Backup task not scheduled: there is already a task with the name '$backup_task_name'." } # Install NuGet and Send-MailKitMessage module (by force) if ($PSVersionTable.PSVersion.Major -eq 5) { Install-PackageProvider -Name NuGet -Force } Install-Module Send-MailKitMessage -Repository PSGallery -Scope AllUsers -Force