Powershell: pasar una cadena json a curl

Resuelto KoenJ asked hace 10 años • 5 respuestas

Estoy intentando pasar una cadena JSON desde un script de PowerShell a la API build.phonegap.com, usando curl.
Según el foro de Phonegap , cuando se ejecuta en una máquina con Windows, los datos JSON deben formatearse como:

curl.exe -ku user@email:mypass -X PUT -d "data={\"password\":\"keypass\"}" https://build.phonegap.com/api/v1/key

De hecho, esto funciona bien cuando se invoca desde la línea de comando.
Sin embargo, cuando intento invocar esto desde un script de PowerShell, las comillas dobles parecen desaparecer.

Hasta ahora he probado:

  • Poniendo el JSON entre comillas simples:
curl.exe -ku usuario@correo electrónico:micontraseña -X PUT -d '"datos={\"contraseña\":\"contraseña clave\"}"' https://build.phonegap.com/api/v1/key
  • Poner el JSON entre comillas simples, sin las barras invertidas de escape de DOS:
curl.exe -ku usuario@correo electrónico:micontraseña -X PUT -d '"datos={"contraseña":"contraseña clave"}"' https://build.phonegap.com/api/v1/key
  • Poner el JSON entre comillas simples, escapando de las comillas dobles y las barras invertidas (estilo DOS con una barra invertida):
curl.exe -ku usuario@correo electrónico:micontraseña -X PUT -d '\"datos={\\\"contraseña\\\":\\\"contraseña clave\\\"}\"' https://build. phonegap.com/api/v1/key
  • Poner el JSON en una cadena con comillas dobles, escapando de las comillas dobles con el carácter de comilla invertida de PowerShell ( `):
curl.exe -ku usuario@correo electrónico:micontraseña -X PUT -d "`"datos={\`"contraseña\`":\`"build*2014`\`"}`"" https://build.phonegap .com/api/v1/key

¿Alguna idea de cómo lograr esto?

Gracias por tu tiempo Koen

KoenJ avatar Jul 15 '14 03:07 KoenJ
Aceptado

Intente usar el --%operador para poner PowerShell en modo de análisis de argumentos simple (tonto):

curl.exe --% -ku user@email:mypass -X PUT -d "data={\"password\":\"keypass\"}" https://build.phonegap.com/api/v1/key

Esto suele ser útil para invocar archivos ejecutables con una sintaxis de argumentos que entra en conflicto con la sintaxis de argumentos de PowerShell. Esto requiere PowerShell V3 o superior.

Keith Hill avatar Jul 15 '2014 05:07 Keith Hill

Actualizar :

  • PowerShell 7.3.0 solucionó principalmente el problema, con excepciones selectivas en Windows ; consulte esta respuesta para obtener más detalles.

  • Para código de versiones cruzadas y ediciones cruzadas, el Nativemódulo que se analiza a continuación aún puede ser de interés.

tl;dr :

En Windows PowerShell y PowerShell (Core) hasta v7.2.x , lamentablemente debe escapar manualmente los caracteres \incrustados" en los argumentos pasados ​​a programas externos .

# From inside PowerShell:
# Note the outer '...' quoting and the unexpected need to escape
# the embedded " chars. as \" (unexpected, because PowerShell itself doesn't
# require " inside '...' to be escaped; also, PowerShell's escape char. is `).
# If outer "..." quoting must be used, use \`" (sic) to escape the embeded "
curl.exe -ku user@email:mypass -X PUT -d 'data={\"password\":\"keypass\"}' https://build.phonegap.com/api/v1/key

Siga leyendo para saber por qué es necesario.


  • El carácter de escape de PowerShell es` (el llamado acento grave ), por lo que para incrustar " caracteres en una cadena "..."(entre comillas dobles, interpolada ), use`" (o "") en lugar de \"; por el contrario, dentro de una cadena '...'(entre comillas simples, textualmente ), no" es necesario escapar.

    • En su intento, PowerShell no lo vio \"como un escape " y, por lo tanto, vio múltiples "..." cadenas, que en última instancia, cuando PowerShell necesariamente aplicó su recotización bajo demanda detrás de escena, pasó dos argumentos de cadena separados que individualmente no necesitaban comillas dobles. , debido a que no contiene espacios, a saber: textualmente data={\ypassword\:\keypass\}

    • Usando las reglas de cotización de PowerShell , deberías haber usado :

      • cualquiera:

        • "data={`"password`":`"keypass`"}"
      • o, más simplemente, dado que no se necesita interpolación de cadenas, a través de una cadena palabra por palabra , entre comillas simples , dentro de la cual "caracteres. no es necesario escapar:

        • 'data={"password":"keypass"}'
      • Desafortunadamente, sin embargo, hasta PowerShell 7.2.x esto NO es suficiente ; Siga leyendo para obtener más detalles.

  • Hasta PowerShell 7.2.x, se necesita una capa adicional inesperada de escape de caracteres incrustados , usando -escaping al llamar a (la mayoría) de los programas externos"\ :

    • En Windows PowerShell hay casos extremos en los que este enfoque no funciona, en cuyo caso --%se requiere el uso de (ver más abajo). En particular, escapar '"foo bar"'no '\"foo bar\"'funciona, debido a que el encerramiento \"está al principio y al final de la cadena; consulte esta respuesta para obtener más detalles.

    • Además, algunos programas externos en Windows ""sólo entienden el escape (p. ej. msiexec); para ellos, use -replace '"', '""'para realizar mediante programación el escape adicional, asumiendo que el valor contiene al menos un espacio. Haga lo mismo con los programas que no admiten "caracteres incrustados. en absoluto (WSH), de modo que los incrustados "al menos no rompan los límites de los argumentos (pero serán eliminados).

    • Para los programas que esperan \"-escaping , use la siguiente -replaceoperación para realizar de manera robusta el escape adicional mediante programación :

      • '...' -replace '(\\*)"', '$1$1\"'
      • Si la cadena de entrada no contiene \"secuencias textuales preexistentes, puede simplificarlas a'...' -replace '"', '\"'
# Note: Escaping the embedded " chars. as `" is enough for PowerShell itself,
#       but, unfortunately, not when calling *external programs*.
#       The `-replace` operation performs the necessary additional \-escaping.
$passwd = 'foo'
curl.exe -ku user@email:mypass -X PUT -d (
  "data={`"password`": `"$passwd`"}" -replace '(\\*)"', '$1$1\"'
) https://build.phonegap.com/api/v1/key
  • Esto no debería ser necesario , pero se debe a un error desde la versión 1 que no se ha solucionado por temor a romper la compatibilidad con versiones anteriores; consulte esta respuesta .

  • PowerShell v7.3 solucionó principalmente el problema, pero con excepciones selectivas en Windows .

    • Las excepciones selectivas (consulte la descripción de la $PSNativeCommandArgumentPassingvariable de preferencia ) son desafortunadas, porque conservan el comportamiento antiguo y roto de los programas en la lista de excepciones, en particular cmd.exelos ejecutables WSH (Windows Scripting Host), así como sus archivos de script asociados ( .cmd, .bat, .js, .vbs, .wsf), con el riesgo de futuras adiciones graduales a la lista de excepciones; consulte este resumen del número 18660 de GitHub

    • Lamentablemente, se dejó pasar la oportunidad de evitar la necesidad de estas excepciones, mediante adaptaciones detrás de escena para CLI de alto perfil en Windows; consulte este resumen del número 15143 de GitHub .

  • Una función auxiliar compatible con versiones anteriores y posteriores es la iefunción del Nativemódulo ( Install-Module Native), que elimina la necesidad de un escape adicional, contiene adaptaciones importantes para CLI de alto perfil en Windows y seguirá funcionando como se esperaba incluso con la solución en lugar:
    ie curl.exe ... -d "data={`"password`": `"$passwd`"}" ... )

  • Usar --%el símbolo de parada de análisis , como en la respuesta de Keith Hill, es una solución alternativa subóptima que, sin embargo , tampoco requiere el \escape adicional :

    • --%tiene limitaciones inherentes (consulte el número 6149 de los documentos de GitHub ) y es prácticamente inútil en plataformas similares a Unix; consulte el número 4963 de los documentos de GitHub .
    • La única forma, incómoda y que produce efectos secundarios, de incrustar valores de variables de PowerShell en los siguientes argumentos --%es (a) definirlos como variables de entorno (p. ej., $env:passwd = 'foo') y (b) hacer referencia a estas variables cmd.exe-style , incluso en Unix (p. ej. , %passwd%).
  • Una solución alternativa , especialmente si necesita incluir los valores de las variables o expresiones de PowerShell en sus llamadas , es llamar vía cmd /ccon un único argumento que contenga toda la línea de comando ; Para facilitar las citas, el siguiente ejemplo utiliza una cadena aquí (consulte la sección inferior de esta respuesta para obtener una descripción general de los literales de cadena de PowerShell):

# Use @"<newline>...<newline>"@ if you need to embed PowerShell variables / expressions.
cmd /c @'
curl.exe -ku user@email:mypass -X PUT -d "data={\"password\":"\keypass\"}" https://build.phonegap.com/api/v1/key
'@
mklement0 avatar Mar 28 '2021 02:03 mklement0

Finalmente encontré la solución. En lugar de usar uno "usa 3 de ellos ( """), y listo. Entonces sería:

data={"""password""":"""keypass"""}
Andres avatar Jun 09 '2022 18:06 Andres