Почему PowerShell не распознает указанные параметры? - PullRequest
2 голосов
/ 17 марта 2019

Почему PowerShell обрабатывает указанные параметры по-разному, когда вы вызываете скрипт напрямую (в консоли PowerShell или ISE) или когда вы вызываете его через другой экземпляр PowerShell?

Вот скрипт (TestQuotes.ps1):

param
(
    [string]
    $Config = $null
)

"Config = $Config"

Вот результаты:

PS D:\Scripts> .\TestQuotes.ps1 -Config "A B C"
Config = A B C
PS D:\Scripts> PowerShell .\TestQuotes.ps1 -Config "A B C"
Config = A
PS D:\Scripts> .\TestQuotes.ps1 -Config 'A B C'
Config = A B C
PS D:\Scripts> PowerShell .\TestQuotes.ps1 -Config 'A B C'
Config = A

Есть идеи?

Ответы [ 2 ]

6 голосов
/ 17 марта 2019

Согласно справке командной строки PowerShell.exe , первый аргумент для исполняемого файла powershell - -Command:

PowerShell[.exe]
       [-Command { - | <script-block> [-args <arg-array>]
                     | <string> [<CommandParameters>] } ]
       [-EncodedCommand <Base64EncodedCommand>]
       [-ExecutionPolicy <ExecutionPolicy>]
       [-File <FilePath> [<Args>]]
       [-InputFormat {Text | XML}]
       [-Mta]
       [-NoExit]
       [-NoLogo]
       [-NonInteractive]
       [-NoProfile]
       [-OutputFormat {Text | XML}]
       [-PSConsoleFile <FilePath> | -Version <PowerShell version>]
       [-Sta]
       [-WindowStyle <style>]

PowerShell[.exe] -Help | -? | /?

Любой текст после -Command отправляется в PowerShell в виде одной командной строки.

...

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

Что на самом деле получает дочерний экземпляр PowerShell, легко проверить с помощью echoargs :

PS > echoargs .\TestQuotes.ps1 -Config "A B C"
Arg 0 is <.\TestQuotes.ps1>
Arg 1 is <-Config>
Arg 2 is <A B C>

Что далее анализируется дочерним экземпляром:

'.\TestQuotes.ps1' '-Config' 'A' 'B' 'C'

И вот где вы получаете «неправильный» результат: Config = A

Если вы укажете -File аргумент, вы получите желаемый результат:

PS >  PowerShell -File .\TestQuotes.ps1 -Config 'A B C'
Config = A B C

PS >  PowerShell -Command .\TestQuotes.ps1 -Config 'A B C'
Config = A
4 голосов
/ 17 марта 2019

tl; dr

Если вы вызываете другой экземпляр PowerShell из PowerShell , используйте блок сценариев ({ ... }) для получения предсказуемого поведения:

Windows PowerShell:

powershell.exe { .\TestQuotes.ps1 -Config "A B C" }

PowerShell Core :

pwsh { .\TestQuotes.ps1 -Config "A B C" }

This заставит кавычки аргументов работать как положено - и даже возвратит объектов с точностью, близкой к типу, из вызова, потому что используется сериализация, аналогичная используемой для удаленного взаимодействия PowerShell.

Обратите внимание, однако, что это , а не опция при вызове из вне PowerShell , например, из cmd.exe или bash.

Ознакомьтесь с объяснением поведения, которое вы видели при отсутствии блока сценария.


PowerShell CLI (вызов powershell.exe (Windows PowerShell) / pwsh.exe (PowerShell Core ) поддерживает только один параметр, который принимает положениеional аргумент (т. е. значение, которому не предшествует имя параметра , например -Command).

  • In Windows PowerShell, этот (подразумеваемый) параметр равен -Command.

  • In PowerShell Core , это-File.

    • Значение по умолчанию пришлось изменить для поддержки использования интерфейса командной строки в Unix shebang lines .

Любые аргументы после Первый позиционный аргумент, если таковой имеется, считается:

  • в Windows PowerShell: часть фрагментаисходного кода PowerShell , переданного (подразумеваемому) параметру
    -Command.

  • в PowerShell Core : отдельные аргументы в передать как литералы в файл сценария , указанный в первом позиционном аргументе (подразумеваемый аргумент -File).


Аргументы переданы -Command -неявно или явно - пройти два раунда синтаксического анализа с помощью PowerShell, что может быть сложно:

  • В первом раунде,"..." (двойные кавычки), заключающие отдельные аргументы: раздет .

    • Если вы звоните из PowerShell , это относится даже к аргументам, которые были первоначально '...' - заключено (в одинарных кавычках), потому что за кулисами PowerShell повторно цитирует такие аргументы, чтобы использовать "..." при вызове внешних программ (включая сам CLI PowerShell).
  • В втором раунде извлеченные аргументы объединяются с пробелами для формирования одиночная строка , то есть , затем интерпретируется как Исходный код PowerShell .


Применяется к вашему вызову,это означает, что и PowerShell .\TestQuotes.ps1 -Config "A B C" и PowerShell .\TestQuotes.ps1 -Config 'A B C' привели к тому, что PowerShell в конечном итоге проанализировал и выполнил следующуюкод понижения:

.\TestQuotes.ps1 -Config A B C

То есть из-за 2 раундов синтаксического анализа исходное цитирование было потерян , в результате чего три различных аргументов были полученыпередан , который объясняет ваш симптом.


Если вам пришлось заставить вашу команду работать без блока сценария , у вас есть две опции:

  • Использование -File, которое применяется только один цикл анализа :

    powershell.exe -File .\TestQuotes.ps1 -Config "A B C"
    
    • То есть , кроме удаления "...", результирующие аргументы обрабатываются как литералы - что, однако, равно обычно , что выхочу.
  • С (подразумевается) -Command, применить дополнительный слой цитирования :

    powershell.exe -Command .\TestQuotes.ps1 -Config '\"A B C\"'
    

Обратите внимание, что PowerShell требует " символов. быть экранированным как \" в аргументах, передаваемых его CLI , тогда как внутри PowerShell , `" (или "") должны использоваться.

...