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

How to pass JSON (string data) to PowerShell?

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

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

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

这里是Windows7(PS4)环境PS是运行宁在:

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

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

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

这个运行s script.bat并输出到script-output.txtscript.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 的 header)

在上面的例子中,JSON是:

"{ "c": "some setting", "d": "unknown", "b": "some thing", "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 
}

tl;dr

您的整个 "..." 封闭的 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-like shell 比如bash).

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

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

的转义

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

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


cmd.exe / 批处理文件中调用

  • 嵌入式 " 必须转义为 \"(即使 PowerShell-内部 你会使用 `" ).

  • 重要提示:

    • 如果JSON文本包含cmd.exe元字符(总是在\"...\"运行之间) ,你必须^-单独转义它们,因为cmd.exe,由于没有将\"识别为转义的",认为这些子字符串 未加引号;例如,\"some & setting\" 必须转义为 \"some ^& setting\";这里需要转义的 cmd.exe 个元字符是:
      & | < > ^
  • cmd.exe风格的环境变量引用例如%USERNAME% interpolated - cmd.exe 没有 literal 字符串语法,它只识别 "...",而 interpolation 可以 发生,就像在 unquoted 标记中一样。
    如果您想按原样传递这样的标记,即 suppress 插值,转义语法取决于您是否从 命令行 [=243] 调用=] 或 批处理文件 ,可悲的是:使用前者的 %^USERNAME%,后者的 %%USERNAME%% - 请参阅 this answer 了解详细信息。

  • 请注意 -Command 调用如何通过将 "..." 字符串括在 '...' 中来简单地添加另一层引用。这是必需的,因为使用 -Command PowerShell 将其接收的参数视为 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 的字符串引用规则适用,这简化了事情,但遗憾的是,您仍然需要手动 \-转义嵌入的 " 字符。 ;背景见 this GitHub issue

    • 更新:PowerShell Core 7.2.0-preview.5 引入了 experimental feature, PSNativeCommandArgumentPassing, which obviates the need for this manual \-escaping; even though it is very much to be hoped for in this case, experimental features aren't guaranteed to become regular features; as of PowerShell Core 7.2.0-preview.5, the feature is a step in the right direction, but is both buggy and lacks important accommodations for CLIs on Windows - see GitHub issue #15143.

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

    • 使用外部 "..." 允许您嵌入来自调用者的变量引用和表达式(由 callerbefore 传递参数),但它使语法复杂化,因为嵌入的 " 必须 double 转义为 \`" (原文如此):首先使用 ` 来符合 PowerShell-internal 语法,然后使用 \ 来满足 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 Core:从 bash

调用
  • Bash,像 PowerShell,理解扩展(内插)"..." 字符串和文字 '...' 字符串。

  • cmd.exe 不同,
  • Bash 将 \" 识别为转义的 " 字符。在 "..." 中,因此无需转义任何 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\" }'"

我建议使用变量来传递字符串。对于给出的示例 JSON,它避免了完全转义。 ConvertFrom-Json 可以用作测试应用。

首先在 PowerShell 中观察

PS C:\> $psJson = '{ "c": "some setting", "d": "unknown", "b": "some thing", "a": 1 }'
PS C:\> ConvertFrom-Json $psJson

c            d       b          a
-            -       -          -
some setting unknown some thing 1

从CMD,我们可以得到同样的结果。从批处理中打开 PowerShell 时,它会继承环境。不要传递字符串,而是设置一个环境变量并像全局变量一样使用它

C:\>set dosJson={ "c": "some setting", "d": "unknown", "b": "some thing", "a": 1 }

C:\>powershell -command "& { ConvertFrom-Json $env:dosJson }"

c            d       b          a
-            -       -          -
some setting unknown some thing 1

编辑:

应该指出,这适用于 -Command 而不是 -File,因为 PowerShell 环境不适用于 -File 参数。当然你可以运行一个脚本里面一个-Command。使用简单的测试脚本 test.ps1

C:\>type test.ps1
param ([string] $json)
ConvertFrom-Json $json
C:\>powershell -command "& { C:\test.ps1 $env:dosJson }"

c            d       b          a
-            -       -          -
some setting unknown some thing 1

所以题目中的script.bat就得改成-Command.