Start-Process с PowerShell.exe демонстрирует различное поведение со встроенными одинарными и двойными кавычками - PullRequest
1 голос
/ 08 апреля 2020

Во-первых, если кому-то интересно, почему мы так запускаем PowerShell, я столкнулся с таким поведением с помощью более сложной команды, которую мы строили, но поведение можно продемонстрировать, используя более простой пример, как показано ниже. , На практике мы запускаем команду под 32-битной PowerShell от имени администратора с дополнительными переменными, отображаемыми в строке (поэтому я просто не использую одинарные кавычки для внешней части), но это, похоже, не учитывает поведение ниже.


Когда я вызываю PowerShell через Start-Process, я получаю некоторые странные поведения, если использую одинарные кавычки, окружающие параметр -Command, для исполняемого файла PowerShell. Например:

Start-Process -FilePath Powershell.exe -ArgumentList "-Command 'ping google.com'"

просто выводит ping google.com в качестве выхода и выхода. Однако, если я использую вложенные двойные кавычки вместо одинарных кавычек, как показано ниже:

Start-Process -FilePath Powershell.exe -ArgumentList "-Command `"ping google.com`""

ping запускается и выдает ожидаемый результат:

Pinging google.com [173.194.78.113] с 32 байтами данных:

Ответ от 173.194.78.113: байт = 32 время = 34 мс TTL = 45

Ответ от 173.194.78.113: байт = 32 время = 33 мс TTL = 45

Ответ от 173.194.78.113: байты = 32 времени = 35 мс TTL = 45

Ответ от 173.194.78.113: байты = 32 времени = 32 мс TTL = 45

Статистика пинга для 173.194.78.113:

Пакетов: Отправлено = 4, Получено = 4, Потерян = = 0 (потеря 0%),

Приблизительное время прохождения сигнала в миллисекундах:

Минимум = 32мс, Максимум = 35мс, Среднее = 33мс

Почему командная строка просто отображается как есть, а не выполняется, если я использую одинарные кавычки для параметра -Command вместо двойных кавычек?

Ответы [ 3 ]

1 голос
/ 09 апреля 2020

Полезный ответ js2010 является верным в том смысле, что использование Start-Process является случайным для вашего вопроса и что поведение задает c для CLI * 1007 PowerShell * (powershell.exe для Windows PowerShell и pwsh для PowerShell [Core] 6 + ):

Вкл. Windows [1] , есть два уровня оценки для рассмотрения:

  • (a) Первоначальный синтаксический анализ командной строки в аргументах.

  • (b) Оценка (с пробелами) результирующие аргументы в качестве кода PowerShell , из-за использования параметра CLI -Command (-c).

Re (a) :

Как и большинство консольных программ на Windows, PowerShell распознает только " символов. (двойные кавычки) - также не ' (одиночные кавычки) - как имеющие функцию syntacti c. [2]

  • То есть, если только " символов. экранированы , они строковые разделители , которые сами удалены во время синтаксического анализа.

  • Как подразумевается выше, ' символов не удалены.

Независимо от того, какие аргументы являются результатом - массив из " -записанных токенов - объединены с один пробел между ними, который становится входом для (b).


Чтобы объяснить это в контексте вашего примера, с Start-Process вычеркнуто из рисунка:

Примечание : следующее применяется к вызовам из cmd.exe или любого контекста, в котором no shell участвует (включая Start-Process и Windows Запустить ( WinKey-R ) диалоговое окно). В отличие от этого, PowerShell повторно цитирует командную строку за кулисами, чтобы всегда использовать ", если необходимо.
Другими словами: следующее относится к командным строкам как видно из PowerShell .

Одиночная -цитированная команда:

# Note: This *would* work for calling ping if run from 
#       (a) PowerShell itself or (b) from a POSIX-like shell such as Bash.
#       However, via cmd.exe or any context where *no* shell is involved,
#       notably Start-Process and the Windows Run dialog, it does not.
powershell -Command 'ping google.com'
  • (a ) приводит к тому, что PowerShell находит следующие два дословных аргумента: 'ping и google.com'

  • (b) объединяет эти дословные аргументы в форму 'ping google.com' [2] и выполняет это как код PowerShell , поэтому выводит содержимое этого строкового литерала , ping google.com

Двойная команда в кавычках:

powershell -Command "ping google.com"
  • (a) приводит к тому, что PowerShell удаляет символы syntacti c ", находя следующий единый дословный аргумент: ping google.com

  • (b) затем приводит к тому, что этот дословный аргумент - ping google.com - выполняется как код PowerShell, который В результате вызывается команда , а именно исполняемый файл ping с аргументом google.com.


[1] Вкл Unix Подобно платформам, первый уровень неприменим, потому что вызываемые программы видят только массив из дословно аргументов, а не командную строку, которую они сами должны анализировать в аргументах. Не то чтобы при вызове PowerShell CLI из POSIX-подобной оболочки, такой как bash на Unix -подобных платформах, именно эта оболочка распознает одинарные кавычки как разделители строк и удаляет их до PowerShell их видит.

[2] Удивительно, но Windows в конечном итоге до каждой отдельной программы может интерпретировать командную строку и некоторые do решили также распознавать ' как разделители строк (например, Ruby). Однако многие программы на Windows, включая сам PowerShell, основаны на среде выполнения C, которая распознает только ".

[3]. это означает, что нормализация пробелов происходит: то есть
powershell -Command 'ping google.com' в равной степени приведет к 'ping google.com'.

0 голосов
/ 09 апреля 2020

Мы можем отбросить старт-процесс из этого. Кажется верным, что встроенные двойные и одинарные кавычки по-разному обрабатываются исполняемым файлом powershell Старт-процесс не имеет отношения к этому поведению. Так ведет себя PowerShell в командной строке. Я не вижу способа изменить это. Вы также можете выполнить команду «start-job -runas32», но она не будет повышена. Другой вариант - опция -file в powershell вместо -command. Эти примеры выполняются из ядра оболочки оболочки Osx (unix):

pwsh -c "'ping -c 1 google.com'"

ping -c 1 google.com


pwsh -c "`"ping -c 1 google.com`""

PING google.com (172.217.10.110): 56 data bytes
64 bytes from 172.217.10.110: icmp_seq=0 ttl=52 time=20.020 ms

--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 20.020/20.020/20.020/0.000 ms


pwsh -c '"ping -c 1 google.com"'        
PING google.com (172.217.6.206): 56 data bytes
64 bytes from 172.217.6.206: icmp_seq=0 ttl=52 time=22.786 ms

--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 22.786/22.786/22.786/0.000 ms
0 голосов
/ 08 апреля 2020

В справке для powershell.exe ничего не говорится о поддержке одинарных кавычек ... зачем вам их использовать?

-Command
    Executes the specified commands (and any parameters) as though they were
    typed at the Windows PowerShell command prompt, and then exits, unless
    NoExit is specified. The value of Command can be "-", a string. or a
    script block.

    If the value of Command is "-", the command text is read from standard
    input.

    If the value of Command is a script block, the script block must be enclosed
    in braces ({}). You can specify a script block only when running PowerShell.exe
    in Windows PowerShell. The results of the script block are returned to the
    parent shell as deserialized XML objects, not live objects.

    If the value of Command is a string, Command must be the last parameter
    in the command , because any characters typed after the command are
    interpreted as the command arguments.

    To write a string that runs a Windows PowerShell command, use the format:
        "& {<command>}"
    where the quotation marks indicate a string and the invoke operator (&)
    causes the command to be executed.
...