fix: lab 的 ACL 场景在 5.1 上会被原生命令的 stderr 中断
tools\lab\payload\run-acl-scenario.ps1 是 $ErrorActionPreference = Stop,而它要大量调用 rmdir / takeown / icacls / scoop / code —— 其中 rmdir 与 takeown 在"对象已经处理过"或 "连接点已经悬空"时就会往 stderr 写字。Windows PowerShell 5.1 会把那升级成终止性的 NativeCommandError(7 改了这条规矩),于是清理函数在设计要处理的**恰恰那个场景**里直接崩掉。 修法:新增 Invoke-NativeTolerant,在进入原生命令时把 EAP 放到 Continue、退出时还原, 把 stdout 与 stderr 合并返回;12 处调用全部收进它。判断"删掉了没有"本来就该用 Test-Path, 不需要让 stderr 变成异常。这与 tests\BakNRet.Security.Tests.ps1 里对 takeown / icacls 用的是同一招(那里已被 5.1 的失败实测逼出来过)。 范围说明:只改了 run-acl-scenario.ps1。provision.ps1 的同类写法**不需要**改 —— 它是 $ErrorActionPreference = Continue,那两处本来就不会踩。 验证边界(如实说明):这个文件要 Hyper-V + 一台 VM 才跑得到,本会话无法执行它。 所以这一步的证据是:两个版本上解析零错(Parse 层覆盖)、12 处替换逐条断言命中、以及 diff 逐行复核。它是"降低风险",不是"已验证修复"。 验收:test.ps1 9/9 全绿(7 与 5.1);Run-RealSmoke 4/4 全绿。
This commit is contained in:
1 parent
8d67a38fb7
commit
10f97246c8
1 file changed
+38
-11
@@ -43,6 +43,33 @@ Import-Module (Join-Path $RepoPath 'Common.psm1') -Force
|
|||||||
$script:Passed = 0
|
$script:Passed = 0
|
||||||
$script:Failures = @()
|
$script:Failures = @()
|
||||||
|
|
||||||
|
function Invoke-NativeTolerant {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
跑一个原生命令,把 stdout 与 stderr 合并成字符串数组返回,不让 stderr 变成错误。
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Windows PowerShell 5.1 在 $ErrorActionPreference = 'Stop' 下会把原生命令写到
|
||||||
|
stderr 的内容升级成终止性的 NativeCommandError(PowerShell 7 改了这条规矩)。
|
||||||
|
|
||||||
|
本脚本要调用 rmdir / takeown / icacls / scoop / code,其中 rmdir 与 takeown 在
|
||||||
|
"对象已经处理过"或"连接点已经悬空"时就会往 stderr 写字 —— 那些话不是错误:真正该
|
||||||
|
判断的是"删掉了没有",用 Test-Path 看。所以在进入原生命令时把 EAP 放到 Continue,
|
||||||
|
退出时还原。这也是 tests\BakNRet.Security.Tests.ps1 里对 takeown / icacls 用的同一招。
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$FilePath,
|
||||||
|
[string[]]$ArgumentList = @()
|
||||||
|
)
|
||||||
|
|
||||||
|
$previous = $ErrorActionPreference
|
||||||
|
$ErrorActionPreference = 'Continue'
|
||||||
|
try {
|
||||||
|
return @(& $FilePath @ArgumentList 2>&1)
|
||||||
|
} finally {
|
||||||
|
$ErrorActionPreference = $previous
|
||||||
|
}
|
||||||
|
}
|
||||||
function Test-Scenario {
|
function Test-Scenario {
|
||||||
param([Parameter(Mandatory = $true)][string]$Name, [bool]$Ok, [string]$Detail = '')
|
param([Parameter(Mandatory = $true)][string]$Name, [bool]$Ok, [string]$Detail = '')
|
||||||
if ($Ok) {
|
if ($Ok) {
|
||||||
@@ -159,17 +186,17 @@ function Remove-TreeHard {
|
|||||||
$links = @(Get-ChildItem -LiteralPath $Path -Recurse -Force -Directory -ErrorAction SilentlyContinue |
|
$links = @(Get-ChildItem -LiteralPath $Path -Recurse -Force -Directory -ErrorAction SilentlyContinue |
|
||||||
Where-Object { $_.Attributes -band [IO.FileAttributes]::ReparsePoint })
|
Where-Object { $_.Attributes -band [IO.FileAttributes]::ReparsePoint })
|
||||||
foreach ($link in $links) {
|
foreach ($link in $links) {
|
||||||
& cmd.exe /c ('rmdir "{0}"' -f $link.FullName) 2>&1 | Out-Null
|
$null = Invoke-NativeTolerant -FilePath 'cmd.exe' -ArgumentList @('/c', ('rmdir "{0}"' -f $link.FullName))
|
||||||
Remove-BaknretJunction -Path $link.FullName
|
Remove-BaknretJunction -Path $link.FullName
|
||||||
}
|
}
|
||||||
|
|
||||||
& cmd.exe /c ('rmdir /s /q "{0}"' -f $Path) 2>&1 | Out-Null
|
$null = Invoke-NativeTolerant -FilePath 'cmd.exe' -ArgumentList @('/c', ('rmdir /s /q "{0}"' -f $Path))
|
||||||
|
|
||||||
if (Test-Path -LiteralPath $Path) {
|
if (Test-Path -LiteralPath $Path) {
|
||||||
# 只处理这一条路径:拿回属主 → 换成继承来的默认 ACL → 再删
|
# 只处理这一条路径:拿回属主 → 换成继承来的默认 ACL → 再删
|
||||||
& takeown.exe /F $Path /R /D Y 2>&1 | Out-Null
|
$null = Invoke-NativeTolerant -FilePath 'takeown.exe' -ArgumentList @('/F', $Path, '/R', '/D', 'Y')
|
||||||
& icacls.exe $Path /reset /T /C /Q 2>&1 | Out-Null
|
$null = Invoke-NativeTolerant -FilePath 'icacls.exe' -ArgumentList @($Path, '/reset', '/T', '/C', '/Q')
|
||||||
& cmd.exe /c ('rmdir /s /q "{0}"' -f $Path) 2>&1 | Out-Null
|
$null = Invoke-NativeTolerant -FilePath 'cmd.exe' -ArgumentList @('/c', ('rmdir /s /q "{0}"' -f $Path))
|
||||||
Remove-Item -LiteralPath $Path -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -LiteralPath $Path -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,21 +273,21 @@ if (-not $SkipScoop) {
|
|||||||
# 这台 VM 出厂不带 git,所以 main bucket 只能先用 zip 兜底进来,git 再由此装上。
|
# 这台 VM 出厂不带 git,所以 main bucket 只能先用 zip 兜底进来,git 再由此装上。
|
||||||
if ((Test-Path -LiteralPath $scoopCmd) -and -not (Test-Path -LiteralPath (Join-Path $scoopRoot 'shims\git.exe'))) {
|
if ((Test-Path -LiteralPath $scoopCmd) -and -not (Test-Path -LiteralPath (Join-Path $scoopRoot 'shims\git.exe'))) {
|
||||||
Write-Host '[A] scoop install git(后面 bucket add 要靠它)' -ForegroundColor Yellow
|
Write-Host '[A] scoop install git(后面 bucket add 要靠它)' -ForegroundColor Yellow
|
||||||
& $scoopCmd install git 2>&1 | ForEach-Object { ' ' + $_ }
|
Invoke-NativeTolerant -FilePath $scoopCmd -ArgumentList @('install', 'git') | ForEach-Object { ' ' + $_ }
|
||||||
}
|
}
|
||||||
|
|
||||||
# vscode 在 extras bucket,不在 main 里
|
# vscode 在 extras bucket,不在 main 里
|
||||||
if ((Test-Path -LiteralPath $scoopCmd) -and -not (Test-Path -LiteralPath (Join-Path $scoopRoot 'buckets\extras'))) {
|
if ((Test-Path -LiteralPath $scoopCmd) -and -not (Test-Path -LiteralPath (Join-Path $scoopRoot 'buckets\extras'))) {
|
||||||
Write-Host '[A] scoop bucket add extras' -ForegroundColor Yellow
|
Write-Host '[A] scoop bucket add extras' -ForegroundColor Yellow
|
||||||
& $scoopCmd bucket add extras 2>&1 | ForEach-Object { ' ' + $_ }
|
Invoke-NativeTolerant -FilePath $scoopCmd -ArgumentList @('bucket', 'add', 'extras') | ForEach-Object { ' ' + $_ }
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Test-Path -LiteralPath $scoopCmd) -and -not (Test-Path -LiteralPath $vscodeCli)) {
|
if ((Test-Path -LiteralPath $scoopCmd) -and -not (Test-Path -LiteralPath $vscodeCli)) {
|
||||||
Write-Host '[A] scoop install vscode(从 extras 下载几百 MB,慢是正常的)' -ForegroundColor Yellow
|
Write-Host '[A] scoop install vscode(从 extras 下载几百 MB,慢是正常的)' -ForegroundColor Yellow
|
||||||
& $scoopCmd install vscode 2>&1 | ForEach-Object { ' ' + $_ }
|
Invoke-NativeTolerant -FilePath $scoopCmd -ArgumentList @('install', 'vscode') | ForEach-Object { ' ' + $_ }
|
||||||
if (-not (Test-Path -LiteralPath $vscodeCli)) {
|
if (-not (Test-Path -LiteralPath $vscodeCli)) {
|
||||||
Write-Host '[A] 第一次没装上,重试一次(下载超时是常见原因)' -ForegroundColor Yellow
|
Write-Host '[A] 第一次没装上,重试一次(下载超时是常见原因)' -ForegroundColor Yellow
|
||||||
& $scoopCmd install vscode 2>&1 | ForEach-Object { ' ' + $_ }
|
Invoke-NativeTolerant -FilePath $scoopCmd -ArgumentList @('install', 'vscode') | ForEach-Object { ' ' + $_ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,7 +309,7 @@ if ($vscodeReady) {
|
|||||||
$probe = 'baknret-' + [guid]::NewGuid().ToString('N').Substring(0, 8)
|
$probe = 'baknret-' + [guid]::NewGuid().ToString('N').Substring(0, 8)
|
||||||
$settingsPath = $null
|
$settingsPath = $null
|
||||||
if ($vscodeReady) {
|
if ($vscodeReady) {
|
||||||
$versionText = (& $codeCmd --version 2>&1 | Out-String).Trim()
|
$versionText = (Invoke-NativeTolerant -FilePath $codeCmd -ArgumentList @('--version') | Out-String).Trim()
|
||||||
Test-Scenario 'A: vscode CLI 可执行(--version)' ($LASTEXITCODE -eq 0) ($versionText -split "`n" | Select-Object -First 1)
|
Test-Scenario 'A: vscode CLI 可执行(--version)' ($LASTEXITCODE -eq 0) ($versionText -split "`n" | Select-Object -First 1)
|
||||||
|
|
||||||
# scoop 的 vscode 清单带 persist:data,用户数据落在 persist 里(portable 模式);
|
# scoop 的 vscode 清单带 persist:data,用户数据落在 persist 里(portable 模式);
|
||||||
@@ -401,7 +428,7 @@ Test-Scenario '恢复日志里出现安全描述符回放' ($restore.Output -mat
|
|||||||
Write-Host ''
|
Write-Host ''
|
||||||
Write-Host '--- A 断言 ---' -ForegroundColor Cyan
|
Write-Host '--- A 断言 ---' -ForegroundColor Cyan
|
||||||
if ($vscodeReady) {
|
if ($vscodeReady) {
|
||||||
$versionText = (& $codeCmd --version 2>&1 | Out-String).Trim()
|
$versionText = (Invoke-NativeTolerant -FilePath $codeCmd -ArgumentList @('--version') | Out-String).Trim()
|
||||||
Test-Scenario 'A: 恢复后 vscode CLI 仍可执行' ($LASTEXITCODE -eq 0) ($versionText -split "`n" | Select-Object -First 1)
|
Test-Scenario 'A: 恢复后 vscode CLI 仍可执行' ($LASTEXITCODE -eq 0) ($versionText -split "`n" | Select-Object -First 1)
|
||||||
|
|
||||||
$settingsOk = $false
|
$settingsOk = $false
|
||||||
|
|||||||
Reference in new issue
Block a user