改造前:全仓 6/6 个源文件在 5.1 上解析失败(README 却承诺支持 5.1)。原因是文件是无 BOM 的 UTF-8,而 5.1 没有 BOM 就按 ANSI 代码页解码源码,中文变乱码、全角问号吃掉引号,整块语法塌掉。 现在 28/28 个文件在 5.1 与 7 上都解析零错误,E2E 36 项在 5.1 上全绿。 顺带修掉一个被 5.1 掩盖的缺陷:带 [CmdletBinding()] 的脚本在 5.1 上,param() 默认值里 拿不到 $PSScriptRoot(实测为空串,7 上正常)。于是 Backup.ps1 / Restore.ps1 在 5.1 上不传 路径参数就报错退出 —— 而计划任务恰恰不传。E2E 之所以看不见,是因为它总是显式传路径。 8 处默认值全部移到 param() 之后的解析段,沿用本仓库对 -BackupDir 一直在用的写法。 新增三条可重放的约定,让编码不再是一次性动作: .gitattributes 接管行尾(本机 core.autocrlf=true,会把工作区改成 CRLF 制造伪 diff) .editorconfig 用 charset = utf-8-bom 锁住 BOM tools\Set-SourceEncoding.ps1 是规范化脚本,tools\Invoke-* 之外的任何改动之后都能重放 test.ps1 是唯一验收入口:Encode + Parse + Unit + Smoke + E2E,在 7 与 5.1 上各跑一遍 test.ps1 的 Encode 层直接检查"必须有 BOM"这条规则。加它的原因很实际:实测本仓库用的 编辑工具在保存时会悄悄去掉 BOM,而丢了 BOM 的文件只在 5.1 上出错、在 7 上完全正常, 没有这条检查就会一直漏过去。 已知未修(下一步处理):5.1 上 Unit 有 6 项、Smoke 有 1 项失败,全部源于测试夹具写 临时文件时没指定编码(5.1 的 Set-Content 默认 ANSI),与产品代码无关。
100 lines
4.5 KiB
PowerShell
100 lines
4.5 KiB
PowerShell
<#
|
||
BakNRet 配置文件。
|
||
|
||
优先级:命令行参数 > 本文件 > 代码内置默认值。
|
||
本文件缺失或某键缺失都直接用默认值,不会报错。
|
||
#>
|
||
@{
|
||
# 归档存放目录(相对路径按脚本所在目录解析)
|
||
BackupDir = 'Backups'
|
||
|
||
# 每次运行的日志目录(backup-<时间戳>.log / restore-<时间戳>.log)
|
||
LogDir = 'logs'
|
||
|
||
# 使用 -Snapshot 时留存带时间戳的副本
|
||
SnapshotDir = 'Backups\snapshots'
|
||
|
||
# 软件名录("软件名 -> 目录"映射表)。相对路径按本配置所在目录解析。
|
||
# BackupList.txt 里写软件名时靠它换成真实目录,归档名也取软件名。
|
||
SoftwareCatalog = 'SoftwareCatalog.psd1'
|
||
|
||
# 名录里写的目录不存在时,按 "<名>_*" / "<名>-*" 向下找几层做前缀补全
|
||
# (应对 legendary -> legendary_2.0.4 这类带后缀的目录)
|
||
CatalogMaxDepth = 5
|
||
|
||
# 低于这个剩余空间(GB)就告警;真正放不下某个条目时会直接跳过该条目
|
||
MinFreeSpaceGB = 5
|
||
|
||
# 归档写完后用 `7z t` 校验内容 CRC,失败则丢弃临时文件
|
||
VerifyArchive = $true
|
||
|
||
# 是否默认给所有归档计算 SHA256(大归档会明显变慢)
|
||
ComputeHash = $false
|
||
|
||
# 7z 压缩级别 0-9
|
||
CompressionLevel = 9
|
||
|
||
# 压缩工具的实时输出:live = 直接显示(默认);quiet = 抑制,只留日志与 manifest
|
||
ToolOutput = 'live'
|
||
|
||
# 是否默认给所有条目留存快照
|
||
Snapshot = @{
|
||
Enabled = $false
|
||
KeepCount = 3
|
||
KeepDays = 30
|
||
}
|
||
|
||
# 加密。默认关闭:一旦开启而口令丢失,备份就再也解不开。
|
||
#
|
||
# **本仓库不存放任何口令**,这里只记"去哪儿找":
|
||
# Encryption.Enabled = $true -> 所有条目都加密
|
||
# SoftwareCatalog.psd1 的 Slot 写 Encrypt = $true(如 OpenSSH)
|
||
# 或 BackupList.txt 里给单个条目加 :encrypt(如 Edge :encrypt)
|
||
#
|
||
# 口令本身按以下优先级获取(见 README「加密」):
|
||
# 1. -Password 命令行参数
|
||
# 2. $env:BAKNRET_PASSWORD
|
||
# 3. PasswordFile 指向的文件首行(文件必须在仓库之外)
|
||
# 4. 交互式询问(仅交互式会话;计划任务里不会停下来等输入)
|
||
# 全都拿不到时该条目明确失败,绝不退化成明文归档。
|
||
#
|
||
# 注意 7z 只接受命令行口令,口令在本机进程列表里短暂可见,这是 7z 本身的限制。
|
||
Encryption = @{
|
||
Enabled = $false
|
||
PasswordFile = 'baknret.key'
|
||
EncryptHeaders = $true
|
||
}
|
||
|
||
# 安全描述符(NTFS 属主 / ACL)。
|
||
#
|
||
# 归档格式装不下它:7-Zip 的 -sni 官方说明是"当前版本只能写进 WIM 归档",
|
||
# .7z 里一个字节的 ACL 都没有。所以每个归档旁边多一个 <归档名>.acl.json,
|
||
# 恢复时按它把属主 + 属组 + DACL 回放回去。
|
||
#
|
||
# 为什么非要不可:C:\ProgramData 的 ACL 里有 (A;OICIIO;GA;;;CO) —— CREATOR OWNER
|
||
# 不是账户,是访问检查时才替换的占位符,替换成"被检查对象的属主"。只回放 ACE 文本、
|
||
# 不恢复属主,等于把"谁创建的东西谁有全权"里的"谁"换成跑恢复脚本的那个账户,
|
||
# 原程序(服务账户 / 专用用户)反而没了读写权限。
|
||
#
|
||
# Mode Off —— 完全不采集:恢复出来的属主/ACL 是新建对象的默认值
|
||
# Full —— 每个对象都存(默认;正确性优先,几万文件的树 sidecar 几 MB)
|
||
# Smart —— 只存"继承复现不出来"的对象(体积优化,判据见代码,终究是启发式)
|
||
# Roots —— 只存每个归档项的根(最省,适合权限只在根上的场景)
|
||
# IncludeSacl 是否连审计规则(SACL)一起存取;读/写它需要 SeSecurityPrivilege
|
||
# SidMap 跨机恢复时的 SID 映射,例如:
|
||
# @{ 'S-1-5-21-1-2-3-1001' = 'S-1-5-21-9-8-7-1001' }
|
||
# FailOnError 安全描述符写盘失败时,是否把该条目算作失败(默认只告警并记进 manifest)
|
||
Security = @{
|
||
Mode = 'Full'
|
||
IncludeSacl = $false
|
||
SidMap = @{}
|
||
FailOnError = $false
|
||
}
|
||
|
||
# 所有条目都生效的排除模式,语法同 BackupList.txt(! 开头 = 任意层级匹配组件名)
|
||
DefaultExcludes = @(
|
||
'!Thumbs.db'
|
||
'!desktop.ini'
|
||
)
|
||
}
|