引入软件名录:清单写软件名,归档名也用软件名
新功能 - 新增 SoftwareCatalog.psd1 —— "软件名 -> 目录"映射表,BackupList.txt 里 直接写软件名即可,归档名也就是软件名(FooClolor.7z), 不再是 FooClolor_from_C_+Programs.7z 这种由路径拼出来的名字。 - 三种写法可混用:软件名、字面路径(现有清单无需改写)、软件名 @pathname。 - 名录支持前缀补全(legendary -> legendary_2.0.4,只认 <名>_* / <名>-*)、 Variants(同名目录在多处)、Includes(分文件维护)。 - tools/Rename-Archives.ps1:存量归档重命名,默认试运行,逐份大小校验并重建 manifest。 - 归档名重复直接报错,不再静默互相覆盖。 两套测试全绿:单元 42 项、端到端 23 项(新增名录命名/解析/迁移用例)。 过程中修掉的缺陷 - Resolve-BackupEntry 里 @pathname 与 Unresolved 分支顺序错误, @pathname 会被静默吃掉(改名后仍用软件名)。 - 源目录被删除时解析器丢掉 Sources,导致恢复端把软件名当路径、 报 "Cannot bind argument to parameter 'Path' because it is an empty string"。 恢复的语义恰恰是"源不存在就要还原回去",现在 Sources 照旧给出。 - 源存在性检查曾被漏掉,Get-Item 对不存在路径抛异常会中断整轮备份; 且不能用 Join-Path 探测——目标盘符不存在时它会直接抛异常。 - 计划任务脚本外的 Caller 需要 -DryRun 才能验,已实跑确认。
This commit is contained in:
1 parent
dbc0c00554
commit
045d51ac9c
9 files changed
+1330
-143
No files matched your search
+439
-8
@@ -417,16 +417,15 @@ function ConvertFrom-BackupListLine {
|
||||
|
||||
# 从尾部摘出 @标记。没有 `::` 时标记直接跟在路径后面
|
||||
# (如 `%UserProfile%\.ssh @encrypt`),因此 tail 为空时还要从路径那半再摘一次。
|
||||
# 标记可能出现在任一侧,所以两边都要摘。
|
||||
$tailSplit = Split-TrailingFlags -Text $tailPart
|
||||
$flags = @($tailSplit.Flags)
|
||||
$tailPart = $tailSplit.Remainder
|
||||
|
||||
if (-not $tailPart) {
|
||||
$pathSplit = Split-TrailingFlags -Text $pathPart
|
||||
if ($pathSplit.Flags.Count -gt 0) {
|
||||
$flags = @($pathSplit.Flags) + $flags
|
||||
$pathPart = $pathSplit.Remainder
|
||||
}
|
||||
$pathSplit = Split-TrailingFlags -Text $pathPart
|
||||
if ($pathSplit.Flags.Count -gt 0) {
|
||||
$flags = @($pathSplit.Flags) + $flags
|
||||
$pathPart = $pathSplit.Remainder
|
||||
}
|
||||
|
||||
$excludes = @()
|
||||
@@ -436,6 +435,9 @@ function ConvertFrom-BackupListLine {
|
||||
|
||||
return [pscustomobject]@{
|
||||
Path = $pathPart
|
||||
# 目录名或文件名,需要靠 SoftwareCatalog 换成真实路径;
|
||||
# 带分隔符或 %变量% 的写法按字面路径处理(并给出警告)。
|
||||
IsName = (-not (Test-LiteralPath -Path $pathPart))
|
||||
ExcludePatterns = $excludes
|
||||
Flags = $flags
|
||||
Raw = $Line
|
||||
@@ -443,6 +445,23 @@ function ConvertFrom-BackupListLine {
|
||||
}
|
||||
}
|
||||
|
||||
function Test-LiteralPath {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
判断清单里的一行是不是"字面路径"(而非软件名)。
|
||||
|
||||
.DESCRIPTION
|
||||
出现分隔符(\ 或 /)或 %环境变量% 就当作字面路径,其余按软件名去名录里查。
|
||||
这条规则保证:现有的全路径清单不需要任何改写就能继续工作。
|
||||
#>
|
||||
param([AllowEmptyString()][string]$Path)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($Path)) { return $true }
|
||||
if ($Path.Contains('\') -or $Path.Contains('/')) { return $true }
|
||||
if ($Path.Contains('%')) { return $true }
|
||||
return $false
|
||||
}
|
||||
|
||||
function Get-ArchiveExcludeArgument {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
@@ -491,10 +510,418 @@ function Get-ArchiveExcludeArgument {
|
||||
return ,$result
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 软件名录(SoftwareCatalog.psd1)
|
||||
# ============================================================================
|
||||
|
||||
function Resolve-CatalogPath {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
计算软件名录的绝对路径(优先 .psd1,找不到就退而用 .json)。
|
||||
#>
|
||||
param([string]$Configured, [string]$Root)
|
||||
|
||||
$candidates = @()
|
||||
if ($Configured) {
|
||||
$value = $Configured
|
||||
if (-not [System.IO.Path]::IsPathRooted($value)) { $value = Join-Path $Root $value }
|
||||
$candidates += $value
|
||||
}
|
||||
$candidates += (Join-Path $Root 'SoftwareCatalog.psd1')
|
||||
$candidates += (Join-Path $Root 'SoftwareCatalog.json')
|
||||
|
||||
foreach ($candidate in $candidates) {
|
||||
if (Test-Path -LiteralPath $candidate) { return $candidate }
|
||||
}
|
||||
return $candidates[0]
|
||||
}
|
||||
|
||||
function Format-CatalogName {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
把软件名规范化成合法的归档基础名。
|
||||
|
||||
.DESCRIPTION
|
||||
软件名就是归档名,所以这里必须挡住非法文件名字符。
|
||||
保留 & % +(与路径命名算法的白名单一致)。
|
||||
#>
|
||||
param([Parameter(Mandatory = $true)][string]$Name)
|
||||
|
||||
$invalidChars = [System.IO.Path]::GetInvalidFileNameChars() |
|
||||
Where-Object { $_ -notin @('&', '%', '+') }
|
||||
|
||||
$clean = -join ($Name.Trim().ToCharArray() | ForEach-Object {
|
||||
if ($_ -in $invalidChars) { '_' } else { $_ }
|
||||
})
|
||||
$clean = $clean -replace ':', '_'
|
||||
return $clean.Trim()
|
||||
}
|
||||
|
||||
function Get-SoftwareCatalog {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
载入"软件名 -> 目录"名录。
|
||||
|
||||
.DESCRIPTION
|
||||
返回按名字索引的哈希表,每项是 @{ Name; Path; ResolvedPath; Kind; Raw }。
|
||||
Kind 取值:Single(一个目录)| Variant(有 variants 的同名目录)| Unresolved(没找到目录)。
|
||||
|
||||
名录文件可以是 .psd1 或 .json——默认用 .psd1,因为路径这种东西很需要写注释。
|
||||
.psd1 里可以用 `Includes` 键引入其它名录文件,多个游戏/多个盘的目录可以分文件维护。
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[int]$MaxDepth = 5
|
||||
)
|
||||
|
||||
$result = @{}
|
||||
if (-not $Path -or -not (Test-Path -LiteralPath $Path)) { return $result }
|
||||
|
||||
$data = $null
|
||||
try {
|
||||
if ($Path.ToLower().EndsWith('.json')) {
|
||||
$data = Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json -ErrorAction Stop
|
||||
} else {
|
||||
$data = Import-PowerShellDataFile -LiteralPath $Path -ErrorAction Stop
|
||||
}
|
||||
} catch {
|
||||
Write-Log "软件名录读取失败:$Path —— $_" -Level ERROR
|
||||
return $result
|
||||
}
|
||||
|
||||
# 递归引入其它名录文件
|
||||
if ($data -is [System.Collections.IDictionary] -and $data.Contains('Includes')) {
|
||||
$includeList = @($data['Includes'])
|
||||
$baseDir = Split-Path -Parent $Path
|
||||
foreach ($include in $includeList) {
|
||||
if (-not $include) { continue }
|
||||
$includePath = [string]$include
|
||||
if (-not [System.IO.Path]::IsPathRooted($includePath)) { $includePath = Join-Path $baseDir $includePath }
|
||||
$included = Get-SoftwareCatalog -Path $includePath -MaxDepth $MaxDepth
|
||||
foreach ($includedName in $included.Keys) {
|
||||
if ($result.ContainsKey($includedName)) { continue }
|
||||
$result[$includedName] = $included[$includedName]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 顶层除 Includes 外的每个键都是一个软件名
|
||||
$keys = @()
|
||||
if ($data -is [System.Collections.IDictionary]) {
|
||||
$keys = @($data.Keys | Where-Object { $_ -ne 'Includes' })
|
||||
} else {
|
||||
$keys = @($data.PSObject.Properties.Name | Where-Object { $_ -ne 'Includes' })
|
||||
}
|
||||
|
||||
foreach ($key in $keys) {
|
||||
$name = Format-CatalogName -Name ([string]$key)
|
||||
if (-not $name) { continue }
|
||||
|
||||
$entry = if ($data -is [System.Collections.IDictionary]) { $data[$key] } else { $data.$key }
|
||||
|
||||
$rawPath = $null
|
||||
$variants = $null
|
||||
if ($entry -is [System.Collections.IDictionary]) {
|
||||
if ($entry.Contains('Path')) { $rawPath = [string]$entry['Path'] }
|
||||
if ($entry.Contains('Variants')) { $variants = @($entry['Variants']) }
|
||||
} else {
|
||||
$rawPath = [string]$entry
|
||||
}
|
||||
if (-not $rawPath) { continue }
|
||||
|
||||
$resolved = [Environment]::ExpandEnvironmentVariables($rawPath)
|
||||
|
||||
if ($variants -and $variants.Count -gt 0) {
|
||||
# 同名目录出现在多个位置:不猜,所有位置都作为归档根目录。
|
||||
$resolvedVariants = @($variants | ForEach-Object { [Environment]::ExpandEnvironmentVariables([string]$_) })
|
||||
$result[$name] = [pscustomobject]@{
|
||||
Name = $name
|
||||
Path = $rawPath
|
||||
ResolvedPath = $resolved
|
||||
Variants = $resolvedVariants
|
||||
Kind = 'Variant'
|
||||
Raw = $entry
|
||||
}
|
||||
Write-Log "名录:$name 有 $($resolvedVariants.Count) 个候选位置" -Level DEBUG
|
||||
continue
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $resolved) {
|
||||
$kind = 'Single'
|
||||
} else {
|
||||
# 名录里写的是父目录,实际目录带版本号之类后缀(如 legendary 的 <name>_2.0.4)
|
||||
$parent = Split-Path -Path $resolved -Parent
|
||||
$leaf = Split-Path -Path $resolved -Leaf
|
||||
$found = $null
|
||||
if ($parent -and (Test-Path -LiteralPath $parent)) {
|
||||
$found = @(Find-ChildDirectoryByName -Parent $parent -Name $leaf -MaxDepth $MaxDepth)
|
||||
if ($found.Count -gt 1) { $kind = 'Variant' } elseif ($found.Count -eq 1) { $kind = 'Single' } else { $kind = 'Unresolved' }
|
||||
} else {
|
||||
$kind = 'Unresolved'
|
||||
}
|
||||
|
||||
if ($found -and $found.Count -gt 0) {
|
||||
$resolved = $found[0]
|
||||
$result[$name] = [pscustomobject]@{
|
||||
Name = $name
|
||||
Path = $rawPath
|
||||
ResolvedPath = $resolved
|
||||
Variants = @($found)
|
||||
Kind = $kind
|
||||
Raw = $entry
|
||||
Suffixed = $true
|
||||
}
|
||||
Write-Log "名录:$name -> $resolved(按前缀补全)" -Level DEBUG
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
$result[$name] = [pscustomobject]@{
|
||||
Name = $name
|
||||
Path = $rawPath
|
||||
ResolvedPath = $resolved
|
||||
Variants = @()
|
||||
Kind = $kind
|
||||
Raw = $entry
|
||||
}
|
||||
}
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
function Find-ChildDirectoryByName {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
在 $Parent 下按精确名或"<名>_<后缀>"/"<名>-<后缀>"形式找目录。
|
||||
|
||||
.DESCRIPTION
|
||||
只做保守的前缀补全:必须以下一个字符是 _ 或 - 为界,
|
||||
避免把 Legendary 匹配成 LegendarySomething。
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Parent,
|
||||
[Parameter(Mandatory = $true)][string]$Name,
|
||||
[int]$MaxDepth = 5
|
||||
)
|
||||
|
||||
$escaped = [regex]::Escape($Name)
|
||||
$pattern = "^$escaped(_|-).+"
|
||||
|
||||
try {
|
||||
return @(Get-ChildItem -LiteralPath $Parent -Directory -Force -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Name -ieq $Name -or $_.Name -imatch $pattern } |
|
||||
Sort-Object Name |
|
||||
Select-Object -ExpandProperty FullName)
|
||||
} catch {
|
||||
return @()
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 归档命名与路径还原
|
||||
# ============================================================================
|
||||
|
||||
function Get-ItemArchiveName {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
决定一个条目的归档基础名(不含扩展名)。
|
||||
|
||||
.DESCRIPTION
|
||||
规则:
|
||||
* 默认用**软件名**(看起来像软件名就查名录;名录里没有则退回可读的目录名);
|
||||
* 条目带 `@pathname` 时用原来的路径命名算法;
|
||||
* 条目本来就写的是字面路径(含分隔符或 %变量%)时也用路径命名算法,
|
||||
这样现有清单不需要改写就能继续工作。
|
||||
#>
|
||||
param($Entry, [string]$CatalogPath, [int]$MaxDepth = 5)
|
||||
|
||||
# @pathname 时用"真实路径"跑路径命名算法。
|
||||
# 清单里写的可能是软件名,必须先经名录换成真实路径,
|
||||
# 否则 Get-BackupBaseName 会对软件名本身运算,得出错误的名字。
|
||||
if ($Entry.Flags -contains 'pathname') {
|
||||
$nameSource = $Entry.Path
|
||||
if (-not (Test-LiteralPath -Path $Entry.Path)) {
|
||||
$catalogForPath = Get-SoftwareCatalog -Path $CatalogPath -MaxDepth $MaxDepth
|
||||
if ($catalogForPath.ContainsKey($Entry.Path)) {
|
||||
$nameSource = $catalogForPath[$Entry.Path].Path
|
||||
}
|
||||
}
|
||||
return Get-BackupBaseName -RawPath $nameSource
|
||||
}
|
||||
|
||||
$looksLikePath = Test-LiteralPath -Path $Entry.Path
|
||||
if (-not $looksLikePath) {
|
||||
$catalog = Get-SoftwareCatalog -Path $CatalogPath -MaxDepth $MaxDepth
|
||||
if ($catalog.ContainsKey($Entry.Path)) {
|
||||
return $catalog[$Entry.Path].Name
|
||||
}
|
||||
Write-Log "名录里没有 '$($Entry.Path)',按目录名处理" -Level WARN
|
||||
return (Format-CatalogName -Name $Entry.Path)
|
||||
}
|
||||
|
||||
return Get-BackupBaseName -RawPath $Entry.Path
|
||||
}
|
||||
|
||||
function Resolve-BackupEntry {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
把清单条目解析成"实际要备份什么"。
|
||||
|
||||
.DESCRIPTION
|
||||
返回 @{ IsName; BaseName; Sources; Source; ArchiveFlavor },其中:
|
||||
* IsName —— 这一行写的是软件名还是字面路径
|
||||
* BaseName —— 归档基础名
|
||||
* Sources —— 要备份的项目列表(一个根目录名 -> 该根目录下的一组相对路径)
|
||||
* ArchiveFlavor —— 'name'(归档根目录叫软件名)或 'path'(叫源目录名)
|
||||
|
||||
归档内部布局:
|
||||
* 软件名条目 -> 根目录用软件名,内容为 `<源目录名>\...`
|
||||
(这样恢复时能知道文件原来属于哪个目录)
|
||||
* 字面路径条目 -> 整条目直接写进归档,保持与历史归档完全一致的布局,
|
||||
否则现有归档一旦被重打,恢复就会失败。
|
||||
#>
|
||||
param(
|
||||
$Entry,
|
||||
[string]$CatalogPath,
|
||||
[int]$MaxDepth = 5
|
||||
)
|
||||
|
||||
$isName = -not (Test-LiteralPath -Path $Entry.Path)
|
||||
# @pathname 强制按"字面路径条目"处理:归档名用路径算法,
|
||||
# 但清单里写的是软件名,真实路径仍要经名录解析。
|
||||
$forcePathFlavor = ($Entry.Flags -contains 'pathname')
|
||||
$baseName = Get-ItemArchiveName -Entry $Entry -CatalogPath $CatalogPath -MaxDepth $MaxDepth
|
||||
$rootNames = @($Entry.Flags | Where-Object { $_ -like 'root=*' } | ForEach-Object { $_.Substring(5) })
|
||||
|
||||
if (-not $isName) {
|
||||
$sourcePath = [Environment]::ExpandEnvironmentVariables($Entry.Path)
|
||||
return [pscustomobject]@{
|
||||
IsName = $false
|
||||
CatalogEntry = $null
|
||||
BaseName = $baseName
|
||||
ArchiveFlavor = 'path'
|
||||
RootName = $null
|
||||
Sources = @([pscustomobject]@{ RootName = $null; ParentDir = (Split-Path -Path $sourcePath -Parent); RelativePaths = @((Split-Path -Path $sourcePath -Leaf)); SourcePath = $sourcePath })
|
||||
Source = $Entry.Path
|
||||
}
|
||||
}
|
||||
|
||||
$catalog = Get-SoftwareCatalog -Path $CatalogPath -MaxDepth $MaxDepth
|
||||
if (-not $catalog.ContainsKey($Entry.Path)) {
|
||||
return [pscustomobject]@{
|
||||
IsName = $true
|
||||
CatalogEntry = $null
|
||||
BaseName = $baseName
|
||||
ArchiveFlavor = 'name'
|
||||
RootName = $rootName
|
||||
Sources = @()
|
||||
Source = $Entry.Path
|
||||
Error = "软件名录里没有 '$($Entry.Path)'"
|
||||
}
|
||||
}
|
||||
|
||||
$catalogEntry = $catalog[$Entry.Path]
|
||||
$rootName = if ($rootNames.Count -gt 0) { $rootNames[0] } else { $baseName }
|
||||
|
||||
# @pathname 必须排在 Unresolved 分支之前:否则路径不存在的条目会先被
|
||||
# 当作普通软件名条目返回 Flavor='name',把 @pathname 覆盖悄悄吃掉。
|
||||
if ($forcePathFlavor) {
|
||||
$flavorPath = $catalogEntry.ResolvedPath
|
||||
$flavorParent = Split-Path -Path $flavorPath -Parent
|
||||
$flavorLeaf = Split-Path -Path $flavorPath -Leaf
|
||||
$flavorSource = @()
|
||||
if ($flavorParent -and $flavorLeaf) {
|
||||
$flavorSource = @([pscustomobject]@{
|
||||
RootName = $null
|
||||
ParentDir = $flavorParent
|
||||
RelativePaths = @($flavorLeaf)
|
||||
SourcePath = $flavorPath
|
||||
})
|
||||
}
|
||||
return [pscustomobject]@{
|
||||
IsName = $true
|
||||
CatalogEntry = $catalogEntry
|
||||
BaseName = $baseName
|
||||
ArchiveFlavor = 'path'
|
||||
RootName = $null
|
||||
Sources = $flavorSource
|
||||
Source = $Entry.Path
|
||||
Error = $(if ($catalogEntry.Kind -eq 'Unresolved') { "名录里的路径不存在:$($catalogEntry.Path)" } else { $null })
|
||||
}
|
||||
}
|
||||
|
||||
# 名录里的路径当前不存在。备份时这是"跳过",但**恢复时这正是要恢复的场景**,
|
||||
# 所以 SourcePath 仍然给出来(恢复端会照它把内容还原回原位),
|
||||
# 只把 Error 标出来让备份端跳过。
|
||||
if ($catalogEntry.Kind -eq 'Unresolved') {
|
||||
$missingPath = $catalogEntry.ResolvedPath
|
||||
$missingParent = Split-Path -Path $missingPath -Parent
|
||||
$missingLeaf = Split-Path -Path $missingPath -Leaf
|
||||
$missingSource = @()
|
||||
if ($missingParent -and $missingLeaf) {
|
||||
$missingSource = @([pscustomobject]@{
|
||||
RootName = $rootName
|
||||
ParentDir = $missingParent
|
||||
RelativePaths = @($missingLeaf)
|
||||
SourcePath = $missingPath
|
||||
})
|
||||
}
|
||||
return [pscustomobject]@{
|
||||
IsName = $true
|
||||
CatalogEntry = $catalogEntry
|
||||
BaseName = $baseName
|
||||
ArchiveFlavor = 'name'
|
||||
RootName = $rootName
|
||||
Sources = $missingSource
|
||||
Source = $Entry.Path
|
||||
Error = "名录里的路径不存在:$($catalogEntry.Path)"
|
||||
}
|
||||
}
|
||||
|
||||
# @pathname 已在前面统一处理(必须排在 Unresolved 之前),这里不再重复。
|
||||
|
||||
$sources = @()
|
||||
|
||||
if ($catalogEntry.Kind -eq 'Variant') {
|
||||
$parent = Split-Path -Path $catalogEntry.ResolvedPath -Parent
|
||||
$relatives = @($catalogEntry.Variants | ForEach-Object { Split-Path -Path $_ -Leaf })
|
||||
$sources = @([pscustomobject]@{
|
||||
RootName = $rootName
|
||||
ParentDir = $parent
|
||||
RelativePaths = $relatives
|
||||
SourcePath = $parent
|
||||
})
|
||||
} elseif ($catalogEntry.Kind -eq 'Single') {
|
||||
$sources = @([pscustomobject]@{
|
||||
RootName = $rootName
|
||||
ParentDir = (Split-Path -Path $catalogEntry.ResolvedPath -Parent)
|
||||
RelativePaths = @((Split-Path -Path $catalogEntry.ResolvedPath -Leaf))
|
||||
SourcePath = $catalogEntry.ResolvedPath
|
||||
})
|
||||
} else {
|
||||
return [pscustomobject]@{
|
||||
IsName = $true
|
||||
CatalogEntry = $catalogEntry
|
||||
BaseName = $baseName
|
||||
ArchiveFlavor = 'name'
|
||||
RootName = $rootName
|
||||
Sources = @()
|
||||
Source = $Entry.Path
|
||||
Error = "名录里的路径不存在:$($catalogEntry.Path)"
|
||||
}
|
||||
}
|
||||
|
||||
return [pscustomobject]@{
|
||||
IsName = $true
|
||||
CatalogEntry = $catalogEntry
|
||||
BaseName = $baseName
|
||||
ArchiveFlavor = 'name'
|
||||
RootName = $rootName
|
||||
Sources = $sources
|
||||
Source = $Entry.Path
|
||||
}
|
||||
}
|
||||
|
||||
function Get-BackupBaseName {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
@@ -728,6 +1155,8 @@ function Get-BaknretConfig {
|
||||
BackupDir = 'Backups'
|
||||
LogDir = 'logs'
|
||||
SnapshotDir = 'Backups\snapshots'
|
||||
SoftwareCatalog = 'SoftwareCatalog.psd1'
|
||||
CatalogMaxDepth = 5
|
||||
MinFreeSpaceGB = 8
|
||||
VerifyArchive = $true
|
||||
ComputeHash = $false
|
||||
@@ -788,8 +1217,10 @@ Export-ModuleMember -Function @(
|
||||
'Set-BaknretDebug', 'Start-BaknretLog', 'Stop-BaknretLog', 'Get-BaknretLogPath', 'Write-Log',
|
||||
'Test-Administrator', 'Get-BaknretFreeSpaceGB',
|
||||
'ConvertTo-NativeArgumentString', 'Invoke-ExternalCommand', 'Resolve-CompressionTool', 'Get-Optimized7zArgument',
|
||||
'ConvertFrom-BackupListLine', 'Get-ArchiveExcludeArgument',
|
||||
'Get-BackupBaseName', 'Convert-BackupFileNameToPath', 'Get-FolderSummary',
|
||||
'ConvertFrom-BackupListLine', 'Get-ArchiveExcludeArgument', 'Test-LiteralPath',
|
||||
'Resolve-CatalogPath', 'Get-SoftwareCatalog', 'Find-ChildDirectoryByName', 'Format-CatalogName',
|
||||
'Get-ItemArchiveName', 'Resolve-BackupEntry', 'Get-BackupBaseName', 'Convert-BackupFileNameToPath',
|
||||
'Get-FolderSummary',
|
||||
'Read-BaknretManifest', 'Write-BaknretManifest', 'Move-BaknretArchiveIntoPlace',
|
||||
'Get-BaknretConfig', 'Get-BaknretPassword'
|
||||
)
|
||||
Reference in new issue
Block a user