<# .SYNOPSIS 已改名:本脚本只是转发到 Backup-Data.ps1(这一层只保留一轮)。 .DESCRIPTION 为什么留一层转发(ADR-0012):入口脚本是**外部接口** —— README 里有二十多处引用、有使用者的 肌肉记忆、tools\Register-BackupTask.ps1 里也可能已经注册过这个路径。内部实现改名断了会当场 报错;外部接口改名断了是**静默没用**,而备份工具"静默没用"是最不能接受的失败方式。 为什么用子进程、而不是 `& $target`:实测 `& script.ps1` 里子脚本的 exit **不会**把退出码传到 父脚本的 $LASTEXITCODE —— 垫片会让失败变成"成功"(错配置时返回 0,被调用脚本返回 1),而计划 任务正是靠退出码判断成败。 为什么重定向之后要**自己转发**:父进程的 stdout 常常是管道(测试与使用者的管道都在解析入口的 输出),而 .NET 起的进程默认只继承控制台、不继承那个管道 —— 不重定向时子进程的输出就到不了 调用方(实测红过)。所以显式重定向,再用**异步读**把两个流读出来转发(同步先读 stdout 再读 stderr 会在管道写满时死锁)。代价是 stdout/stderr 的相对顺序不再保留 —— 这也正是这层垫片 只留一轮的原因之一。 为什么导入模块时临时压掉 verbose:调用方可能给入口传 -Verbose(测试就是这么拿到详细日志的), 那样 Import-Module 会多打一行 "VERBOSE: Loading module from path ..." —— 而测试是**解析子进程 输出**做断言的,多这么一行就会把它顶掉。只压这一句,$Rest 里的 -Verbose 仍会原样转发。 这一层下一轮删。想用新名字就直接调 Backup-Data.ps1。 #> [CmdletBinding()] param( [Parameter(ValueFromRemainingArguments = $true)]$Rest ) $ErrorActionPreference = 'Stop' $savedVerbosePreference = $VerbosePreference $VerbosePreference = 'SilentlyContinue' Import-Module (Join-Path $PSScriptRoot 'BakNRet\BakNRet.psd1') -Force $VerbosePreference = $savedVerbosePreference $target = Join-Path $PSScriptRoot 'Backup-Data.ps1' Write-Host '注意:Backup.ps1 已改名为 Backup-Data.ps1(这层转发只保留一轮)。' -ForegroundColor Yellow $hostExe = (Get-Process -Id $PID).Path $forwardArguments = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $target) + @($Rest) + @(if ($PSBoundParameters.ContainsKey('Verbose')) { '-Verbose' }) + @(if ($PSBoundParameters.ContainsKey('Debug')) { '-Debug' }) $startInfo = New-Object System.Diagnostics.ProcessStartInfo $startInfo.FileName = $hostExe $startInfo.Arguments = ConvertTo-BakNRetNativeArgumentString -ArgumentList $forwardArguments $startInfo.UseShellExecute = $false $startInfo.RedirectStandardOutput = $true $startInfo.RedirectStandardError = $true $process = New-Object System.Diagnostics.Process $process.StartInfo = $startInfo [void]$process.Start() $stdoutTask = $process.StandardOutput.ReadToEndAsync() $stderrTask = $process.StandardError.ReadToEndAsync() $process.WaitForExit() $standardOutput = $stdoutTask.Result $standardError = $stderrTask.Result if ($standardOutput) { Write-Host -NoNewline $standardOutput } if ($standardError) { [Console]::Error.Write($standardError) } exit $process.ExitCode