3152 行、66 个函数的单文件模块拆成: BakNRet\BakNRet.psd1 模块清单:FunctionsToExport 是显式白名单(62 个名字) BakNRet\BakNRet.psm1 加载器:点源顺序的唯一一处声明 BakNRet\Public\*.ps1 62 个对外函数,一函数一文件,文件名 = 函数名 BakNRet\Private\*.ps1 4 个内部函数 + State.ps1(模块级状态集中一处) 为什么是一函数一文件:这是社区里脚本模块的主流形态(调研实测:winutil 79 个、 Terminal-Icons 24 个、ModuleBuilder 23 个,全部如此)。收益是改动落在小文件里、diff 按职责 可读、模块级状态有唯一去处。 为什么这不算"打散":模块内 dot-source 的文件共享同一个模块作用域(实测确认),所以 "按顺序点源 67 个文件"与"点源一个大文件"在语义上等价;顺序只在加载器里出现一次, tools\Build-BakNRetModule.ps1 从那里读出顺序就能拼回单文件 —— 本次产物 dist\BakNRet.psm1 3240 行、两个版本都解析零错。 新增一条断言把这条承诺钉住:加载器点源的文件集合必须与磁盘一致、导出名单必须与 Public\ 一一对应。漏一个文件或漏一个名字就是静默少一个函数 —— 而那种错在运行时只表现为 "找不到命令"。 引用更新:11 个文件里的 Common.psm1 改成 BakNRet\BakNRet.psd1(走清单导入, FunctionsToExport 才真的说了算);Common.psm1 直接删除,不留转发垫片。 验收:test.ps1 9/9 全绿(7 与 5.1),98 个文件两版解析零错,276 个断言原样通过 —— 这次搬家没有改变任何可观察行为。
201 lines
8.7 KiB
PowerShell
201 lines
8.7 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
BakNRet —— 备份 / 恢复脚本的公共功能模块。
|
||
|
||
.DESCRIPTION
|
||
提供日志(控制台 + 落盘)、外部命令调用(可取得真实退出码)、
|
||
BackupList.txt 语法解析、归档命名与逆向解析、目录摘要、manifest 读写、
|
||
磁盘剩余空间查询等公共能力。
|
||
|
||
兼容 Windows PowerShell 5.1 与 PowerShell 7.x:
|
||
* 不使用 ?? / 三元运算符 / Join-String / -AsHashtable 等 6.0+ 语法;
|
||
* 不使用 ProcessStartInfo.ArgumentList(5.1 上不存在),改为自行构造命令行。
|
||
|
||
模块内出现的备份清单语法(BackupList.txt 每一行):
|
||
|
||
[+|-] <软件名 或 绝对路径> [修饰符...] [# 说明]
|
||
[:: <Absolute\Path>] [:- <模式>[,...]] [:+ <包含项>[,...]]
|
||
[:encrypt | :!encrypt] [@ <Key>='<Value>']
|
||
|
||
标记(必须是独立的空白分隔记号,前后都要有空格):
|
||
+ 仅备份,不恢复(Restore.ps1 跳过)
|
||
- 仅恢复,不备份(Backup.ps1 跳过)
|
||
:: 覆盖 Path,等价于 `@ Path='...'`
|
||
:- 排除模式,等价于 `@ Exclude='...'`
|
||
:+ 追加包含项(<归档内相对路径>:<宿主机绝对路径>),等价于 `@ Include='...'`
|
||
:encrypt 该条目加密(`@ Encrypt='$true'`)
|
||
:!encrypt 该条目不加密(`@ Encrypt='$false'`)
|
||
@ Key='值' 覆盖 SoftwareCatalog.psd1 里的同名默认字段
|
||
|
||
兼容的历史写法:`@encrypt` / `@!encrypt` / `@pathname` / `@root=<名>`,
|
||
以及用双引号包住路径或模式值。
|
||
|
||
归档内布局(SoftwareCatalog.psd1 的 Slot 是包内的一层目录):
|
||
软件名条目 -> <Slot>\<该 Path 的内容>(Path 是文件时就是名为 <Slot> 的文件)
|
||
手写路径 -> <路径末级名>\...(历史布局,不变)
|
||
#>
|
||
|
||
|
||
# ----------------------------------------------------------------------------
|
||
# 加载器:下面这份点源顺序是**唯一**一份顺序声明。
|
||
#
|
||
# 每个函数一个文件,文件名 = 函数名;要合回单个 .psm1(发布形态,或做代码签名时需要),
|
||
# 跑 tools\Build-BakNRetModule.ps1 —— 它从本文件里读出顺序,所以顺序不需要维护两遍。
|
||
# ----------------------------------------------------------------------------
|
||
|
||
. (Join-Path $PSScriptRoot 'Private\State.ps1')
|
||
|
||
# ---- 日志 ----
|
||
. (Join-Path $PSScriptRoot 'Public\Set-BaknretDebug.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Start-BaknretLog.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Stop-BaknretLog.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretLogPath.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Write-Log.ps1')
|
||
|
||
# ---- 运行锁 ----
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretRunLockPath.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Enter-BaknretRunLock.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Exit-BaknretRunLock.ps1')
|
||
|
||
# ---- 环境 ----
|
||
. (Join-Path $PSScriptRoot 'Public\Test-Administrator.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretFreeSpaceGB.ps1')
|
||
|
||
# ---- 外部命令 ----
|
||
. (Join-Path $PSScriptRoot 'Public\ConvertTo-NativeArgumentString.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Invoke-ExternalCommand.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Resolve-CompressionTool.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-Optimized7zArgument.ps1')
|
||
|
||
# ---- BackupList.txt 解析 ----
|
||
. (Join-Path $PSScriptRoot 'Public\Split-BaknretToken.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Remove-BaknretQuote.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Test-BaknretMarker.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\ConvertFrom-BaknretPatternList.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\ConvertFrom-BackupListLine.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Test-LiteralPath.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretRegexExclude.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretExcludeArgument.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Split-BaknretPatternScope.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Merge-BaknretExcludeArgument.ps1')
|
||
|
||
# ---- 软件名录(SoftwareCatalog.psd1) ----
|
||
. (Join-Path $PSScriptRoot 'Public\Resolve-CatalogPath.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Format-CatalogName.ps1')
|
||
. (Join-Path $PSScriptRoot 'Private\Test-BaknretMapKey.ps1')
|
||
. (Join-Path $PSScriptRoot 'Private\Get-BaknretMapValue.ps1')
|
||
. (Join-Path $PSScriptRoot 'Private\Get-BaknretMapKeys.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Expand-CatalogPathText.ps1')
|
||
. (Join-Path $PSScriptRoot 'Private\Import-BaknretDataFile.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-SoftwareCatalog.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-ArchiveTopLevelNames.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Find-ChildDirectoryByName.ps1')
|
||
|
||
# ---- 归档命名与路径还原 ----
|
||
. (Join-Path $PSScriptRoot 'Public\Get-ItemArchiveName.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretArchiveTopName.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\New-BaknretArchiveItem.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\New-BaknretJunction.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Remove-BaknretJunction.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\New-BaknretArchiveStaging.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Remove-BaknretArchiveStaging.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Resolve-BackupEntry.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Write-BackupEntryPlan.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BackupBaseName.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Convert-BackupFileNameToPath.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-FolderSummary.ps1')
|
||
|
||
# ---- manifest.json ----
|
||
. (Join-Path $PSScriptRoot 'Public\Read-BaknretManifest.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Sync-BaknretManifestArchive.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Write-BaknretManifest.ps1')
|
||
|
||
# ---- 归档原子替换 ----
|
||
. (Join-Path $PSScriptRoot 'Public\Move-BaknretArchiveIntoPlace.ps1')
|
||
|
||
# ---- 安全描述符(NTFS 属主 / ACL) ----
|
||
. (Join-Path $PSScriptRoot 'Public\Enable-BaknretPrivilege.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\ConvertTo-BaknretWildcardPattern.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Test-BaknretPathExcluded.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretAceSignatureList.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretSecuritySddlWithStale.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretSecurityRecord.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Test-BaknretSecurityRecordNeeded.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretSecurityRecords.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Write-BaknretAtomicText.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Save-BaknretSecuritySidecar.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Read-BaknretSecuritySidecar.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Convert-BaknretSidMap.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Set-BaknretObjectSecurity.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Restore-BaknretSecurity.ps1')
|
||
|
||
# ---- 配置 ----
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretConfig.ps1')
|
||
. (Join-Path $PSScriptRoot 'Public\Get-BaknretPassword.ps1')
|
||
|
||
Export-ModuleMember -Function @(
|
||
'Enter-BaknretRunLock',
|
||
'Exit-BaknretRunLock',
|
||
'Get-BaknretRunLockPath',
|
||
'Set-BaknretDebug',
|
||
'Start-BaknretLog',
|
||
'Stop-BaknretLog',
|
||
'Get-BaknretLogPath',
|
||
'Write-Log',
|
||
'Test-Administrator',
|
||
'Get-BaknretFreeSpaceGB',
|
||
'ConvertTo-NativeArgumentString',
|
||
'Invoke-ExternalCommand',
|
||
'Resolve-CompressionTool',
|
||
'Get-Optimized7zArgument',
|
||
'Split-BaknretToken',
|
||
'Remove-BaknretQuote',
|
||
'Test-BaknretMarker',
|
||
'ConvertFrom-BaknretPatternList',
|
||
'ConvertFrom-BackupListLine',
|
||
'Test-LiteralPath',
|
||
'Get-BaknretRegexExclude',
|
||
'Get-BaknretExcludeArgument',
|
||
'Split-BaknretPatternScope',
|
||
'Merge-BaknretExcludeArgument',
|
||
'Resolve-CatalogPath',
|
||
'Get-SoftwareCatalog',
|
||
'Find-ChildDirectoryByName',
|
||
'Format-CatalogName',
|
||
'Expand-CatalogPathText',
|
||
'Get-ArchiveTopLevelNames',
|
||
'Get-BaknretArchiveTopName',
|
||
'New-BaknretArchiveItem',
|
||
'New-BaknretJunction',
|
||
'Remove-BaknretJunction',
|
||
'New-BaknretArchiveStaging',
|
||
'Remove-BaknretArchiveStaging',
|
||
'Get-ItemArchiveName',
|
||
'Resolve-BackupEntry',
|
||
'Write-BackupEntryPlan',
|
||
'Get-BackupBaseName',
|
||
'Convert-BackupFileNameToPath',
|
||
'Get-FolderSummary',
|
||
'Read-BaknretManifest',
|
||
'Write-BaknretManifest',
|
||
'Sync-BaknretManifestArchive',
|
||
'Move-BaknretArchiveIntoPlace',
|
||
'Enable-BaknretPrivilege',
|
||
'ConvertTo-BaknretWildcardPattern',
|
||
'Test-BaknretPathExcluded',
|
||
'Get-BaknretAceSignatureList',
|
||
'Get-BaknretSecuritySddlWithStale',
|
||
'Get-BaknretSecurityRecord',
|
||
'Test-BaknretSecurityRecordNeeded',
|
||
'Get-BaknretSecurityRecords',
|
||
'Write-BaknretAtomicText',
|
||
'Save-BaknretSecuritySidecar',
|
||
'Read-BaknretSecuritySidecar',
|
||
'Convert-BaknretSidMap',
|
||
'Set-BaknretObjectSecurity',
|
||
'Restore-BaknretSecurity',
|
||
'Get-BaknretConfig',
|
||
'Get-BaknretPassword'
|
||
)
|
||
|