Restic 备份工具使用指南(Windows Server 2019 适配版)

Restic 备份工具使用指南(Windows Server 2019 适配版)

Restic 同样是 Windows 上可用的单二进制、客户端加密、全局去重快照备份工具。在 Windows Server 2019 中,最关键的差异有三点:通过任务计划程序实现无人值守 、用 VSS 快照处理被锁定文件 、用 NTFS ACL 严格控制密码文件权限。

一、安装(单二进制,推荐 winget 或手动放置)

方式 A:winget(推荐,便于后续升级)

以管理员身份打开 PowerShell:

powershell 复制代码
winget install restic.restic

安装后确认版本:

powershell 复制代码
restic version

方式 B:手动下载 .exe

从 restic releases 下载 restic_*_windows_amd64.zip,解压后将 restic.exe 放入 C:\Program Files\Restic\,并将该目录加入系统 PATH。不要直接丢进 System32,便于后续版本管理与审计。

方式 C:我共享的百度网盘地址下载

链接: https://pan.baidu.com/s/1_-lRGoG_VOMa_SQwRqnyLg?pwd=hpdy 提取码: hpdy

目录结构

text 复制代码
C:\Program Files\Restic\
├── logs\                       # 存放每日备份、清理和校验的日志
├── exclude.txt                 # 备份排除列表(如临时文件、缓存目录等)
├── init.log                    # 首次执行 restic init 时的输出日志
├── restic.exe                  # Restic 主程序
├── restic_backup_passwd.txt    # Restic 仓库密码文件(需严格控制 NTFS ACL 权限)
└── restic-backup.ps1           # 自动化备份与发信通知的主 PowerShell 脚本

二、环境变量与密码文件(Windows 下务必用密码文件,不用明文环境变量)

Restic 在 Windows 上同样支持环境变量,但生产环境优先使用密码文件。PowerShell 中设置当前会话的临时环境变量可用于测试:

powershell 复制代码
$env:RESTIC_REPOSITORY = "D:\Backup\restic-repo"
$env:RESTIC_PASSWORD_FILE = "C:\ProgramData\Restic\password.txt"

如果要持久化到系统级(不推荐用于密码),可用:

powershell 复制代码
[Environment]::SetEnvironmentVariable("RESTIC_REPOSITORY", "D:\Backup\restic-repo", "Machine")

密码文件权限(关键) :Windows 没有 chmod 600,必须用 NTFS ACL 限制为仅运行备份的身份可读 。假设任务以 SYSTEM 运行,则只允许 SYSTEM 和 Administrators 读取:

powershell 复制代码
$acl = Get-Acl "C:\ProgramData\Restic\password.txt"
$acl.SetAccessRuleProtection($true, $false)  # 禁用继承
$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) }
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM","Read","Allow")
$acl.AddAccessRule($rule)
$rule2 = New-Object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators","Read","Allow")
$acl.AddAccessRule($rule2)
Set-Acl "C:\ProgramData\Restic\password.txt" $acl

这样可避免普通用户或误操作进程读取密码。

仓库后端示例(Windows 路径写法) :

text 复制代码
# 本地目录
D:\Backup\restic-repo

# SFTP
sftp://user@192.168.1.100//backup/repo

# S3 兼容(MinIO / 阿里云 OSS / 华为 OBS)
s3:http://192.168.1.200:9000/restic-repo
s3:oss-cn-beijing.aliyuncs.com/bucket-name/repo

S3 场景还需额外设置凭证(建议同样用受限文件或仅在任务专用账户中设置):

powershell 复制代码
$env:AWS_ACCESS_KEY_ID     = "xxx"
$env:AWS_SECRET_ACCESS_KEY = "xxx"

三、初始化仓库(只执行一次)

powershell 复制代码
# 初始化 restic 仓库到 D:\backup\repo
restic init --repo "D:\backup\repo" --password-file "C:\ProgramData\Restic\password.txt"

# 示例1
restic init --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"

输出 created restic repository ... 即成功。仓库密码一旦丢失,所有备份永久无法恢复 ,建议用 restic key add 添加备用密钥并存放在安全位置。

四、核心备份:backup(Windows Server 2019 必须加 --use-fs-snapshot)

Linux 下可直接备份运行中的文件;Windows 上大量文件会被进程锁定(如数据库、IIS 日志、系统文件),不加 VSS 快照会遇到 Access is denied 或文件被跳过 。Restic 在 Windows 上支持 --use-fs-snapshot,通过卷影复制服务读取一致状态的文件。

基础备份命令(管理员 PowerShell) :

powershell 复制代码
restic backup C:\Data D:\AppData `
  --use-fs-snapshot `
  --repo "D:\jg_cpz\minio_backup" `
  --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" `
  --exclude-file "C:\ProgramData\Restic\exclude.txt" `
  --compression better `
  --tag server-data

常用参数(Windows 等价) :

text 复制代码
--use-fs-snapshot           # Windows 必加,处理锁定文件
--exclude C:\Data\tmp       # 排除目录
--exclude-file exclude.txt  # 批量排除,一行一个 Windows 路径
--compression better           # auto|off|fastest|better|max
--dry-run                    # 试运行,不写仓库
--host WS2019-DB01           # 手动指定主机名

示例:SQL Server 热备(不落地文件)

如果服务器上运行 SQL Server,可以用 sqlcmd 输出流直接管道给 restic,避免生成巨大的 .bak 临时文件:

powershell 复制代码
sqlcmd -S localhost -E -Q "BACKUP DATABASE [YourDB] TO DISK = 'NUL' WITH COPY_ONLY" |
  restic backup --stdin --tag mssql

注意:TO DISK = 'NUL' 不会产生真实文件,数据流直接进入 restic。需确保 sqlcmd 可用且执行账户有备份权限。

五、快照管理:snapshots / forget / prune

查看快照

powershell 复制代码
restic snapshots
restic snapshots --tag server-data
restic snapshots --host WS2019-DB01
restic snapshots latest

# 示例

restic snapshots --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"

# 输出结果:

D:\jg_cpz> restic snapshots --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"
repository 2086c998 opened (version 2, compression level auto)
ID        Time                 Host           Tags         Paths           Size
--------------------------------------------------------------------------------------
4d9d5fbb  2026-10-24 08:52:24  ecs-240e-0002  server-data  D:\minio        1.218 GiB
5e8acd11  2026-10-24 09:00:32  ecs-240e-0002  server-data  D:\jg_cpz\gdal  222.012 MiB
--------------------------------------------------------------------------------------
Timestamps shown in local time
2 snapshots


restic snapshots --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" latest

# 输出结果:

D:\jg_cpz> restic snapshots --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" latest
repository 2086c998 opened (version 2, compression level auto)
ID        Time                 Host           Tags         Paths           Size
--------------------------------------------------------------------------------------
5e8acd11  2026-10-24 09:00:32  ecs-240e-0002  server-data  D:\jg_cpz\gdal  222.012 MiB
--------------------------------------------------------------------------------------
Timestamps shown in local time
1 snapshots

自动清理旧快照

forget 只打删除标记,prune 才真正回收数据块。生产环境建议分两步执行,确认 forget 结果无误后再 prune:

powershell 复制代码
# forget 命令的作用是删除快照记录。注意,它不会立刻释放硬盘空间,它只是把备份的"目录"删了。
#--keep-daily 7:保留最近 7 天,每天的最后一个快照。
#--keep-weekly 4:保留最近 4 周,每周的最后一个快照。
#--keep-monthly 6:保留最近 6 个月,每个月的最后一个快照。
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6

restic prune

删掉指定快照

删除指定的 restic 快照,核心命令是 restic forget <快照ID>。这个操作分两步走:forget 负责删除快照的"记录",而 prune 负责真正释放被占用的磁盘空间。

🔍 第一步:找到要删除的快照 ID

首先,你需要列出所有快照,找到目标快照的 ID。

powershell 复制代码
restic -r "D:\jg_cpz\minio_backup" snapshots

# 示例:
D:\tmp> restic --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" snapshots

# 输出:
repository 2086c998 opened (version 2, compression level auto)
ID        Time                 Host           Tags         Paths           Size
--------------------------------------------------------------------------------------
4d9d5fbb  2026-10-24 08:52:24  ecs-240e-0002  server-data  D:\minio        1.218 GiB

5e8acd11  2026-10-24 09:00:32  ecs-240e-0002  server-data  D:\jg_cpz\gdal  222.012 MiB

fe28025e  2026-10-24 12:00:58  ecs-240e-0002  mysqbackup   D:\backup       62.101 GiB

de371bec  2026-10-24 14:02:34  ecs-240e-0002  server-data  D:\backup       63.536 GiB
                                                           D:\jg_cpz\gdal
                                                           D:\minio
--------------------------------------------------------------------------------------
Timestamps shown in local time
4 snapshots

# 示例:
D:\tmp> restic -r "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" snapshots

# 输出:

repository 2086c998 opened (version 2, compression level auto)
ID        Time                 Host           Tags         Paths           Size
--------------------------------------------------------------------------------------
4d9d5fbb  2026-10-24 08:52:24  ecs-240e-0002  server-data  D:\minio        1.218 GiB

5e8acd11  2026-10-24 09:00:32  ecs-240e-0002  server-data  D:\jg_cpz\gdal  222.012 MiB

fe28025e  2026-10-24 12:00:58  ecs-240e-0002  mysqbackup   D:\backup       62.101 GiB

de371bec  2026-10-24 14:02:34  ecs-240e-0002  server-data  D:\backup       63.536 GiB
                                                           D:\jg_cpz\gdal
                                                           D:\minio
--------------------------------------------------------------------------------------
Timestamps shown in local time
4 snapshots

执行后,你会看到一个列表,ID 列就是快照的唯一标识(通常是8位短ID)。

🗑️ 第二步:执行删除

这里有两种方式,你可以任选其一:

方式一:分两步执行(更安全,便于确认)

  1. 仅删除快照记录 :forget 命令只移除快照的引用,不立即释放空间。

    powershell 复制代码
    restic -r "D:\jg_cpz\minio_backup" forget <快照ID>
    
    # 示例:
    
    restic -r "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" forget 4d9d5fbb
  2. 释放磁盘空间 :接着运行 prune,它会扫描仓库,删除那些不再被任何快照引用的"孤儿"数据块。

    powershell 复制代码
    restic -r "D:\jg_cpz\minio_backup" prune
    
    # 示例:
    
    restic -r "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" prune

方式二:一步到位(推荐)

直接在 forget 命令后加上 --prune 参数,restic 会在删除快照后自动执行清理。

powershell 复制代码
restic -r "D:\jg_cpz\minio_backup" forget <快照ID> --prune

# 示例:

restic -r "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" forget fe28025e --prune

注意 :prune 会重打包仓库,不能与其他备份任务同时运行 ,否则会锁库报错。应安排在业务低峰期,且与

备份任务错开。

注意删除逻辑:如下两种情况

情况一:这个文件在其他保留的快照里也有(最常见)

结论:文件还在,可以恢复。

  • 原理 :假设你每天备份同一个文件 app.log。第一天快照A存了它,第二天快照B也存了它。restic 在底层只会存一份数据块,快照A和快照B都只是通过"指针"指向这份数据块。
  • 操作 :如果你用 forget 删除了快照A,并执行了 prune。restic 在清理时会发现:"虽然快照A没了,但快照B还在使用这份数据块",于是它会保留这份数据。
  • 结果:当你去恢复快照B时,这个文件完整无缺。

情况二:这个文件是"只属于"被删快照的(独有数据)

结论:一旦你执行了 prune,文件就被彻底物理删除了,无法恢复。

  • 原理 :假设你在快照A里存了一个文件 only_in_A.txt,后来你把这个文件从源目录删了,后续的快照B、C里都没有它。当你对快照A执行 forget 并加上 prune 后,restic 扫描发现没有任何快照还在引用这份数据,于是就会从硬盘上彻底抹掉它。
  • 结果:以后恢复快照B或C时,里面不会有这个文件;快照A的记录也已经没了。这份数据就"灰飞烟灭"了。

六、恢复:restore(最重要的功能)

恢复到目标目录

powershell 复制代码
restic restore <快照ID> --target D:\Restore

restic restore 4d9d5fbb --target D:\tmp --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"

只恢复单个目录或文件

powershell 复制代码
restic restore <快照ID> --target D:\Restore --include "/D/minio/data"

# 例如:

# 注意 --include "/D/minio/data"  的路径不能是:"\D\minio\data"

restic restore 4d9d5fbb --target D:\tmp --include "/D/minio/data" --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"

直接导出单个文件

powershell 复制代码
restic dump <快照ID> "/D/minio/config/minio.env" > D:\test.txt

# 示例:

restic dump 4d9d5fbb --repo "D:\jg_cpz\minio_backup1" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" "/D/minio/config/minio.env"> D:\tmp\minio.env

列出快照内文件

powershell 复制代码
restic ls <快照ID>

# 示例:
# 用 restic ls 命令看一眼快照 4d9d5fbb 的目录结构,确认 data 文件夹到底是以什么路径存储的。
restic ls 4d9d5fbb --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"

restic ls <快照ID> "/D/minio/config"

# 示例:
restic ls 4d9d5fbb --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" "/D/minio/config"

# 输出:

repository 2086c998 opened (version 2, compression level auto)
[0:00] 100.00%  4 / 4 index files loaded
snapshot 4d9d5fbb of [D:\minio] at 2026-10-24 08:52:24.1702605 +0800 CST by ECS-240E-0002\Administrator@ecs-240e-0002 filtered by [/D/minio/config]:
/D/minio/config
/D/minio/config/minio.env

全仓库搜索文件名

powershell 复制代码
restic find "filename.txt" <快照ID>

# 示例:
restic find "minio.env" 4d9d5fbb --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt" 

# 输出:
repository 2086c998 opened (version 2, compression level auto)
[0:00] 100.00%  4 / 4 index files loaded
Found matching entries in snapshot de371bec from 2026-10-24 14:02:34
/D/minio/config/minio.env

Found matching entries in snapshot 4d9d5fbb from 2026-10-24 08:52:24
/D/minio/config/minio.env

⚠️ Windows 恢复的重要限制 :Restic 在 Windows 上对文件 ACL 和所有者 的备份/恢复能力有限,部分版本虽已改进 SecurityDescriptor 支持,但仍需 Backup Operators 组成员或相应特权。如果恢复后出现权限异常,可能需要手动修正。

七、仓库校验(防静默损坏,运维必做)

磁盘静默损坏和 bit rot 无法肉眼发现,必须定期 check:

powershell 复制代码
restic check

# 示例:
restic check --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"

# 输出:
using temporary cache in C:\Users\ADMINI~1\AppData\Local\Temp\1\restic-check-cache-2435865498
create exclusive lock for repository
repository 2086c998 opened (version 2, compression level auto)
created new cache in C:\Users\ADMINI~1\AppData\Local\Temp\1\restic-check-cache-2435865498
load indexes
[0:00] 100.00%  4 / 4 index files loaded
check all packs
check snapshots, trees and blobs
[0:00] 100.00%  4 / 4 snapshots
no errors were found

更严格的完整数据校验(较慢):

powershell 复制代码
restic check --read-data

# 示例:
restic check --read-data --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"
# 输出:
using temporary cache in C:\Users\ADMINI~1\AppData\Local\Temp\1\restic-check-cache-1059252936
create exclusive lock for repository
repository 2086c998 opened (version 2, compression level auto)
created new cache in C:\Users\ADMINI~1\AppData\Local\Temp\1\restic-check-cache-1059252936
load indexes
[0:00] 100.00%  4 / 4 index files loaded
check all packs
check snapshots, trees and blobs
[0:00] 100.00%  4 / 4 snapshots
read all data
[0:40] 100.00%  120 / 120 packs
no errors were found

折中方案(随机抽样):

powershell 复制代码
restic check --read-data-subset 10%

# 示例:
restic check --read-data-subset 10% --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"
# 输出:
using temporary cache in C:\Users\ADMINI~1\AppData\Local\Temp\1\restic-check-cache-2999965827
create exclusive lock for repository
repository 2086c998 opened (version 2, compression level auto)
created new cache in C:\Users\ADMINI~1\AppData\Local\Temp\1\restic-check-cache-2999965827
load indexes
[0:00] 100.00%  4 / 4 index files loaded
check all packs
check snapshots, trees and blobs
[0:00] 100.00%  4 / 4 snapshots
read 10.0% of packfiles
[0:04] 100.00%  12 / 12 packs
no errors were found

最佳实践 :每周跑一次 check,失败触发告警。若备份中途中断导致 repository locked:

powershell 复制代码
restic unlock
# 示例:
restic unlock --repo "D:\jg_cpz\minio_backup" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"
# 输出:
repository 2086c998 opened (version 2, compression level auto)

八、跨仓库复制快照:copy(异地灾备 3-2-1)

将本地仓库快照同步到异地 OSS 或另一台服务器:

powershell 复制代码
restic copy --repo D:\Backup\restic-repo `
            --repo2 s3:http://192.168.1.200:9000/restic-repo `
            <快照ID>

# 示例:
restic copy --repo "D:\jg_cpz\minio_backup" `
            --repo2 s3:http://192.168.1.200:9000/restic-repo `
            5e8acd11 `
            --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"

注意:在运行 restic copy 命令之前,先在同一个 PowerShell 窗口里执行以下命令设置环境变量。这些变量只在当前窗口有效,关闭后即失效。

使用repo2 之前需要初始化:

powershell 复制代码
$env:AWS_ACCESS_KEY_ID = "你的AccessKey"
$env:AWS_SECRET_ACCESS_KEY = "你的SecretKey"
$env:AWS_DEFAULT_REGION = "us-east-1"  # MinIO 通常需要,可任意指定,但必须存在

# 使用前需要初始化

restic init --repo "s3:http://192.168.1.200:9000/restic-repo" --password-file "C:\Program Files\Restic\restic_backup_passwd.txt"

复制全部快照时省略 <快照ID>。copy 利用全局去重,只传输目标仓库缺失的数据块,不会重复上传相同内容。

九、自动化脚本 + 任务计划程序

Windows Server 2019 使用任务计划程序实现开机自启和定时备份,并且状态邮件通知。

脚本的核心逻辑是:每次运行先检测仓库是否已初始化,未初始化则执行 restic init;随后执行备份,并根据最终状态发送邮件。

powershell 复制代码
# C:\Program Files\Restic\restic-backup.ps1(管理员/SYSTEM 权限运行)
$ErrorActionPreference = "Stop"

# ========== 1. 基础配置 ==========
# ========== 性能参数 ==========
$env:RESTIC_PACK_SIZE = "128"      # 本地仓库建议 64~128
$env:RESTIC_REPOSITORY    = "D:\jg_backup"
$env:RESTIC_PASSWORD_FILE = "C:\Program Files\Restic\restic_backup_passwd.txt"
$env:EXCLUDE_FILE = "C:\Program Files\Restic\exclude.txt"
$backupPaths = @("D:\jg_cpz","D:\minio")
$RepoConfigFile = "D:\jg_backup\config"   # restic 仓库的标志性文件

$MailParams = @{
    SmtpServer = "smtp.qq.com"
    Port       = 587
    From       = "610152753@qq.com"
    To         = "qiaoshunlong@163.com"
    UseSsl     = $true
    Credential = New-Object System.Management.Automation.PSCredential(
        "610152753@qq.com",
        (ConvertTo-SecureString "你的16位QQ邮箱授权码" -AsPlainText -Force)
    )
}

# 引入 Mailozaurr
Import-Module Mailozaurr -ErrorAction Stop

# ========== 2. 辅助函数:发送邮件 ==========
function Send-BackupMail {
    param([string]$Subject, [string]$Body, [string]$Priority = "Normal")
    $mail = @{
        From     = $MailParams.From
        To       = $MailParams.To
        Subject  = $Subject
        Body     = $Body
        Priority = $Priority
        SmtpServer = $MailParams.SmtpServer
        Port       = $MailParams.Port
        UseSsl     = $MailParams.UseSsl
        Credential = $MailParams.Credential
    }
    try {
        Send-EmailMessage @mail -ErrorAction Stop
    } catch {
        # 邮件失败时写入本地日志,避免因邮件问题中断备份
        "邮件通知失败:$($_.Exception.Message)" | Out-File "C:\Program Files\Restic\mail-failure.log" -Append
    }
}

# ========== 3. 仅首次运行:初始化仓库 ==========
if (-not (Test-Path $RepoConfigFile)) {
    try {
        restic init --repo $env:RESTIC_REPOSITORY --password-file $env:RESTIC_PASSWORD_FILE 2>&1 | Out-File "C:\Program Files\Restic\init.log" -Append
        if ($LASTEXITCODE -eq 0) {
            Send-BackupMail -Subject "[Restic] 仓库初始化成功 $(hostname)" `
                -Body "仓库 $($env:RESTIC_REPOSITORY) 已初始化完成。`n时间:$(Get-Date)"
        } else {
            Send-BackupMail -Subject "[CRIT] [Restic] 仓库初始化失败 $(hostname)" `
                -Body "restic init 退出码 $LASTEXITCODE,请检查 init.log。" -Priority High
            exit 1   # 初始化失败则不继续备份
        }
    } catch {
        Send-BackupMail -Subject "[CRIT] [Restic] 仓库初始化异常 $(hostname)" `
            -Body $_.Exception.Message -Priority High
        exit 1
    }
}
# 初始化成功后,继续执行备份

# ========== 4. 执行备份 ==========
$ErrorActionPreference = "Continue"
# Restic 在备份前会并发统计文件数量和总大小,用于估算进度,这个扫描阶段在文件多时会产生大量额外 I/O,拖慢整体速度。加上 --no-scan 可以跳过这一阶段
$LogFile = "C:\Program Files\Restic\logs\backup-$(Get-Date -Format 'yyyyMMdd-HHmm').log"
restic backup $backupPaths `
  --use-fs-snapshot `
  --no-scan `
  -o vss.provider=MS `
  --repo $env:RESTIC_REPOSITORY `
  --password-file $env:RESTIC_PASSWORD_FILE `
  --exclude-file $env:EXCLUDE_FILE `
  --compression better `
  --tag server-data *>> $LogFile

$ret = $LASTEXITCODE

# ========== 5. 根据备份状态发送通知 ==========

# ========== 构造带日志的邮件正文 ==========
function Get-LogTail {
    param([string]$Path, [int]$Lines = 80)
    if (-not (Test-Path $Path)) { return "(日志文件不存在)" }
    $content = Get-Content -Path $Path -Tail $Lines -ErrorAction SilentlyContinue
    if (-not $content) { return "(日志为空)" }
    return ($content -join "`r`n")
}

# 清理旧快照(分两步,确认后再 prune)
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 *>> $LogFile
restic prune *>> $LogFile
restic check *>> $LogFile

$logTail = Get-LogTail -Path $LogFile -Lines 80

if ($ret -eq 0) {
    $subject = "[OK] [Restic] 备份成功 $(hostname)"
    $body = "备份完成。`n日志文件:$LogFile`n`n===== 末尾日志 =====`n$logTail"
    Send-BackupMail -Subject $subject -Body $body
}
elseif ($ret -eq 3) {
    $subject = "[WARN] [Restic] 备份部分文件失败 $(hostname)"
    $body = "退出码 3,快照已生成但部分文件被跳过。`n日志文件:$LogFile`n`n===== 末尾日志 =====`n$logTail"
    Send-BackupMail -Subject $subject -Body $body -Priority High
}
else {
    $subject = "[CRIT] [Restic] 备份失败 $(hostname)"
    $body = "退出码 $ret。`n日志文件:$LogFile`n`n===== 末尾日志 =====`n$logTail"
    Send-BackupMail -Subject $subject -Body $body -Priority High
    exit $ret
}

关键设计说明

① 初始化的幂等判断

Test-Path $RepoConfigFile 检查仓库根目录下是否存在 config 文件。restic init 成功后会生成该文件,因此这个判断比直接反复执行 restic init 更安全------后者在仓库已存在时会报错并退出。只有 config 不存在时才走初始化分支,满足"仅第一次运行"的要求。

② 初始化失败即终止

初始化失败后直接 exit 1,不再继续备份。因为仓库不可用时备份必然失败,继续执行只会产生无意义的错误日志。

③ 邮件通知的时机

脚本在三个关键节点发送邮件:初始化成功 / 失败 、备份成功 / 部分失败 / 完全失败 。邮件发送本身用 try/catch 包裹,即使 SMTP 服务器临时不可达,也不会中断备份流程,而是降级写入本地日志。

④ 优先级区分

备份成功用 Normal,警告和致命错误用 High,便于邮件客户端或后续告警规则做差异化处理。


创建任务计划程序任务(管理员 PowerShell)

Restic 在 Windows 上要完整利用 VSS 快照,任务身份需要具备 "作为服务登录" 和备份特权。最省事的做法是以 SYSTEM 运行,并勾选"使用最高权限运行"。

powershell 复制代码
$action  = New-ScheduledTaskAction -Execute "PowerShell.exe" `
  -Argument "-NoProfile -ExecutionPolicy Bypass -File `"C:\Program Files\Restic\restic-backup.ps1`""
$trigger = New-ScheduledTaskTrigger -Daily -At "23:00PM"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName "Restic Backup" -Action $action -Trigger $trigger -Principal $principal

也可在 GUI 的任务计划程序 中创建任务,触发器选"每天",操作指向 PowerShell 脚本,勾选**"使用最高权限运行"**,并在"常规"中选择"不管用户是否登录都要运行"。


部署提醒

  • Mailozaurr 安装 :在以 SYSTEM 运行的任务计划中,模块需要安装在系统级 路径,建议提前在管理员 PowerShell 中执行 Install-Module Mailozaurr -Scope AllUsers -Force。
  • 凭据安全 :示例中密码是明文,生产环境建议改用 Windows 凭据管理器 或加密的 CLIXML 文件读取 SMTP 密码,避免脚本泄露。
  • 初始化日志 :init.log 和备份日志分开存放,便于故障时快速区分是仓库创建问题还是备份执行问题。
相关推荐
DogDaoDao3 天前
Windows 双 Shell 全面对比:CMD 与 PowerShell 的技术剖析
windows·shell·测试·powershell·cmd·程序员开发
Vex2une5 天前
PowerShell 7.5新特性解析:跨平台自动化与AI集成实战指南
ai编程·powershell·安全合规·自动化脚本·.net 9·跨平台运维·ssh远程
螺蛳粉 螺蛳粉5 天前
Hadoop第四篇:把 DBA 的巡检清单变成一键体检:AI SSH 运维 Agent 实战 MySQL 篇
mysql·dba·主从复制·运维自动化·数据库巡检·ai运维·智能运维aiops
NC 王炸8 天前
AI 做的便签,换个浏览器就没了?加一个导出按钮,把数据带走
javascript·ai编程·数据备份·localstorage·txt导出
Vex2une12 天前
PowerShell 发展史:从命令行外壳到跨平台自动化引擎
windows·自动化·azure·powershell·vs code·脚本语言·dsc
Vex2une14 天前
PowerShell ISE 到 VS Code 迁移史:从集成脚本环境到现代编辑器工作流
windows·vscode·powershell·powershell ise·powershell 扩展·powershell 7·脚本编辑器
sqgzznl15 天前
电脑怎么设置实时保存?办公、设计文件双重防丢教程
电脑·数据存储·数据备份·文件备份·企业备份·网盘系统
Vex2une17 天前
Windows PowerShell 发展史:从命令行工具到自动化核心
windows·自动化运维·命令行·powershell·cmd·脚本语言·对象管道