如何将 JSON(字符串数据)传递给 PowerShell?

Yum*_*umi 2 syntax powershell json batch-file quoting

我将以下内容作为参数传递给 powershell(w7 上的 v4):

-debugWrite -fileName SettingsFile -jsonContent { "c": "some setting", "d":  "unknown", "b": "some thing", "a": 1 }
Run Code Online (Sandbox Code Playgroud)

但是 PS 被 JSON 挂断了。我试过分隔 \double-quotes\ 并将 -jsonContent 之后的所有内容放在“单引号”中,但无济于事。

这是运行 PS 的 Windows 7 (PS4) 环境:

注意:“...”混淆指的是同一个目录。IOW,所有文件都位于同一目录中。

运行一个批处理文件,开始整个事情:

    "C:\...\script.bat" > "C:\...\script-output.txt" 2>&1
Run Code Online (Sandbox Code Playgroud)

这会运行script.bat并输出到script-output.txt. script.bat是一个长的 1-liner:

%WINDIR%\sysnative\windowspowershell\v1.0\powershell.exe -ExecutionPolicy Bypass -File "C:\...\customscript.PS1" --% -fileName DropFileToCreate -jsonContent "{     "c":  "some setting",     "d":  "unknown",     "b":  "some thing",     "a":  1 }" -debugWrite
Run Code Online (Sandbox Code Playgroud)

传奇:

DropFileToCreate - 传递给 PS 脚本的文件名,用于在同一目录中创建文件。

-jsonContent- 脚本中的命名参数(见下面的标题customscript.PS1

在上面的例子中,JSON 是:

"{ "c": "some setting", "d": "unknown", "b": "something", "a": 1 }"

-debugWrite - 一个开关参数(此处用于启用 Write-Host 调试)

最后,有点customscript.PS1

Param (
    [Parameter(Mandatory = $True)]
    [String]
    $fileName,
    [Parameter(Mandatory = $True)]
    $jsonContent,
    [Parameter(Mandatory = $False)]
    [Switch]
    $debugWrite = $False
)
[...]
Run Code Online (Sandbox Code Playgroud)

JSON 更容易看到,空格解释,如果表达为:

{
 "c": "some setting",
 "d": "unknown",
 "b": "some thing",
 "a": 1 
}
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 14

tl;博士

您整体"..."封闭的 JSON 字符串已嵌入 ",必须将其转义为\"(原文如此;命令简化):

powershell.exe -File "C:\...\customscript.PS1" ... -jsonContent "{ \"c\": \"some setting\", \"d\": \"unknown\", \"b\": \"some thing\", \"a\": 1 }"
Run Code Online (Sandbox Code Playgroud)

继续阅读,了解何时需要额外的转义、-File调用与调用的不同之处-Command以及调用 shell(powershell.exe从哪里调用)的重要性。


笔记:

  • 这个答案主要讨论了Windows PowerShell可执行文件的使用 powershell.exe,但它类似地适用于 PowerShell Core可执行文件pwsh,并且有一个关于从bash底部调用的部分。

  • 下面的从 PowerShell 本身调用部分,特别是 所需的语法-File,也适用于将 JSON 传递给其他程序,例如curl.exe

PowerShell CLI所需的语法- 即powershell.exe使用参数调用-取决于

  • 无论您是从cmd.exe(命令提示符/批处理文件)调用还是从 PowerShell 本身调用(或者,在 PowerShell Core 中从类似 POSIX 的 shell调用bash)。

  • 是将参数传递给powershell -Command(内联命令)还是
    powerShell -File(脚本路径)。

无论哪种方式,您最初的尝试都无法奏效,因为文字{ "c": "some setting" ... }不能被识别为单个参数,因为包含空格并且没有整体用引号括起来;稍后添加的命令带有 enclosure "...",缺少嵌入的".

以下命令使用简化的 JSON 字符串演示了所讨论场景所需的语法。

要使-File命令可运行,请script.ps1在当前目录中创建一个文件。具有以下内容:ConvertFrom-Json $Args[0]


cmd.exe/ 批处理文件调用

  • Embedded"必须转义为\"(即使 PowerShell- 在内部您会使用`")。

  • 重要的:

    • 如果 JSON 文本包含cmd.exe 元字符(总是在\"...\"运行之间),您必须^单独对它们进行转义,因为cmd.exe由于无法识别\"为转义",将这些子字符串视为未加引号;例如,\"some & setting\"必须转义为\"some ^& setting\"; cmd.exe这里需要转义的元字符是:
      & | < > ^
  • cmd.exe- 风格的环境变量引用,例如%USERNAME% 插值-cmd.exe没有文字字符串语法,它只识别"...",确实发生插值的地方,就像在未加引号的标记中一样。
    如果您想按原样传递这样的标记,即为了抑制插值,转义语法取决于您是从命令行调用还是从批处理文件调用,遗憾的是:使用%^USERNAME%前者,%%USERNAME%%后者使用 - 请参阅这个关于血腥细节的答案

  • 请注意-Command调用如何通过将"..."字符串包含在'...'. 这是必需的,因为-CommandPowerShell 将它接收到的参数视为 PowerShell源代码而不是文字参数(后者就是-File);如果不是封闭'...',整个封闭"..."将在解释之前被剥离

-File

# With a literal string:
powershell -File ./script.ps1 "{ \"c\": \"some setting\", \"unknown\": \"b\" }"

# With an expandable string (expanded by the caller):
powershell -File ./script.ps1 "{ \"c\": \"some %USERNAME%\", \"unknown\": \"b\" }"
Run Code Online (Sandbox Code Playgroud)

-Command

# With a literal string:
powershell -Command ConvertFrom-Json '"{ \"c\": \"some setting\", \"unknown\": \"b\" }"'

# With an expandable string (expanded by the caller):
powershell -Command ConvertFrom-Json '"{ \"c\": \"some %USERNAME%\", \"unknown\": \"b\" }"'
Run Code Online (Sandbox Code Playgroud)

从 PowerShell 本身调用

  • 从 PowerShell 调用使转义cmd.exe元字符的需要消失,因为cmd.exe不涉及。

  • PowerShell 的字符串引用规则适用,这简化了问题,但遗憾的是,您仍然需要手动\转义嵌入的"字符。; 有关背景,请参阅此 GitHub 问题

    • 更新:PowerShell Core 7.2.0-preview.5 引入了一个实验性功能, PSNativeCommandArgumentPassing,无需手动\转义;尽管在这种情况下很有希望,但不能保证实验性功能成为常规功能;从 PowerShell Core 7.2.0-preview.5 开始,该功能是朝着正确方向迈出的一步,但既有缺陷,又缺乏对 WindowsCLI 的重要调整 - 请参阅GitHub 问题 #15143

    • 使用外部'...'引用简化了嵌入引用的语法,但这限制了您传递文字字符串。

    • 使用外"...",您可以从主叫嵌入变量引用和表达式(由扩大来电者之前传递参数),但它给出的语法复杂,是一个嵌入式"然后必须加倍转义为\`"(原文如此):先用`符合 PowerShell内部语法,然后\满足 PowerShell CLI的要求。

    • 如果您的 JSON 文本不是文字并存储在变量中,则必须传递
      $jsonVar -replace '"', '\"'以执行必要的转义 - 请参阅此答案

使用-File或调用外部程序时,例如curl.exe

# With a literal string:
powershell -File ./script.ps1 '{ \"c\": \"some setting\", \"unknown\": \"b\" }'

# With an expandable string (expanded by the caller):
powershell -File ./script.ps1 "{ \`"c\`": \`"some $env:OS\`", \`"unknown\`": \`"b\`" }"
Run Code Online (Sandbox Code Playgroud)

-Command

# With a literal string:
powershell -Command ConvertFrom-Json '''"{ \"c\": \"some setting\", \"unknown\": \"b\" }"'''

# With an expandable string (expanded by the caller):
powershell -Command ConvertFrom-Json "'{ \`"c\`": \`"some $env:OS\`", \`"unknown\`": \`"b\`" }'"
Run Code Online (Sandbox Code Playgroud)

PowerShell核心:从bash

  • Bash 与 PowerShell 一样,可以理解扩展(插值)"..."字符串和文字'...'字符串。

  • 与 不同cmd.exe,Bash识别\"为转义"字符。inside "...",因此无需转义 Bash 的任何元字符。

-File

# With a literal string:
pwsh -File ./script.ps1 '{ "c": "some setting", "unknown": "b" }'

# With an expandable string (expanded by the caller):
pwsh -File ./script.ps1 "{ \"c\": \"some $USER\", \"unknown\": \"b\" }"
Run Code Online (Sandbox Code Playgroud)

-Command

# With a literal string:
pwsh -Command ConvertFrom-Json \''{ "c": "some setting", "unknown": "b" }'\'

# With an expandable string (expanded by the caller):
pwsh -Command ConvertFrom-Json "'{ \"c\": \"some $USER\", \"unknown\": \"b\" }'"
Run Code Online (Sandbox Code Playgroud)