我正在尝试使用curl 将 JSON 字符串从 powershell 脚本内传递到 build.phonegap.com api。
根据 phonegap 论坛,在 Windows 计算机上运行时,必须格式化 JSON 数据如:
curl.exe -ku user@email:mypass -X PUT -d "data={\"password\":\"keypass\"}" https://build.phonegap.com/api/v1/key
Indeed, this does run fine when invoked from the command line.
However, when I try to invoke this from within a powershell script, the double quotes seem to be stripped.
到目前为止,我已经尝试过:
curl.exe -ku user@email:mypass -X PUT -d '"data={\"password\":\"keypass\"}"' https://build.phonegap.com/api/v1/key
- 将 JSON 放入单引号字符串中,无需 DOS 转义反斜杠:
curl.exe -ku user@email:mypass -X PUT -d '"data={"password":"keypass"}"' https://build.phonegap.com/api/v1/key
- 将 JSON 放在单引号字符串中,转义双引号和反斜杠(带反斜杠的 DOS 风格):
curl.exe -ku user@email:mypass -X PUT -d '\"data={\\\"password\\\":\\\"keypass\\\"}\"' https://build.phonegap.com/api/v1/key
- 将 JSON 放在双引号字符串中,使用 powershell 反引号字符转义双引号 (
`
):
curl.exe -ku user@email:mypass -X PUT -d "`"data={\`"password\`":\`"build*2014`\`"}`"" https://build.phonegap.com/api/v1/key
知道如何实现这一目标吗?
感谢您抽出时间,
科恩
I'm trying to pass a JSON string from within a powershell script to the build.phonegap.com api, using curl.
According to phonegap's forum, when running on a Windows machine, the JSON data has to be formatted as:
curl.exe -ku user@email:mypass -X PUT -d "data={\"password\":\"keypass\"}" https://build.phonegap.com/api/v1/key
Indeed, this does run fine when invoked from the command line.
However, when I try to invoke this from within a powershell script, the double quotes seem to be stripped.
So far, I have tried:
- Putting the JSON in single quoted string:
curl.exe -ku user@email:mypass -X PUT -d '"data={\"password\":\"keypass\"}"' https://build.phonegap.com/api/v1/key
- Putting the JSON in single quoted string, without the DOS escape backslashes:
curl.exe -ku user@email:mypass -X PUT -d '"data={"password":"keypass"}"' https://build.phonegap.com/api/v1/key
- Putting the JSON in single quoted string, escaping the double quotes and backslashes (DOS style with a backslash):
curl.exe -ku user@email:mypass -X PUT -d '\"data={\\\"password\\\":\\\"keypass\\\"}\"' https://build.phonegap.com/api/v1/key
- Putting the JSON in a double quoted string, escaping the double quotes with the powershell backtick character (
`
):
curl.exe -ku user@email:mypass -X PUT -d "`"data={\`"password\`":\`"build*2014`\`"}`"" https://build.phonegap.com/api/v1/key
Any idea how to achieve this?
Thanks for your time,
Koen
发布评论
评论(6)
尝试使用
--%
运算符将 PowerShell 置于简单(哑)参数解析模式:这对于使用与 PowerShell 参数语法相冲突的参数语法调用 exe 通常很有用。这确实需要 PowerShell V3 或更高版本。
Try using the
--%
operator to put PowerShell into simple (dumb) argument parsing mode:This is quite often useful for invoking exes with argument syntax that runs afoul of PowerShell's argument syntax. This does require PowerShell V3 or higher.
更新:
PowerShell 7.3.0 大部分修复了问题,Windows上有选择性例外 - 请参阅此答案以及下面的详细信息。
对于跨版本、跨版本、跨平台代码,下面讨论的
Native
模块可能仍然令人感兴趣。tl;dr:
在 Windows PowerShell 和 PowerShell (Core) 7 至 v7.2.x,不幸的是,您必须手动
\
-转义参数传递给外部程序中嵌入的"
字符。请继续阅读以了解原因
PowerShell 的转义
`
(所谓的反引号),因此为了嵌入"
中的字符"..."
(双引号,插值)字符串,使用`"
(或""
) 而不是\"
;相比之下,在'...'
(单引号,逐字)字符串中,"
需要不需要逃脱。在您的尝试中,PowerShell 并未将
\"
视为转义"
,因此看到多个< /em>"..."
字符串,最终 - 当 PowerShell 需要在幕后应用其按需重新引用时,传递了两个 > 由于不包含,单独的字符串参数不需要双引号空格,即:逐字data={\
和password\:\keypass\}
使用 PowerShell的引用规则,你应该用过:
要么:
"data={`"password`":`"keypass`"}"
或者,更简单地说,假设不需要字符串插值,通过逐字、单引用的字符串,其中
"< /code> 字符不需要转义:
'data={"password":"keypass"}'
不幸的是,然而,直到 PowerShell 7.2.x,这还不够;请继续阅读以了解详细信息。
直到 PowerShell 7.2.x,需要使用
\
对嵌入的"
字符进行意外的额外转义层 -调用(大多数)外部程序时转义:在Windows PowerShell中,存在边缘情况此方法不起作用,在这种情况下使用
--%
是必需的(见下文)。值得注意的是,将'"foo bar"'
转义为'\"foo bar\"'
不起作用,因为包含\"
位于字符串的开头和结尾 - 有关详细信息,请参阅此答案。此外,Windows 上的一些外部程序仅理解
""
-转义(例如msiexec
);对于它们,请使用-replace '"', '""'
以编程方式执行额外的转义,假设该值至少包含一个空格。对不支持嵌入 < 的程序执行相同的操作代码>“字符。完全(WSH),这样嵌入的"
至少不会打破参数边界(但它们将被剥离)。对于需要
\"
-转义的程序,请使用以下-replace
操作来稳健执行额外的操作以编程方式转义:'...' - 替换 '(\\*)"', '$1$1\"'
\"
序列,您可以简化为'...' -replace '"', '\" '
或者,为了获得更好的性能,'...'.Replace('"', '\"')
这不是必需的,但这是由于 v1 以来的错误由于担心破坏向后兼容性,该问题尚未修复 - 请参阅这个答案。
PowerShell v7.3 大部分解决了该问题,但Windows 上有选择性例外。
选择性例外 - 请参阅
$PSNativeCommandArgumentPassing
首选项变量 - 不幸的是,因为它们保留了例外列表中的程序的旧的、损坏的行为,特别是cmd.exe
和 WSH(Windows 脚本主机)可执行文件及其关联的脚本文件 (.cmd
、.bat
、.js
、.vbs
、.wsf
),以及未来的风险,零碎地添加到例外列表中- 请参阅 GitHub 问题 #18660的摘要
遗憾的是,通过 Windows 上备受瞩目的 CLI 的幕后调整来避免这些例外的机会被放弃了;请参阅 GitHub 问题 #15143 中的摘要。
向后和向前兼容的辅助函数是来自
Native
module (Install-Module Native
),它消除了额外转义的需要,包含高层人士的重要住宿即使修复到位,和 Windows 上的 CLI 将继续按预期工作:即curl.exe ... -d "data={`"password`": `"$passwd`"}" ...
)使用
-- %
,停止解析符号,如 Keith Hill 的答案 是一个次优解决方法,也不需要额外的\
-转义,但是:--%
具有固有的局限性 - 请参阅 GitHub 文档问题 #6149 - 在类 Unix 平台上几乎没有用 - 请参阅 GitHub 文档问题 #4963。--%
后面的参数中嵌入 PowerShell 变量值的唯一 - 尴尬且产生副作用 - 的方法是 (a) 将它们定义为 >环境变量(例如,$env:passwd = 'foo'
)和(b)引用这些变量cmd.exe
-style< /em>,甚至在 Unix 上(例如,%passwd%
)。替代解决方法 - 特别是如果您需要在调用中包含 PowerShell 变量或表达式的值 > - 是通过
cmd /c
调用,并使用包含整个命令行的单个参数;为了引用方便,以下示例使用此处字符串(请参阅此答案的底部部分 有关 PowerShell 字符串文字的概述):Update:
PowerShell 7.3.0 mostly fixed the problem, with selective exceptions on Windows - see this answer and further below for details.
For cross-version, cross-edition, cross-platform code, the
Native
module discussed below may still be of interest.tl;dr:
In Windows PowerShell and PowerShell (Core) 7 up to v7.2.x, you unfortunately must manually
\
-escape embedded"
characters in arguments passed to external programs.Read on for why that is necessary.
PowerShell's escape character is
`
(the so-called backtick), so in order to embed"
characters in a"..."
(double-quoted, interpolating) string, use`"
(or""
) rather than\"
; by contrast, inside a'...'
(single-quoted, verbatim) string,"
need not be escaped.In your attempt, PowerShell didn't see
\"
as an escaped"
and therefore saw multiple"..."
strings, which ultimately - when PowerShell of necessity applied its on demand re-quoting behind the scenes, passed two separate string arguments that individually didn't need double-quoting, due to not containing spaces, namely: verbatimdata={\
andpassword\:\keypass\}
Using PowerShell's quoting rules, you should have used:
either:
"data={`"password`":`"keypass`"}"
or, more simply, given that no string interpolation is needed, via a verbatim, single-quoted string, inside of which
"
chars. don't require escaping:'data={"password":"keypass"}'
Unfortunately, however, up to PowerShell 7.2.x this is NOT enough; read on for details.
Up to PowerShell 7.2.x, an unexpected extra layer of escaping of embedded
"
characters is needed, using\
-escaping when calling (most) external programs:In Windows PowerShell there are edge cases where this approach doesn't work, in which case use of
--%
is required (see below). Notably, escaping'"foo bar"'
as'\"foo bar\"'
doesn't work, due to the enclosing\"
being at the very start and end of the string - see this answer for details.Also, some external programs on Windows understand
""
-escaping only (e.g.msiexec
); for them, use-replace '"', '""'
in order to programmatically perform the extra escaping, assuming the value contains at least one space. Do the same for programs that do not support embedded"
chars. at all (WSH), so that the embedded"
at least do not break argument boundaries (but they will be stripped).For programs that expect
\"
-escaping, use the following-replace
operation to robustly perform the extra escaping programmatically:'...' -replace '(\\*)"', '$1$1\"'
\"
sequences, you can simplify to'...' -replace '"', '\"'
or, for better performance,'...'.Replace('"', '\"')
This shouldn't be required, but is due to a bug since v1 that hasn't been fixed for fear of breaking backward compatibility - see this answer.
PowerShell v7.3 mostly fixed the issue, but with selective exceptions on Windows.
The selective exceptions - see the description of the
$PSNativeCommandArgumentPassing
preference variable - are unfortunate, because they retain the old, broken behavior for the programs on the exception list, notablycmd.exe
and the WSH (Windows Scripting Host) excecutables as well as their associated script files (.cmd
,.bat
,.js
,.vbs
,.wsf
), with the risk of future, piecemeal additions to the exception list - see this summary from GitHub issue #18660Sadly, an opportunity to avoid the need for these exceptions - via behind-the-scenes accommodations for high-profile CLIs on Windows - was passed up; see this summary from GitHub issue #15143.
A backward- and forward-compatible helper function is the
ie
function from theNative
module (Install-Module Native
), which obviates the need for the extra escaping, contains important accommodations for high-profile CLIs on Windows, and will continue to work as expected even with the fix in place:ie curl.exe ... -d "data={`"password`": `"$passwd`"}" ...
)Using
--%
, the stop-parsing symbol, as in Keith Hill's answer is a suboptimal workaround that also doesn't require the extra\
-escaping, however:--%
has inherent limitations - see GitHub docs issue #6149 - and is virtually useless on Unix-like platforms - see GitHub docs issue #4963.--%
is to (a) define them as environment variables (e.g.,$env:passwd = 'foo'
) and (b) to reference these variablescmd.exe
-style, even on Unix (e.g.,%passwd%
).An alternative workaround - especially if you need to include the values of PowerShell variables or expressions in your calls - is to call via
cmd /c
with a single argument containing the entire command line; for quoting convenience, the following example uses a here-string (see the bottom section of this answer for an overview of PowerShell's string literals):终于找到了解决办法。我不使用一个
"
,而是使用其中的 3 个 ("""
),仅此而已。所以它会是:Finally found the solution. Istead of using one
"
use 3 of them ("""
), and thats it. So it would be:以下是我如何在 PowerShell 7.2 中成功发送 json 请求
Here's how I did manage to send a json request in PowerShell 7.2
我发现以下方法比转义字符更具可读性,并且在脚本中运行良好:
$( ) 在curl 本身之前执行,将哈希表对象转换为json。
关于 Convertto-json 的 Microsoft 文档:
https:// learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json?view=powershell-7.4
I found the following way to be more readable than escaping the char and work fine inside scripts:
The $( ) is executed before the curl itself, converting the hashtable object to json.
Microsoft documentation on the convertto-json:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json?view=powershell-7.4
设置内容类型:
Set the content type: