about_Parsing
Краткое описание
Описывает, как PowerShell анализирует команды.
Подробное описание
При вводе команды в командной строке PowerShell разбивает текст команды на последовательность сегментов, называемых маркерами , а затем определяет, как интерпретировать каждый маркер.
Например, если ввести:
Write-Host book
PowerShell разбивает команду на два маркера и Write-Host
book
и интерпретирует каждый маркер независимо, используя один из двух основных режимов анализа: режим выражения и режим аргументов.
Примечание
Когда PowerShell анализирует входные данные команды, он пытается разрешить имена команд в командлеты или собственные исполняемые файлы. Если имя команды не имеет точного соответствия, PowerShell добавляет Get-
команду в качестве команды по умолчанию. Например, PowerShell анализирует как Service
Get-Service
. Использовать эту функцию не рекомендуется по следующим причинам:
- Это неэффективно. Это приводит к тому, что PowerShell выполняет поиск несколько раз.
- Внешние программы с тем же именем разрешаются сначала, поэтому вы не можете выполнить нужный командлет.
Get-Help
иGet-Command
не распознают имена без глаголов.- Имя команды может быть зарезервированным словом или ключевым словом языка.
Process
является обоими и не может быть разрешена вGet-Process
.
Режим выражений
Режим выражений предназначен для объединения выражений, необходимых для обработки значений на языке сценариев. Выражения представляют собой представления значений в синтаксисе PowerShell и могут быть простыми или составными, например:
Литеральные выражения являются прямыми представлениями своих значений:
'hello'
32
Выражения переменных содержат значение переменной, на которые они ссылаются:
$x
$script:path
Операторы объединяют другие выражения для оценки:
-12
-not $Quiet
3 + 7
$input.Length -gt 1
- Символьные строковые литералы должны содержаться в кавычках.
- Числа обрабатываются как числовые значения, а не как ряд символов (если они не экранированы).
- Операторы, включая унарные операторы, такие как
-
и и-not
, и двоичные операторы, такие как+
и-gt
, интерпретируются как операторы и применяют соответствующие операции к их аргументам (операндам). - Выражения атрибутов и преобразования анализируются как выражения и применяются к подчиненным выражениям. Например:
[int] '7'
. - Ссылки на переменные вычисляются по их значениям, но сплаттинг запрещен и вызывает ошибку средства синтаксического анализа.
- Все остальное обрабатывается как вызываемая команда.
Режим аргументов
При анализе PowerShell сначала интерпретирует входные данные как выражение. Но при обнаружении вызова команды синтаксический анализ продолжается в режиме аргументов. Если у вас есть аргументы, содержащие пробелы, например пути, эти значения аргументов необходимо заключить в кавычки.
Режим аргументов предназначен для анализа аргументов и параметров для команд в среде оболочки. Все входные данные рассматриваются как расширяемая строка, если в ней не используется один из следующих синтаксисов:
Знак доллара (
$
), за которым следует имя переменной, начинает ссылку на переменную, в противном случае она интерпретируется как часть расширяемой строки. Ссылка на переменную может включать доступ к членам или индексирование.- Дополнительные символы, следующие за простыми ссылками на переменные, например
$HOME
, считаются частью одного и того же аргумента. Заключите имя переменной в фигурные скобки ({}
), чтобы отделить его от последующих символов. Например,${HOME}
. - Если ссылка на переменную включает доступ к члену, первый из дополнительных символов считается началом нового аргумента. Например,
$HOME.Length-more
приводит к двум аргументам: значение и строковый$HOME.Length
литерал-more
.
- Дополнительные символы, следующие за простыми ссылками на переменные, например
Кавычки (
'
и"
) начинают строкиФигурные скобки (
{}
) начинают новые блоки скриптаЗапятые (
,
) представляют списки, передаваемые в виде массивов, если вызываемая команда не является собственным приложением. В этом случае они интерпретируются как часть расширяемой строки. Начальные, последовательные или конечные запятые не поддерживаются.Круглые скобки (
()
) начинают новое выражениеОператор subexpression (
$()
) начинает внедренное выражениеНачальный при знаке (
@
) начинает синтаксис выражений, например splatting (@args
), массивы (@(1,2,3)
) и литералы хэш-таблицы (@{a=1;b=2}
).()
,$()
и@()
в начале маркера создают новый контекст анализа, который может содержать выражения или вложенные команды.- Если за ними следуют дополнительные символы, первый дополнительный символ считается началом нового отдельного аргумента.
- Если перед ним неуправляемый литерал
$()
работает как расширяемая строка,()
начинается новый аргумент, который является выражением, и@()
принимается как литерал@
с()
началом нового аргумента, являющегося выражением.
Все остальное обрабатывается как расширяемая строка, за исключением метасимвы, которые по-прежнему нуждаются в экранировании. См. раздел Обработка специальных символов.
- Метасимвосимы режима аргументов (символы со специальным синтаксическим значением
<space> ' " ` , ; ( ) { } | & < > @ #
): . Из них< > @ #
являются специальными только в начале маркера.
- Метасимвосимы режима аргументов (символы со специальным синтаксическим значением
Маркер остановки анализа (
--%
) изменяет интерпретацию всех оставшихся аргументов. Дополнительные сведения см. в разделе о маркере остановки синтаксического анализа ниже.
Примеры
В следующей таблице приведено несколько примеров маркеров, обработанных в режиме выражения и режиме аргументов, а также приведена оценка этих маркеров. В этих примерах значение переменной $a
равно 4
.
Пример | Режим | Результат |
---|---|---|
2 |
Выражение | 2 (целое число) |
`2 |
Expression | "2" (команда) |
Write-Output 2 |
Expression | 2 (целое число) |
2+2 |
Expression | 4 (целое число) |
Write-Output 2+2 |
Аргумент | "2+2" (строка) |
Write-Output(2+2) |
Expression | 4 (целое число) |
$a |
Expression | 4 (целое число) |
Write-Output $a |
Expression | 4 (целое число) |
$a+2 |
Expression | 6 (целое число) |
Write-Output $a+2 |
Аргумент | "4+2" (строка) |
$- |
Аргумент | "$-" (команда) |
Write-Output $- |
Аргумент | "$-" (строка) |
a$a |
Expression | "a$a" (команда) |
Write-Output a$a |
Аргумент | "a4" (строка) |
a'$a' |
Expression | "a$a" (команда) |
Write-Output a'$a' |
Аргумент | "a$a" (строка) |
a"$a" |
Expression | "a$a" (команда) |
Write-Output a"$a" |
Аргумент | "a4" (строка) |
a$(2) |
Expression | "a$(2)" (команда) |
Write-Output a$(2) |
Аргумент | "a2" (строка) |
Каждый токен можно интерпретировать как тип объекта, например Boolean или String. PowerShell пытается определить тип объекта из выражения . Тип объекта зависит от типа параметра, ожидаемого командой, и от того, знает ли PowerShell, как преобразовать аргумент в правильный тип. В следующей таблице приведено несколько примеров типов, назначенных значениям, возвращаемым выражениями.
Пример | Режим | Результат |
---|---|---|
Write-Output !1 |
— аргумент | "!1" (строка) |
Write-Output (!1) |
expression | False (логическое значение) |
Write-Output (2) |
expression | 2 (целое число) |
Set-Variable AB A,B |
— аргумент | "A", "B" (массив) |
CMD /CECHO A,B |
— аргумент | "A,B" (строка) |
CMD /CECHO $AB |
expression | A B (массив) |
CMD /CECHO :$AB |
— аргумент | ":A B" (строка) |
Обработка специальных символов
Символ обратного выражения (`
) можно использовать для экранирования любого специального символа в выражении. Это наиболее полезно для экранирования метасимвы режима аргументов, которые вы хотите использовать в качестве литеральных символов, а не как метасимвы. Например, чтобы использовать знак доллара ($
) в качестве литерала в расширяемой строке:
"The value of `$ErrorActionPreference is '$ErrorActionPreference'."
The value of $ErrorActionPreference is 'Continue'.
Продолжение строки
Символ обратного ввода также можно использовать в конце строки, чтобы продолжить ввод в следующей строке. Это повышает удобочитаемость команды, которая принимает несколько параметров с длинными именами и значениями аргументов. Пример:
New-AzVm `
-ResourceGroupName "myResourceGroupVM" `
-Name "myVM" `
-Location "EastUS" `
-VirtualNetworkName "myVnet" `
-SubnetName "mySubnet" `
-SecurityGroupName "myNetworkSecurityGroup" `
-PublicIpAddressName "myPublicIpAddress" `
-Credential $cred
Однако следует избегать использования продолжения строки.
- Символы обратной черты могут быть трудно видеть и легко забыть.
- Дополнительное пространство после обратного тикала разрывает продолжение строки. Так как пространство трудно увидеть, может быть трудно найти ошибку.
PowerShell предоставляет несколько способов разбиения линий в естественных точках синтаксиса.
- После символов канала (
|
) - После бинарных операторов (
+
,-
,-eq
и т. д.) - После запятых (
,
) в массиве - После открытия символов, таких как
[
,{
,(
Для большого набора параметров используйте вместо него сплаттинг. Пример:
$parameters = @{
ResourceGroupName = "myResourceGroupVM"
Name = "myVM"
Location = "EastUS"
VirtualNetworkName = "myVnet"
SubnetName = "mySubnet"
SecurityGroupName = "myNetworkSecurityGroup"
PublicIpAddressName = "myPublicIpAddress"
Credential = $cred
}
New-AzVm @parameters
Передача аргументов в собственные команды
При выполнении собственных команд из PowerShell аргументы сначала анализируются с помощью PowerShell. Проанализированные аргументы затем объединяются в одну строку, каждый параметр отделяется пробелом.
Например, следующая команда вызывает icacls.exe
программу.
icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F
Чтобы выполнить эту команду в PowerShell 2.0, необходимо использовать escape-символы, чтобы предотвратить неправильное интерпретацию круглых скобок в PowerShell.
icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F
Маркер остановки синтаксического анализа
Начиная с PowerShell 3.0, вы можете использовать маркер остановки синтаксического анализа (--%
), чтобы остановить интерпретацию входных данных PowerShell как команд или выражений PowerShell.
Примечание
Маркер остановки анализа предназначен только для использования на платформах Windows.
При вызове собственной команды поместите маркер остановки синтаксического анализа перед аргументами программы. Этот метод гораздо проще, чем использование escape-символов для предотвращения неправильной интерпретации.
При обнаружении маркера остановки анализа PowerShell обрабатывает оставшиеся символы в строке как литерал. Единственная интерпретация, которую он выполняет, заключается в замене значений переменных среды, использующих стандартную нотацию Windows, например %USERPROFILE%
.
icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F
PowerShell отправляет в программу следующую командную icacls.exe
строку:
X:\VMS /grant Dom\HVAdmin:(CI)(OI)F
Маркер остановки синтаксического анализа действует только до следующей новой строки или символа конвейера. Вы не можете использовать символ продолжения строки (`
) для расширения эффекта или использовать разделитель команд (;
) для завершения действия.
Кроме %variable%
ссылок на переменные среды, вы не можете внедрить в команду другие динамические элементы. Экранирование символа %
как %%
, как это можно сделать в пакетных файлах, не поддерживается. %<name>%
маркеры постоянно расширяются. Если <name>
не ссылается на определенную переменную среды, маркер передается как есть.
Вы не можете использовать перенаправление потоков (например >file.txt
, ), так как они передаются в качестве аргументов в целевую команду.
В следующем примере первый шаг выполняет команду без использования маркера остановки синтаксического анализа. PowerShell вычисляет строку в кавычках и передает значение (без кавычек) в , что приводит к cmd.exe
ошибке.
PS> cmd /c echo "a|b"
'b' is not recognized as an internal or external command,
operable program or batch file.
PS> cmd /c --% echo "a|b"
"a|b"
Примечание
Некоторые команды в системах Windows реализуются в виде пакетного файла Windows. Например, эта az
команда для Azure CLI является пакетным файлом Windows.
Передача аргументов, содержащих символы кавычек
Некоторые собственные команды ожидают аргументы, содержащие символы кавычек. PowerShell 7.3 изменил способ анализа командной строки для собственных команд.
Внимание!
Новое поведение является критическим изменением , чем поведение Windows PowerShell 5.1. Оно может нарушить выполнение скриптов и задач автоматизации, которые устраняют различные проблемы, возникающие при вызове собственных приложений. Используйте маркер остановки анализа (--%
) или командлет , Start-Process
чтобы избежать передачи собственного аргумента при необходимости.
Новая $PSNativeCommandArgumentPassing
переменная предпочтения управляет этим поведением. Эта переменная позволяет выбрать поведение во время выполнения. Возможные значения: Legacy
, Standard
и Windows
. Поведение по умолчанию зависит от платформы. На платформах Windows по умолчанию используется Windows
параметр , а не платформы Windows — .Standard
Legacy
является историческим поведением. Поведение Windows
режима и Standard
одинаково, за исключением того, что в Windows
режиме вызовы следующих файлов автоматически используют передачу аргумента Legacy
стиля.
cmd.exe
cscript.exe
wscript.exe
- заканчивается на
.bat
- заканчивается на
.cmd
- заканчивается на
.js
- заканчивается на
.vbs
- заканчивается на
.wsf
$PSNativeCommandArgumentPassing
Если задано значение Legacy
или Standard
, средство синтаксического анализа не проверяет наличие этих файлов.
Примечание
В следующих примерах используется TestExe.exe
средство . Вы можете выполнить сборку TestExe
из исходного кода. См . раздел TestExe в исходном репозитории PowerShell.
Это изменение привело к появлению следующих новых поведений:
сохраняются литеральные или расширяемые строки со встроенными кавычками:
PS> $a = 'a" "b' PS> TestExe -echoargs $a 'c" "d' e" "f Arg 0 is <a" "b> Arg 1 is <c" "d> Arg 2 is <e f>
сохраняются пустые строки в качестве аргументов:
PS> TestExe -echoargs '' a b '' Arg 0 is <> Arg 1 is <a> Arg 2 is <b> Arg 3 is <>
Цель этих примеров — передать путь к каталогу (с пробелами и кавычками) "C:\Program Files (x86)\Microsoft\"
в собственную команду, чтобы она получила путь в виде строки в кавычках.
В Windows
режиме или Standard
следующие примеры дают ожидаемые результаты:
TestExe -echoargs """${env:ProgramFiles(x86)}\Microsoft\"""
TestExe -echoargs '"C:\Program Files (x86)\Microsoft\"'
Чтобы получить те же результаты в Legacy
режиме, необходимо экранировать кавычки или использовать маркер остановки синтаксического анализа (--%
):
TestExe -echoargs """""${env:ProgramFiles(x86)}\Microsoft\\"""""
TestExe -echoargs "\""C:\Program Files (x86)\Microsoft\\"""
TestExe -echoargs --% ""\""C:\Program Files (x86)\Microsoft\\"\"""
TestExe -echoargs --% """C:\Program Files (x86)\Microsoft\\""
TestExe -echoargs --% """%ProgramFiles(x86)%\Microsoft\\""
Примечание
Символ обратной косой черты (\
) не распознается PowerShell как escape-символ. Это escape-символ, используемый базовым API для ProcessStartInfo.ArgumentList.
В PowerShell 7.3 также добавлена возможность трассировки привязки параметров для собственных команд. Дополнительные сведения см. в разделе Trace-Command.
Передача аргументов в команды PowerShell
Начиная с PowerShell 3.0, вы можете использовать маркер конца параметров (--
), чтобы запретить PowerShell интерпретировать входные данные как параметры PowerShell. Это соглашение, указанное в спецификации оболочки и служебных программ POSIX.
Маркер конца параметров
Маркер конца параметров (--
) указывает, что все следующие за ним аргументы должны передаваться в их фактической форме, как если бы вокруг них были размещены двойные кавычки. Например, с помощью --
можно вывести строку -InputObject
без кавычек или интерпретации как параметра:
Write-Output -- -InputObject
-InputObject
В отличие от маркера остановки синтаксического анализа (--%
), любые значения, следующие за --
маркером, могут быть интерпретированы PowerShell как выражения.
Write-Output -- -InputObject $env:PROCESSOR_ARCHITECTURE
-InputObject
AMD64
Это поведение применяется только к командам PowerShell. При использовании маркера при вызове --
внешней команды --
строка передается в качестве аргумента этой команде.
TestExe -echoargs -a -b -- -c
В выходных данных показано, что --
передается в качестве аргумента в TestExe
.
Arg 0 is <-a>
Arg 1 is <-b>
Arg 2 is <-->
Arg 3 is <-c>