诊断 Windows 沙箱 ACL 故障
**将每个审批请求用通俗的语言写出来,使用用户的语言。**提示是用户在允许访问之前看到的全部内容,所以它必须能独立表达:脚本将触摸哪个文件夹,它会为缺失权限的地方添加当前登录用户的完全控制条目并移除外来软件包条目,文件内容和所有者不变,以及打印的恢复命令可以撤消每个更改。将错误代码、WRITE_DAC/WRITE_OWNER、S-1-15-2-* SID、icacls、ACL、ACE、裁决名称和开关保留在请求之外:写 Windows 文件权限,而不是 ACL 或 ACE。只询问一次,针对一条命令。
一个命令诊断并修复
该脚本没有模式。-Path、-AllowRoot 和 -Out 会读取该路径及其所有上级目录,并在同一次运行中修复观察结果所证明的问题:
- 在该链上缺少有效
WRITE_DAC或WRITE_OWNER的目录会收到当前登录用户的允许完全控制 ACE,因为 DSH 无法在没有它们的情况下预配其工作区授权; - 显式的 AppContainer 包允许 ACE(
S-1-15-2-*,但以 1 或 2 结尾的已知组除外)会从其来源处被移除,从上级目录开始,这也会移除这些包的访问权限; - 沙箱无法预配的目录(其预配错误报告在工作区根目录上报告的状态)或授权根目录本身也会在同一轮中搜索这些 ACE,因此对于更深层的条目不需要第二次请求。这种受限的遍历会报告
truncated和不可读的目录;如果被截断,请再次传入仍然失败的更深的路径。
每个更改都会备份,然后通过重新读取来验证。-AllowRoot 限制了这一切:仅当对象是该目录或严格位于其内部时才会被更改,因此工作区根目录可以自修复。永远不要将其拆分为诊断调用和修复调用,永远不要为一次修复询问两次,也不要传入不存在的模式开关。
& '<skill-directory>\scripts\diagnose-windows-sandbox-acl.ps1' -Path '<failing-path>' -AllowRoot '<authorized-directory>' -Out '<recovery-directory>'
exit $LASTEXITCODE
替换为完整的、带引号的路径。保持 -Out 持久化且归用户所有,最好放在失败的工作区旁边;切勿使用技能资源目录,该目录在技能卸载时会被删除。每次调用只传入一个路径。
运行
在受限环境中重复失败的操作。脚本会写入权限,而受限令牌无法做到这一点——在受限环境中运行它会将沙箱自身的限制报告为缺失的权限——因此请求批准执行该命令,并在非受限环境中运行。在受限环境中运行脚本永远没有意义。非受限模式不会提升 Windows 令牌。
诊断工作区写入、列表或通常可读路径的意外拒绝;对于预期内的拒绝则给予解释:在工作区外写入、read-only 下的任何写入、管道子进程 spawn EPERM、ConstrainedLanguage 错误。如果批准被拒绝或不可用,则将路径报告为“未诊断”并停止。
读取输出
每条记录都会到达 stdout、-Out 下的 acl-report-*.jsonl 文件以及最终的 RECAP 行,该行包含裁决、更改、验证、拒绝和扫描。工具输出仅保留其尾部,因此请先阅读摘要,当摘要不够时再从报告中读取特定记录。信任 verification 记录,而不是 completed 操作。根据 details.nextAction 做出决定:
nextAction | 含义 |
|---|---|
verify_original_confined_operation | 修复已验证;在受限环境中重复原始操作。 |
stop | 未修复任何内容,或拒绝终止了运行。报告并停止。 |
restore_pending_then_stop | 回滚未验证。按顺序运行打印的恢复命令,然后停止。 |
拒绝 ACE 的存在本身并不确定因果关系,并且脚本从未移除过拒绝 ACE;DSH 的 S-1-4-* 授权和 Everyone DeleteSubdirectoriesAndFiles 拒绝是预期的,不是冲突。阻止修复的拒绝 ACE 会在尝试修复后结束运行而不进行修复(REPAIR_REFUSED 或 GRANT_FAILED),并恢复其尝试的操作。每次更改都会在 -Out 中留下两个文件(acl-backup-<id>.json 及其 .ps1 文件),并且运行会打印匹配的 ROLLBACK 命令。
修复之后,以及何时停止
在受限环境中重复原始失败的操作。已验证的修复不会因为原始操作因其他原因失败而被撤消:继续处理新的观察结果,如果更深的路径仍然被拒绝,则在那里再次运行相同的单个命令——同样是一次调用,一次批准。
**在任何修复失败或被拒绝,或验证失败后停止。**脚本已恢复该次调用的更改;不要重复它或开始另一个修复,也永远不要手动移除拒绝 ACE。
**停止的运行仍然需要为用户做出决定。**指明阻塞的对象及其缺少的权限或 ACE,哪些内容被更改和回滚,按顺序的恢复命令,以及报告路径。只有用户才能解除限制,因此要求他们暂时将会话切换为 完全权限 (full access),并说明这意味着什么:在该权限下继续工作,或要求您继续调查此文件权限问题,因为报告已记录了机制和证据。然后要求他们将会话作为反馈发送,引用重要的报告记录,以便未处理的场景能够到达我们这里——只有到达此会话的内容才会随之传播。例如:
这个工作区被 Windows 文件权限挡住了:
<对象>上<缺哪个权限 / 哪条权限项>。你可以把本会话切到「完全权限」(full access) 临时继续工作;切完之后既能直接干活,也可以让我继续排查这个文件权限问题(报告里已经有机制和证据)。也麻烦把这个会话作为反馈发出去,好让我们补上这个场景。This workspace is blocked by Windows file permissions:
<object><missing right / offending entry>. Switch this session to full access (完全权限) to keep working meanwhile; then either continue your work or have me keep investigating this file-permission problem from the report. Please also send this session as feedback so we can cover the case.
禁止操作
- 手动编辑 ACL、更改所有者、擦除拒绝 ACE 或递归替换子权限;
- 通过 UAC 或
runas以提升权限运行脚本; - 扩大
-AllowRoot以到达上级目录,或重复被拒绝或失败的调用。
用用户的语言报告:分析的路径、更改、验证、恢复命令、下一步。将授权的非受限运行标记为如此,而不是沙箱修复。