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 (
$()
) начинает внедренное выражениеИнициал при знаке (
@
) начинает синтаксис выражений, например сплаттинг (@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"
Примечание
Маркер остановки анализа не требуется при использовании командлетов PowerShell. Однако может быть полезно передать аргументы в функцию PowerShell, предназначенную для вызова собственной команды с этими аргументами.
Передача аргументов, содержащих символы кавычек
Некоторые собственные команды ожидают аргументы, содержащие символы кавычек. PowerShell 7.3 изменил способ анализа командной строки для собственных команд.
Внимание!
Новое поведение является критическим изменением поведения Windows PowerShell 5.1. Оно может нарушить выполнение скриптов и задач автоматизации, которые устраняют различные проблемы, возникающие при вызове собственных приложений. Используйте маркер остановки синтаксического анализа (--%
) или командлет , Start-Process
чтобы при необходимости избежать передачи собственного аргумента.
Новая $PSNativeCommandArgumentPassing
переменная предпочтения управляет этим поведением. Эта переменная позволяет выбрать поведение во время выполнения. Возможные значения: Legacy
, Standard
и Windows
. Поведение по умолчанию зависит от платформы. На платформах Windows по умолчанию используется Windows
параметр , а на платформах, отличных от Standard
Windows, — .
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
В отличие от маркера stop-parsing (--%
), все значения, следующие за --
маркером, могут интерпретироваться 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>
Тильда (~)
Символ тильды (~
) имеет особое значение в PowerShell. При использовании с командами PowerShell в начале пути символ тильды разворачивается в домашнем каталоге пользователя. Если символ тильды используется в любом другом месте пути, он рассматривается как литеральный символ.
PS D:\temp> $PWD
Path
----
D:\temp
PS D:\temp> Set-Location ~
PS C:\Users\user2> $PWD
Path
----
C:\Users\user2
В этом примере параметр New-Item
Name объекта ожидает строку. Символ тильды рассматривается как литеральный символ. Чтобы изменить созданный каталог, необходимо указать путь символом тильды.
PS D:\temp> Set-Location ~
PS C:\Users\user2> New-Item -Type Directory -Name ~
Directory: C:\Users\user2
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 5/6/2024 2:08 PM ~
PS C:\Users\user2> Set-Location ~
PS C:\Users\user2> Set-Location .\~
PS C:\Users\user2\~> $PWD
Path
----
C:\Users\user2\~
При использовании символа тильды с собственными командами PowerShell передает тильду как литеральный символ. Использование тильды в пути приводит к ошибкам для собственных команд в Windows, которые не поддерживают символ тильды.
PS D:\temp> $PWD
Path
----
D:\temp
PS D:\temp> Get-Item ~\repocache.clixml
Directory: C:\Users\user2
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 4/29/2024 3:42 PM 88177 repocache.clixml
PS D:\temp> more.com ~\repocache.clixml
Cannot access file D:\temp\~\repocache.clixml