Invoke-Expression
(со встроенным псевдонимом iex
) и &
, оператор вызова , служат различным целям:
Invoke-Expression
оценивает данную строку как исходный код PowerShell , как если бы вы выполнили содержимое строки непосредственно как команду.
Как таковой, он аналогичен eval
в bash
и, следовательно, только для использования с входом, который полностью находится под контролем вызывающего абонента или входом, которому вызывающий абонент доверяет .
Часто существуют лучшие решения, поэтому Выражение вызова, как правило, следует избегать
&
используется для вызова команды (& <nameOrPath> [...]
) или блока сценария (& { ... } [...]
) :
- Ни один из случаев не предполагает оценку строки в качестве исходного кода.
В данном случае:
ядром вашей команды является следующее выражение, котороеich возвращает string
"echo 'helloworld'"
(его содержимое не включает в себя "
- это просто представление результирующей строки в виде строкового литерала PowerShell):
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('ZWNobyAnaGVsbG93b3JsZCc='))
Также обратите внимание, что из-за синтаксического анализа командной строки ""...""
, окружающий основное выражение в ваших исходных командах, эффективно игнорируется , что объясняет, почему выражение выполняется вместо того, чтобы рассматриваться как содержимое строки. [1]
Следовательно, ваши две команды составляют:
[1] Необязательное чтение: проблемы цитирования PowerShell при вызове внешних программ
Примечание:
Обработка цитирования по отношению к внешним программам или при вызове из внешних программНасколько я могу судить, не является частью официальной документации (на момент написания статьи ни about_Parsing , ни about_Quoting_Rules , ни about_Special_Characters не упоминали об этом - я открыл эта проблема на GitHub для решения этой проблемы).
Существуют недостатки в существующей обработке, но они не могут быть исправлены без нарушения обратной совместимости.
При звонке из PowerShellПервый подход заключается в использовании блока сценариев , который обходит проблемы цитирования - см. ниже.
Даже если вы правильно встраивали "
, экранируя их как ""
внутри общей строки "..."
из PowerShell- внутренняя перспектива, требуется дополнительное экранирование "
с \
для передачи их во внешнюю программу , даже если эта внешняя программа является другим экземпляром PowerShell, вызываемым черезpowershell.exe
.
Возьмите этот упрощенный пример:
powershell.exe -command " ""hi"" " # !! BROKEN
powershell.exe -command ' "hi" ' # !! BROKEN
Внутренняя оболочка PowerShell, " ""hi"" "
и ' "hi" '
преобразуются в строку с буквальным содержимым "hi"
, которая при выполнении печатает hi
.
К сожалению, PowerShell передает эту строку в powershell.exe
как " "hi" "
- обратите внимание, как ""
превратился в обычный "
, и включающие одинарные кавычки были заменены двойными кавычками -что фактически приводит к hi
после анализа новым экземпляром (потому что " "hi" "
анализируется как конкатенация подстрок " "
, hi
и " "
), поэтому PowerShell завершает попыткувыполнить (предположительно несуществующую) команду с именем hi
.
В отличие от этого, если вам удастся передать внедренное значение как "
как \"
(sic) - после удовлетворения собственных потребностей PowerShell в экранировании - команда работает так, как задумано.Поэтому, как указано, вам необходимо объединить внутреннее экранирование PowerShell с экранированием для CLI, чтобы пропустить встроенный "
, чтобы:
- внутри в целом
"..."
, каждый встроенный "
должен быть экранирован как \""
(sic) или \`"
(sic) - внутри в целом
'...'
, \"
можно использоватькак есть.
powershell.exe -command " \""hi\"" " # OK
powershell.exe -command " \`"hi\`" " # OK
powershell.exe -command ' \"hi\" ' # OK
В качестве альтернативы используйте блок сценариев вместо команды string , которая обходит кавычкиголовные боли:
powershell.exe -command { "hi" } # OK, but only works when calling from PS
Обратите внимание, что техника блока сценариев работает только при вызове из PowerShell , а не из cmd.exe
.
cmd.exe
имеет свои собственные требования цитирования: В частности, cmd.exe
поддерживает только ""
для встраивания двойных кавычек (не также `"
);таким образом, среди приведенных выше решений только
powershell.exe -command " \""hi\"" "
работает из cmd.exe
(пакетный файл) без дополнительного экранирования.
Недостатком \""
, однако, является то, что пробеги внутреннего пробела между \""...\""
сворачиваются в одно пространство каждый.Чтобы избежать этого, используйте \"...\"
, но cmd.exe
затем видит подстроки между экземплярами \"
как без кавычек , что приведет к разрыву команды, если эта подстрока содержит метасимволы, такие как |
или &
;например, powershell.exe -command " \"a|b\" "
;чтобы исправить это, вы должны индивидуально ^
-создать следующие символы: & | < > ^
powershell.exe -command ' "hi" '
аналогично хрупким, поскольку cmd.exe
не распознает '
как разделитель строк, поэтому любые метасимволывнешние вложенные "..."
снова интерпретируются самим cmd.exe
;например, powershell.exe -command ' "hi" | Measure-Object '
Наконец, используя ""
из cmd.exe
для встраивания "
иногда работает, но не надежно ;например, powershell.exe -command " 'Nat ""King"" Cole' "
печатает Nat "King Cole
(закрывающий "
отсутствует).
Кажется, это было исправлено в PowerShell Core .