首页 > 解决方案 > 如何将 JSON(字符串数据)传递给 PowerShell?

问题描述

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

-debugWrite -fileName SettingsFile -jsonContent { "c": "some setting", "d":  "unknown", "b": "some thing", "a": 1 }

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

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

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

运行一个批处理文件,开始整个过程​​:

    "C:\...\script.bat" > "C:\...\script-output.txt" 2>&1

这运行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

传奇:

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

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

在上面的示例中,JSON 是:

"{ "c": "一些设置", "d": "未知", "b": "一些东西", "a": 1 }"

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

最后,一点customscript.PS1

Param (
    [Parameter(Mandatory = $True)]
    [String]
    $fileName,
    [Parameter(Mandatory = $True)]
    $jsonContent,
    [Parameter(Mandatory = $False)]
    [Switch]
    $debugWrite = $False
)
[...]

JSON 更容易看到,并且解释了空格,如果表示为:

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

标签: jsonpowershellbatch-filesyntaxquoting

解决方案


tl;博士

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

powershell.exe -File "C:\...\customscript.PS1" ... -jsonContent "{ \"c\": \"some setting\", \"d\": \"unknown\", \"b\": \"some thing\", \"a\": 1 }"

继续阅读以了解何时需要额外的转义、-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 的外壳程序,例如bash)调用。

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

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

以下命令使用简化的 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-style 环境变量引用,例如%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\" }"

-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\" }"'

从 PowerShell 本身调用

  • 从 PowerShell 调用无需转义cmd.exe元字符,因为cmd.exe不涉及。

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

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

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

    • 使用外部"..."允许您嵌入来自调用者的变量引用和表达式(在传递参数之前由调用者扩展),但它使语法复杂化,因为嵌入必须被双重转义为(原文如此):首先使用符合 PowerShell-内部语法,然后 with以满足 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\`" }"

-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\`" }'"

PowerShell核心:从bash

  • Bash 和 PowerShell 一样,既能理解扩展(内插)"..."字符串,也能理解文字'...'字符串。

  • Bash 与 不同cmd.exe,将其识别\"为转义"字符。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\" }"

-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\" }'"

推荐阅读