Как передать JSON (строковые данные) в PowerShell? - PullRequest
0 голосов
/ 27 ноября 2018

В качестве аргумента для powershell (v4 на w7) я передаю следующее:

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

Но PS зацикливается на JSON.Я попытался разграничить \ double-quotes \ и поместить все после -jsonContent в 'single quotes', но безрезультатно.

Вот среда Windows 7 (PS4), в которой работает PS:

примечание: "..." запутывание относится к тому же каталогу.IOW, все файлы находятся в одном каталоге.

Пакетный файл запускается, запускается весь процесс:

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

Это запускает script.bat и выводит script-output.txt.script.bat является длинным 1-строчным:

%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 
}

1 Ответ

0 голосов
/ 27 ноября 2018

tl; dr

Ваша полная "..." -замкнутая строка JSON имеет внедренный ", который должен быть экранирован как \" (sic;Упрощенная команда):

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

Читайте, когда требуется дополнительное экранирование, чем отличается вызов -File от вызова -Command и как вызывающая оболочка (откуда вы вызываете 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 / пакетный файл

  • Встроенный " должен быть экранирован как \" (хотя PowerShell- внутри вы бы использовали `").

  • Важно:

    • Если текст JSON содержит cmd.exe метасимволы (неизменно между \"...\" запусками), вы должны ^ - оставить их отдельно , потому что cmd.exe, из-за того, что \" не распознается как экранированный ", считает эти подстроки без кавычек ;например, \"some & setting\" должен быть экранирован как \"some ^& setting\";метасимволы cmd.exe, которые здесь необходимо экранировать:
      & | < > ^

    • cmd.exe в стиле ссылки на переменные окружения , такие как %USERNAME% являются интерполированными - cmd.exe не имеет буквального строкового синтаксиса, он распознает только "...", где интерполяция имеет место , так же, какв без кавычек токенов.
      Если вы хотите передать такой токен как есть, т. е. подавить интерполяцию, синтаксис экранирования зависит от того, вызываете ли вы из командная строка или командный файл , к сожалению: используйте %^USERNAME% от первого и %%USERNAME%% от второго - см. этот ответ для подробностей.

  • Обратите внимание, что вызовы -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, что упрощает ситуацию, хотя, к сожалению, вам все еще нужно вручную \ -внешний встраивать " символы. ;см. эту проблему GitHub для фона.

    • Использование внешнего цитирования '...' упрощает синтаксис для встроенного цитирования, но это ограничивает вас передачей literal строки.

    • Использование внешнего "..." позволяет встраивать переменные ссылки и выражения из вызывающей стороны (которые перед вызовом вызывают , до аргумент передается), но это усложняет синтаксис, учитывая, что встроенный " должен затем вдвойне экранироваться как \`" (sic): сначала с `, чтобы соответствовать PowerShell- внутренний синтаксис, затем с \ для удовлетворения требований 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, распознает \"как сбежал " символов.внутри "...", поэтому нет необходимости избегать метасимволов Баша.

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