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


about_Parsing

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

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

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

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

Например, если ввести:

Write-Host book

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

Примечание

При анализе входных данных команды PowerShell пытается разрешить имена команд в командлеты или собственные исполняемые файлы. Если имя команды не имеет точного совпадения, PowerShell добавляет Get- команду в качестве команды по умолчанию. Например, PowerShell анализирует как ServiceGet-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 параметр , а на платформах, отличных от StandardWindows, — .

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-ItemName объекта ожидает строку. Символ тильды рассматривается как литеральный символ. Чтобы изменить созданный каталог, необходимо указать путь символом тильды.

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

См. также раздел