简体   繁体   English

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

[英]How to pass JSON (string data) to PowerShell?

I'm passing the following as an argument to powershell (v4 on w7):我将以下内容作为参数传递给 powershell(w7 上的 v4):

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

But PS gets hung up on the JSON.但是 PS 被 JSON 挂断了。 I've tried delimiting the \\double-quotes\\ and putting everything after -jsonContent in 'single quotes', but to no avail.我试过分隔 \\double-quotes\\ 并将 -jsonContent 之后的所有内容放在“单引号”中,但无济于事。

Here is the Windows 7 (PS4) environment PS is running in:这是运行 PS 的 Windows 7 (PS4) 环境:

note: "..." obfuscation refers to the same dir.注意:“...”混淆指的是同一个目录。 IOW, all files live in the same directory. IOW,所有文件都位于同一目录中。

A batch file is run, kicking off the whole thing:运行一个批处理文件,开始整个事情:

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

This runs script.bat and outputs to script-output.txt .这将运行script.bat并输出到script-output.txt script.bat is a long 1-liner: 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

Legend:传奇:

DropFileToCreate - the filename passed to the PS script, used to create a file in same dir. DropFileToCreate - 传递给 PS 脚本的文件名,用于在同一目录中创建文件。

-jsonContent - A named parameter in the script (see below for header of customscript.PS1 ) -jsonContent - 脚本中的命名参数(请参阅下面的customscript.PS1标头)

In the above example, the JSON is:在上面的例子中,JSON 是:

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

-debugWrite - A switch parameter (used here to enable Write-Host debugging) -debugWrite - 开关参数(此处用于启用 Write-Host 调试)

Finally, a bit of the customscript.PS1 :最后,一些customscript.PS1

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

The JSON is easier seen, and spaces explained, if expressed as: JSON 更容易看到,空格解释,如果表达为:

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

tl;dr tl;博士

Your overall "..." -enclosed JSON string has embedded " , which must be escaped as \\" (sic; command simplified):您的整体"..."封闭的 JSON 字符串已嵌入" ,必须将其转义为\\" (原文如此;命令已简化):

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

Read on for when additional escaping is needed, how -File invocation differs from -Command invocation, and in what way the calling shell (where you call powershell.exe from) matters.请继续阅读时需要额外的转义,如何-File的调用不同于-Command调用,以及以何种方式调用shell(如你拨打powershell.exe从)事宜。


Note:笔记:

  • This answer primarily discusses use of the Windows PowerShell executable, powershell.exe , but it applies analogously to the PowerShell Core executable, pwsh , and there's a section on calling from bash at the bottom.此答案主要讨论了Windows PowerShell可执行文件powershell.exe ,但它类似于 PowerShell Core可执行文件pwsh ,并且底部有一个关于从bash调用的部分。

  • The section Calling from PowerShell itself below, specifically the syntax required with -File , applies to passing JSON to other programs such as curl.exe as well.从自身的PowerShell下面,特别是与所需的语法调用部分-File ,适用于通过JSON到其他程序如curl.exe为好。

The required syntax for the PowerShell CLI - that is, invoking powershell.exe with arguments - depends on : PowerShell CLI所需的语法- 即使用参数调用powershell.exe -取决于

  • whether you're calling from cmd.exe (Command Prompt / batch file) or from PowerShell itself (or, in PowerShell Core from a POSIX-like shell such as bash ).无论您是从cmd.exe (命令提示符/批处理文件)还是从 PowerShell 本身(或者,在 PowerShell Core 中从类似 POSIX 的 shell 调用,例如bash )。

  • whether you pass arguments to powershell -Command (inline command) or是否将参数传递给powershell -Command (内联命令)或
    powerShell -File (script path). powerShell -File (脚本路径)。

Either way, your original attempt could not have worked, because literal { "c": "some setting" ... } cannot be recognized as a single argument , due to containing whitespace and not being enclosed in quotes overall;无论哪种方式,您最初的尝试都无法奏效,因为文字{ "c": "some setting" ... }不能被识别为单个参数,因为包含空格不是整体用引号括起来 the command added later, with enclosing "..." , lacks escaping of the embedded " .后来添加的命令,包含"..." ,缺少对嵌入的"转义。

The following commands demonstrate the required syntax for the scenarios discussed, using a simplified JSON string.以下命令使用简化的 JSON 字符串演示了所讨论场景所需的语法。

To make the -File commands runnable, create a script.ps1 file in the current dir.要使-File命令可运行,请在当前目录中创建一个script.ps1文件。 with the following content: ConvertFrom-Json $Args[0]具有以下内容: ConvertFrom-Json $Args[0]


Calling from cmd.exe / a batch filecmd.exe / 批处理文件调用

  • Embedded " must be escaped as \\" (even though PowerShell- internally you'd use `" ).嵌入的"必须转义为\\" (即使 PowerShell - 在内部你会使用`" )。

  • Important:重要的:

    • If the JSON text contains cmd.exe metacharacters (invariably between \\"...\\" runs), you must ^ -escape them individually , because cmd.exe , due to not recognizing \\" as an escaped " , considers these substrings unquoted ;如果 JSON 文本包含cmd.exe元字符(总是在\\"...\\"运行之间),则必须单独^ -escape 它们,因为cmd.exe由于未将\\"识别为转义的" ,将这些子字符串视为未加引号; eg, \\"some & setting\\" must be escaped as \\"some ^& setting\\" ;例如, \\"some & setting\\"必须转义为\\"some ^& setting\\" the cmd.exe metacharacters that need escaping here are:这里需要转义的cmd.exe元字符是:
      & | < > ^
  • cmd.exe -style environment-variable references such as %USERNAME% are interpolated - cmd.exe has no literal string syntax, it only recognizes "..." , where interpolation does take place, just as in unquoted tokens. cmd.exe风格的环境变量引用,例如%USERNAME%内插的- cmd.exe没有文字字符串语法,它只识别"..." ,其中确实发生了内插,就像在未加引号的标记中一样。
    If you want to pass such a token as-is, ie, to suppress interpolation, the escaping syntax depends on whether you're calling from the command line or a batch file , sadly: use %^USERNAME% from the former, and %%USERNAME%% from the latter - see this answer for the gory details.如果您想按原样传递这样的标记,即抑制插值,转义语法取决于您是从命令行调用还是从批处理文件调用,遗憾的是:使用前者的%^USERNAME%%%USERNAME%%来自后者的%%USERNAME%% - 有关血腥细节,请参阅此答案

  • Note how the -Command calls simply add another layer of quoting, by enclosing the "..." string in '...' .请注意-Command调用如何通过将"..."字符串包含在'...'简单地添加另一层引用。 This is required, because with -Command PowerShell treats the arguments it receives as PowerShell source code rather than as literal arguments (the latter is what happens with -File );这是必需的,因为使用-Command PowerShell 将其接收到的参数视为 PowerShell源代码而不是文字参数(后者是-File发生的情况); if it weren't for the enclosing '...' , the overall enclosing "..." would be stripped before interpretation.如果不是封闭的'...' ,整个封闭的"..."将在解释之前被剥离

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

With -Command :使用-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\" }"'

Calling from PowerShell itself从 PowerShell 本身调用

  • Calling from PowerShell makes the need to escape cmd.exe metacharacters go away, because cmd.exe is not involved.从 PowerShell 调用使转义cmd.exe元字符的需要消失,因为cmd.exe不涉及。

  • PowerShell's string-quoting rules apply, which simplifies matters, although, sadly, you still need to manually \\ -escape embedded " chars. ; see this GitHub issue for background. PowerShell 的字符串引用规则适用,这简化了问题,但遗憾的是,您仍然需要手动\\ -escape 嵌入的"字符。请参阅此 GitHub 问题以了解背景。

    • Update : PowerShell Core 7.2.0-preview.5 introduced an experimental feature , PSNativeCommandArgumentPassing , which obviates the need for this manual \\ -escaping;更新:PowerShell Core 7.2.0-preview.5 引入了一项实验性功能PSNativeCommandArgumentPassing ,无需使用本手册\\ -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 .从 PowerShell Core 7.2.0-preview.5 开始,该功能是朝着正确方向迈出的一步,但既有缺陷,又缺乏对 WindowsCLI 的重要调整 - 请参阅GitHub 问题 #15143

    • Using outer '...' quoting simplifies the syntax for the embedded quoting, but that limits you to passing literal strings.使用外部'...'引用简化了嵌入引用的语法,但这限制了您传递文字字符串。

    • Using outer "..." allows you to embed variable references and expressions from the caller (which are expanded by the caller , before the argument is passed), but it complicates the syntax, given that an embedded " must then be doubly escaped as \\`" (sic): first with ` to conform to PowerShell- internal syntax, then with \\ to satisfy the PowerShell CLI 's requirements.使用外部"..."允许您嵌入来自调用者的变量引用和表达式(传递参数之前调用者扩展),但它使语法复杂化,因为必须将嵌入的"双重转义为\\`" (原文如此):首先使用`以符合 PowerShell内部语法,然后使用\\来满足 PowerShell CLI的要求。

    • If your JSON text is not a literal and stored in a variable , you must pass如果您的 JSON 文本不是文字并存储在变量中,则必须通过
      $jsonVar -replace '"', '\\"' to perform the necessary escaping - see this answer . $jsonVar -replace '"', '\\"'执行必要的转义 - 请参阅此答案

With -File or when calling external programs such as curl.exe :使用-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\`" }"

With -Command :使用-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 : Calling from bash PowerShell核心:从bash调用

  • Bash, like PowerShell, understands both expanding (interpolating) "..." strings and literal '...' strings. Bash 与 PowerShell 一样,可以理解扩展(插入) "..."字符串和文字'...'字符串。

  • Bash, unlike cmd.exe , recognizes \\" as escaped " chars.cmd.exe不同,Bash 将\\"识别为转义的"字符。 inside "..." , so there's no need to escape any of Bash's metacharacters."..." ,因此无需转义 Bash 的任何元字符。

With -File :使用-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\" }"

With -Command :使用-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\" }'"

I would suggest using a variable to pass the string.我建议使用变量来传递字符串。 For the example JSON given, it avoids escaping entirely.对于给出的示例 JSON,它完全避免了转义。 ConvertFrom-Json can be used as a test app. ConvertFrom-Json可以用作测试应用程序。

First in PowerShell, observe首先在 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

From CMD, we can achieve the same result.从 CMD 中,我们可以达到相同的结果。 When PowerShell is opened from a batch, it inherits the environment.从批处理中打开 PowerShell 时,它会继承环境。 Instead of passing the string, set an environment variable and use it like a global不是传递字符串,而是设置一个环境变量并将其用作全局变量

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

EDIT:编辑:

It should be pointed out that this works for -Command and not -File , because the PowerShell environment is not available to the -File args.应该指出的是,这适用于-Command而不是-File ,因为PowerShell的环境是不可用的-File ARGS。 Of course you can run a script inside a -Command .当然,您可以在-Command运行脚本。 Using a trivial test script test.ps1使用一个简单的测试脚本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

So the script.bat in the question would have to be changed to -Command .因此,问题中的script.bat必须更改为-Command

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM