关于 powershell-safe-invocation
面向需要安全调用本机程序和管理文件的开发者与自动化脚本作者,提供 PowerShell 使用指南。内容涵盖参数传递、引号、编码、Shell 版本差异及执行方式选择。
主要功能
- 01结构化传递本机程序参数
- 02安全引号与脚本文件使用指南
- 03使用哈希表传递 Cmdlet 参数
- 04注意编码的文件处理
- 05检查 Shell 版本和命令语法
适用场景
- 01启动路径含空格的本机程序
- 02运行多行或嵌套引号脚本
- 03保留文件编码地进行处理
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ misaka-mikoto-tech/ agent-skills --skill powershell-safe-invocation安装后在 Claude Code 中输入/powershell-safe-invocation确认已加载。
附带文件reference.md
详细介绍
PowerShell 安全调用
Shell
除非明确要求使用 Windows PowerShell 5.1,否则请通过 pwsh.exe 使用 PowerShell 7。
如果不确定当前使用的 Shell,请进行验证:
$PSVersionTable.PSVersion
$PSNativeCommandArgumentPassing
不要假设安装 PowerShell 7 后,powershell.exe 就会使用 PowerShell 7:
pwsh.exe= PowerShell 7powershell.exe= Windows PowerShell 5.1
原生程序
如果可以分别传递参数,切勿将所有参数拼成一个命令字符串。
请使用:
$exe = 'C:\Path With Spaces\tool.exe'
$argList = @(
'--input'
'C:\Data Folder\input.json'
'--flag'
)
& $exe @argList
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
throw "$exe failed with exit code $exitCode"
}
规则:
- 将每个原生参数视为一个数组项。
- 使用
&调用存储在变量中的可执行文件路径。 - 立即捕获
$LASTEXITCODE。 - 避免将
$args用作自己的参数数组名称;它是 PowerShell 自动变量。请使用$argList或$nativeArgs等名称。 - 不要使用
Invoke-Expression。 - 不要仅为了启动可执行文件而添加
cmd.exe /c层。 - 不要在 PowerShell 中使用 Bash 风格的
\"转义。
Cmdlet
对 PowerShell cmdlet 使用哈希表展开传参:
$params = @{
LiteralPath = 'C:\Data[1]\input.txt'
Destination = 'C:\Output'
Force = $true
ErrorAction = 'Stop'
}
Copy-Item @params
当 cmdlet 支持 -LiteralPath 时,对具体路径使用该参数。对于仅提供 -Path 的 cmdlet(例如 New-Item),请使用 -Path;如果不确定,请检查 Get-Command <cmdlet> -Syntax。
不要使用 $LASTEXITCODE 来测试 PowerShell cmdlet。请使用终止错误:
$ErrorActionPreference = 'Stop'
将作为参数值传递的表达式用括号括起来,或先赋值:使用 Select-Object -Index (100..120),不要使用 -Index 100..120。
不要直接将语句语法(例如 foreach (...) { ... })的输出通过管道传递;请先赋值语句输出,或使用管道 cmdlet ForEach-Object。
复杂命令
避免使用引号嵌套过多的命令,例如:
cmd.exe /c pwsh.exe -Command "..."
对于多行代码、嵌套引号、JSON、XML、正则表达式、管道、重定向或非 ASCII 路径:
- 编写一个临时
.ps1文件。 - 使用以下命令执行:
pwsh.exe -NoLogo -NoProfile -NonInteractive -File script.ps1
除非只是简短、简单的表达式,否则优先使用 -File 而非 -Command。
除非执行策略确实阻止了受信任脚本的运行,否则不要添加 -ExecutionPolicy Bypass。
如果必须从外层 PowerShell 进程通过 -Command 传递脚本,请记住外层 Shell 会先展开 $variables。如果内层脚本包含 $p、$env:...、$PSVersionTable 等内容,请使用外层单引号脚本字符串:
pwsh.exe -NoLogo -NoProfile -Command '$p = "C:\Data Folder\input.txt"; Test-Path -LiteralPath $p'
如果命令必须经过多个解释器或包装器,请停下来改为编写 .ps1 文件,不要继续叠加引号。
字符串和多行代码
- 对字面字符串和路径使用单引号。
- 仅在需要 PowerShell 展开时使用双引号。
- 避免使用反引号进行续行;请使用数组、哈希表、展开传参、括号或脚本块。
- 不要使用 Bash 风格的 here-doc(例如
python - <<'PY');PowerShell 对<的解析方式不同。请使用临时脚本文件,或将 PowerShell here-string 通过管道传递给程序。 - 对于 JSON,请创建对象并使用
ConvertTo-Json;不要手动转义 JSON。 - 对于字面多行文本,请使用单引号 here-string:开头的
@'后不要添加任何字符,并在行首单独使用'@作为结束标记。
编码
PowerShell 7 默认以不带 BOM 的 UTF-8 输出文本;Windows PowerShell 5.1 的默认值因 cmdlet 而异。
- 创建供其他工具读取的新文本文件时,请明确指定所需编码(通常为
utf8)。 - 更改现有文本文件前,请确定并保留其现有编码。不要悄悄转换 GBK、UTF-16 或对 BOM 敏感的文件;如果编码不明确,请检查或询问。
- 默认不要设置
Console.InputEncoding或Console.OutputEncoding。只有确认终端或原生程序存在编码不匹配时才设置;$OutputEncoding则控制 PowerShell 发送给原生程序的文本。 - 不要对二进制文件应用文本编码选项。请使用字节 API 处理二进制数据。
Start-Process
对于普通的前台执行,请使用:
& $exe @argList
仅在需要提升权限、打开新窗口或隐藏窗口、分离启动或使用 shell 行为时,才使用 Start-Process。
Start-Process -ArgumentList 会将各个值拼接成命令行字符串,并非可靠的结构化参数 API。当参数边界必须精确时,优先使用 ProcessStartInfo.ArgumentList。
需要启动独立进程且参数较复杂时,请使用:
$psi = [System.Diagnostics.ProcessStartInfo]::new()
$psi.FileName = $exe
$psi.UseShellExecute = $false
foreach ($arg in $argList) {
$psi.ArgumentList.Add($arg)
}
$process = [System.Diagnostics.Process]::Start($psi)
$process.WaitForExit()
if ($process.ExitCode -ne 0) {
throw "Process failed with exit code $($process.ExitCode)"
}
文件操作
递归删除、移动或覆盖之前:
- 解析根路径和目标路径的绝对路径。
- 确认目标位于预期根目录内。
- 拒绝空路径、根级路径或非预期路径。
- 在 PowerShell 中执行文件系统更改,不要将路径传递给其他 shell。
映射的驱动器按用户/会话隔离。如果在自动化或沙盒账户下运行 Test-Path X:\... 失败,但交互运行时成功,请使用 whoami 检查当前身份,并查看 Get-PSDrive。如果映射不可见,请向用户索取 UNC 路径、为同一账户建立映射,或在平台支持时将任务切换为当前用户/完全访问执行模式。
版本和模块差异
PowerShell 5.1 和 PowerShell 7 对同一命令可能提供不同的参数或命令类型。依赖特定版本的参数之前,请在当前 shell 中验证语法:
$PSVersionTable.PSVersion
Get-Command Format-Hex -Syntax
Get-Command Get-FileHash -Syntax
例如,PowerShell 7 提供 Format-Hex -Count,而 Windows PowerShell 5.1 不支持。在 5.1 中,请改用管道限制:
Format-Hex -LiteralPath 'C:\Data\buffer.bin' | Select-Object -First 2
如果命令发现行为异常,请先检查 $env:PSModulePath 和 Get-Module -ListAvailable <ModuleName>,再判断 cmdlet 是否缺失。
决策顺序
选择最简单且安全的选项:
- PowerShell cmdlet。
& $exe @argList。- 使用
pwsh.exe -File执行临时.ps1文件。 ProcessStartInfo.ArgumentList。- 仅在需要其特殊行为时使用
Start-Process。 - 仅在需要 cmd 语义时使用
cmd.exe /c。 - 仅在严格受控且别无选择时使用
Invoke-Expression。
不常见的情况和完整示例,请参阅 reference.md。