Поделиться через


about_Parsing

Краткое описание

Описывает, как PowerShell анализирует команды.

Подробное описание

При вводе команды в командной строке PowerShell разбивает текст команды на ряд сегментов, называемых маркерами , а затем определяет, как интерпретировать каждый маркер.

Например, если вы введите следующее:

Write-Host book

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

Примечание.

При анализе входных данных команды 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
  • Строковые литералы символов должны содержаться в кавычках .
  • Числа обрабатываются как числовые значения, а не как ряд символов (если не экранируются).
  • Операторы, включая унарные операторы, такие -gt+ как - и -not двоичные операторы, интерпретируются как операторы и применяют соответствующие операции к их аргументам (операндам).
  • Выражения атрибута и преобразования анализируются как выражения и применяются к подчиненным выражениям. Например: [int] '7'.
  • Ссылки на переменные оцениваются по их значениям, но сплатирование запрещено и вызывает ошибку синтаксического анализа.
  • Все остальное рассматривается как команда для вызова.

Режим аргумента

При синтаксическом анализе PowerShell сначала выполняет интерпретацию входных данных как выражения. Но при обнаружении вызова команды синтаксический анализ продолжается в режиме аргумента. Если у вас есть аргументы, содержащие пробелы, такие как пути, необходимо заключить эти значения аргументов в кавычки.

Режим аргументов предназначен для синтаксического анализа аргументов и параметров для команд в среде оболочки. Все входные данные рассматриваются как расширяемая строка, если она не использует один из следующих синтаксисов:

  • Знак доллара ($) и имя переменной начинает ссылку на переменную, в противном случае она интерпретируется как часть расширяемой строки. Ссылка на переменную может включать доступ к члену или индексирование.

    • Дополнительные символы после простых ссылок на переменные, например $HOME, считаются частью одного и того же аргумента. Заключите имя переменной в фигурные скобки ({}), чтобы отделить ее от последующих символов. Например, ${HOME}.
    • Если ссылка на переменную включает доступ к члену, первый из дополнительных символов считается началом нового аргумента. Например, $HOME.Length-more приводит к двум аргументам: значению и строкового $HOME.Length литерала -more.
  • Кавычки (' и ") begin strings

  • Фигурные скобки ({}) начинают новые блоки скриптов

  • Запятые (,) представляют списки, передаваемые в виде массивов, если вызываемая команда не является собственным приложением, в этом случае они интерпретируются как часть расширяемой строки. Начальные, последовательные или конечные запятые не поддерживаются.

  • Круглые скобки (()) начинают новое выражение

  • Оператор subexpression ($()) начинает внедренное выражение

  • Инициал при знаке (@) начинает синтаксисы выражений, такие как splatting (@args), массивы (@(1,2,3)) и хэш-литералы таблицы (@{a=1;b=2}).

  • (), $()и @() в начале маркера создайте новый контекст синтаксического анализа, который может содержать выражения или вложенные команды.

    • После выполнения дополнительных символов первый дополнительный символ считается началом нового отдельного аргумента.
    • Если перед неквалированный литерал работает как расширяемая строка, () запускает новый аргумент, который является выражением, и @() принимается как литерал $()@ с () запуском нового аргумента, который является выражением.
  • Все остальное рассматривается как расширяемая строка, за исключением метазарядчиков, которые по-прежнему нуждаются в побеге. См. раздел " Обработка специальных символов".

    • Метахарактеры в режиме аргумента (символы с особым синтаксическим значением) : <space> ' " ` , ; ( ) { } | & < > @ # Из них < > @ # только специальные в начале токена.
  • Маркер остановки синтаксического анализа (--%) изменяет интерпретацию всех оставшихся аргументов. Дополнительные сведения см. в разделе токена остановки анализа ниже.

Примеры

В следующей таблице приведены несколько примеров маркеров, обработанных в режиме выражения и режиме аргумента, и оценка этих маркеров. В этих примерах значение переменной $a равно 4.

Пример Режим Результат
2 Expression 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) выражение False (логическое значение)
Write-Output (2) выражение 2 (целое число)
Set-Variable AB A,B аргумент "A", "B" (массив)
CMD /CECHO A,B аргумент "A,B" (строка)
CMD /CECHO $AB выражение "A B" (массив)
CMD /CECHO :$AB аргумент ':A B' (строка)

Обработка специальных символов

Символ backtick (`) можно использовать для экранирования любого специального символа в выражении. Это наиболее полезно для экранирования метачарактеров в режиме аргументов, которые вы хотите использовать в качестве литеральных символов, а не в качестве метачарактера. Например, чтобы использовать знак доллара ($) в качестве литерала в расширяемой строке:

"The value of `$ErrorActionPreference is '$ErrorActionPreference'."
The value of $ErrorActionPreference is 'Continue'.

Продолжение строки

Символ backtick также можно использовать в конце строки, чтобы продолжить входные данные в следующей строке. Это улучшает удобочитаемость команды, которая принимает несколько параметров с длинными именами и значениями аргументов. Например:

New-AzVm `
    -ResourceGroupName "myResourceGroupVM" `
    -Name "myVM" `
    -Location "EastUS" `
    -VirtualNetworkName "myVnet" `
    -SubnetName "mySubnet" `
    -SecurityGroupName "myNetworkSecurityGroup" `
    -PublicIpAddressName "myPublicIpAddress" `
    -Credential $cred

Однако следует избегать использования продолжения строки.

  • Обратные символы могут быть трудно видеть и легко забыть.
  • Дополнительное пространство после заднего фрагмента разрывает продолжение линии. Так как пространство трудно увидеть, что это может быть трудно найти ошибку.

PowerShell предоставляет несколько способов разрыва линий в естественных точках синтаксиса.

  • После символов канала (|)
  • После двоичных операторов (+, -, -eqи т. д.)
  • После запятых (,) в массиве
  • После открытия таких символов, как [, {(

Для большого набора параметров используйте вместо этого splatting. Например:

$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 это и не 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\\""

Примечание.

Символ обратной косой черты\ () не распознается как escape-символ PowerShell. Это 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>

Тильде (~)

Символ тильды (~) имеет особое значение в 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

См. также