Как заставить ($Line_1`n$Line_2) работать в CMD-скрипте?

Я использую следующий код в файле сценария CMD

      PowerShell Add-Type -AssemblyName System.Windows.Forms;^
$Line_1 = 'Hello!';^
$Line_2 = 'How are you?';^
[System.Windows.Forms.MessageBox]::Show($Line_1)

Выше будет показано только ($Line_1)
Если ($Line_1`n$Line_2) используется, ничего не будет показано.

Как мне показать оба $Line_1 и $Line_2?

3 ответа

Решение

Очевидно $Line_1 + "`n" + $Line_2 и "$Line_1`n$Line_2"работает нормально. Просто сложно отправить командную строку в PowerShell из cmd с его устаревшими причудами, потому что:

PowerShell ожидает, что команда будет представлена ​​в виде одной строки в последнем параметре, поэтому вам нужно заключить все в кавычки или избежать всех разделителей. Самое простое решение - использовать одну строку и избегать кавычек следующим образом

      PowerShell "Add-Type -AssemblyName System.Windows.Forms; $Line_1 = 'Hello!'; $Line_2 = 'How are you?'; [System.Windows.Forms.MessageBox]::Show($Line_1 + \"`n\" + $Line_2)"

Если вы хотите поместить команды в несколько строк, вы не можете заключить строку в кавычки. Чтобы представить все это как один аргумент, теперь вам нужно экранировать все пробелы (вам почему-то не нужно экранировать ; в этом случае, возможно потому, что после передачи командной строки в PowerShell он вызывает GetCommandLineW и снова разбирает все само)

      PowerShell Add-Type^ -AssemblyName^ System.Windows.Forms;^
$Line_1^ =^ 'Hello!';^
$Line_2^ =^ 'How^ are^ you?';^
[Windows.Forms.MessageBox]::Show($Line_1^ +^ \"`n\"^ +^ $Line_2)"

В качестве альтернативы вы можете избежать этого "`n" строка, получив новую строку напрямую с помощью [char]10

      PowerShell -Command Add-Type -AssemblyName System.Windows.Forms;^
$Line_1 = 'Hello!';^
$Line_2 = 'How are you?';^
[System.Windows.Forms.MessageBox]::Show($Line_1 + [char]10 + $Line_2)

Наконец, решение, которое работает без каких-либо побегов, которое использует EncodedCommandпараметр PowerShell, который получает строку в кодировке base64 командной строки UTF-16. Вы можете получить закодированную версию, запустив ее в PowerShell.

      $str = @'
>> Add-Type -AssemblyName System.Windows.Forms;
>> $Line_1 = 'Hello!';
>> $Line_2 = 'How are you?';
>> [System.Windows.Forms.MessageBox]::Show($Line_1 + "`n" + $Line_2)
>> '@
PS C:\Users\phucl> [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($str))
QQBkAGQALQBUAHkAcABlACAALQBBAHMAcwBlAG0AYgBsAHkATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwA7AAoAIAA9ACAAJwBIAGUAbABsAG8AIQAnADsACgAgAD0AIAAnAEgAbwB3ACAAYQByAGUAIAB5AG8AdQA/ACcAOwAKAFsAUwB5AHMAdABlAG0ALgBXAGkAbgBkAG8AdwBzAC4ARgBvAHIAbQBzAC4ATQBlAHMAcwBhAGcAZQBCAG8AeABdADoAOgBTAGgAbwB3ACgAIAArACAAIgAKACIAIAArACAAKQA=

После наличия закодированной версии вы можете вызвать это из cmd

      PowerShell -EncodedCommand QQBkAGQALQBUAHkAcABlACAALQBBAHMAcwBlAG0AYgBsAHkATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwA7AAoAJABMAGkAbgBlAF8AMQAgAD0AIAAnAEgAZQBsAGwAbwAhACcAOwAKACQATABpAG4AZQBfADIAIAA9ACAAJwBIAG8AdwAgAGEAcgBlACAAeQBvAHUAPwAnADsACgBbAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwAuAE0AZQBzAHMAYQBnAGUAQgBvAHgAXQA6ADoAUwBoAG8AdwAoACQATABpAG4AZQBfADEAIAArACAAIgBgAG4AIgAgACsAIAAkAEwAaQBuAGUAXwAyACkA

Ответ phuclv содержит хорошую справочную информацию и жизнеспособные решения.

Самое простое решение:

      PowerShell -c Add-Type -AssemblyName System.Windows.Forms;^
$Line_1 = 'Hello!';^
$Line_2 = 'How are you?';^
[System.Windows.Forms.MessageBox]::Show(\"$Line_1`nLine2\")

Обратите внимание, что я явно добавил имя параметра (), чтобы сигнализировать о том, что передается командная строка PowerShell. Хотя это не обязательно в Windows PowerShell , которая по умолчанию используется, она находится в PowerShell (Core) 7+, где теперь используется по умолчанию - см. Документацию CLI для Windows PowerShell и PowerShell (Core) 7+.

То есть вы должны использовать $Line_1`n$Line_2внутри - расширяемая строка , и вы должны \-экранировать символы, чтобы PowerShell не удалял их в ходе синтаксического анализа командной строки (при отсутствии общих двойных кавычек, """ тоже работает).

Предостережения :

  • Этот многострочный метод, который синтаксически не может использовать внешние кавычки для всей команды, требует тщательного экранирования всех метасимволов, которые должны быть переданы в PowerShell , особенно >, , и |- если эти символы не входят в подстроку, заключенную в двойные кавычки; например, & помещенный внутри \"...\" строка - например \"$Line_1`n & $Line_2\"- должен не быть убежал.

    • В виде исключения метасимвол % всегда нужно экранировать как %%.
  • Каждый оператор должен быть завершен (как вы это сделали), потому что продолжение строки ( ^) Приводит не новой строки между строк ввода, поэтому PowerShell видит их как одну линию , на которой должно быть несколько операторов ;-разделено.

  • Потому что ни cmd.exeни начальный синтаксический анализ командной строки PowerShell не знает о строках в одинарных кавычках ( '...'), такие строки разбиваются на несколько аргументов, если они содержат пробелы, что означает, что, по сути, выполнение нескольких смежных пробелов внутри таких строк нормализуется до одного пробела каждая. Например, 'How are you?', в конечном итоге рассматривается как 'How are you?'от PowerShell; чтобы этого избежать, используйте двойные кавычки (с \"-эскейп).


Как PowerShell анализирует аргументы, переданные его CLI -Command / -c параметр:

PowerShell дает вам выбор между передачей командной строки

  • либо: как один аргумент, заключенный в общее; например:

    • powershell -c "Get-Date -Format 'yyyy MMM'"
  • или: несколько аргументов - возможно, индивидуально "..."-quoted - к ​​которому PowerShell затем присоединяется, чтобы сформировать единую строку; например:

    • powershell -c Get-Date -Format "'yyyy MMM'"

В обоих случаях неэкранированные символы удаляются из аргументов, поскольку предполагается, что они имеют просто синтаксическую функцию ради командной строки, а не результирующей команды PowerShell.

После удаления синтаксиса "и объединяя полученные аргументы с пробелами, если применимо, Powershell интерпретирует полученную строку как код PowerShell .

Примечание: это принципиально отличается от того, как анализируются аргументы при использовании -FileПараметр CLI для вызова файла сценария и передачи ему аргументов - подробнее см. В этом ответе .

Есть несколько способов объединения строк, которые вы можете найти, но, вероятно, самый простой способ - использовать символ +. `n - это символ новой строки, который помещает Строку 2 под строкой 1. Обратите внимание, что` - это символ обратной кавычки (обычно на той же клавише, что и тильда ~)

      [System.Windows.Forms.MessageBox]::Show($Line_1 + "`n" + $Line_2)

Посмотрев еще раз на ваш пост, я заметил, что вы были близки с ($Line_1`n $Line_2). Вам не хватает только некоторых двойных кавычек

      [System.Windows.Forms.MessageBox]::Show("$Line_1`n$Line_2")

Powershell с радостью заменяет переменные их значениями, помещенными в двойные кавычки. Вы можете узнать больше о расширяемых строках здесь и здесь

Другие вопросы по тегам