次の方法で共有


about_Parsing

簡単な説明

PowerShell でコマンドを解析する方法について説明します。

長い説明

コマンド プロンプトでコマンドを入力すると、PowerShell はコマンド テキストを トークン と呼ばれる一連のセグメントに分割し、各トークンの解釈方法を決定します。

たとえば、次のように入力します。

Write-Host book

PowerShell は、コマンドを 2 つのトークン と bookに分割し、Write-Host式モードと引数モードの 2 つの主要な解析モードのいずれかを使用して、各トークンを個別に解釈します。

注意

PowerShell はコマンド入力を解析するときに、コマンド名をコマンドレットまたはネイティブ実行可能ファイルに解決しようとします。 コマンド名が完全に一致しない場合、PowerShell はコマンドの Get- 先頭に既定の動詞として付加します。 たとえば、PowerShell では としてGet-Service解析されますService。 次の理由から、この機能を使用することはお勧めしません。

  • 非効率的です。 これにより、PowerShell が複数回検索されます。
  • 同じ名前の外部プログラムが最初に解決されるため、目的のコマンドレットを実行することはできません。
  • Get-HelpGet-Command は、動詞のない名前を認識しません。
  • コマンド名には、予約語または言語キーワード (keyword)を指定できます。 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 と文字列リテラル の 2 つの引数が返されます -more
  • 引用符 (' および ") の開始文字列

  • 中かっこ ({}) が新しいスクリプト ブロックを開始する

  • コンマ (,) は、呼び出されるコマンドがネイティブ アプリケーションでない限り、配列として渡されるリストを導入します。その場合、それらは展開可能な文字列の一部として解釈されます。 最初、連続、または末尾のコンマはサポートされていません。

  • かっこ (()) で新しい式を開始する

  • Subexpression 演算子 ($()) が埋め込み式を開始する

  • 最初のアット マーク (@) は、スプラッティング ()、配列 (@args)、ハッシュ テーブル リテラル (@(1,2,3)@{a=1;b=2}) などの式構文を開始します。

  • ()$()、および @() トークンの開始時に、式または入れ子になったコマンドを含めることができる新しい解析コンテキストが作成されます。

    • その後に追加の文字が続くと、最初の追加文字は、新しい個別の引数の先頭と見なされます。
    • 引用符で囲まれていないリテラル$()が前にある場合は、展開可能な文字列のように動作し、()式である新しい引数を開始し@()、式である新しい引数を開始してリテラル@()として受け取ります。
  • それ以外はすべて、エスケープが必要なメタ文字を除き、展開可能な文字列として扱われます。 特殊文字の処理に関するページを参照してください。

    • 引数モードメタ文字 (特別な構文の意味を持つ文字) は、 です <space> ' " ` , ; ( ) { } | & < > @ #。 そのうち、 < > @ # はトークンの開始時にのみ特別です。
  • 停止解析トークン (--%) は、残りのすべての引数の解釈を変更します。 詳細については、以下の 「stop-parsing token 」セクションを参照してください。

次の表に、式モードと引数モードで処理されるトークンの例と、それらのトークンの評価を示します。 これらの例では、変数 $a の値は です 4

モード 結果
2 2 (整数)
`2 Expression "2" (コマンド)
Write-Output 2 Expression 2 (整数)
2+2 Expression 4 (整数)
Write-Output 2+2 引数 "2+2" (string)
Write-Output(2+2) Expression 4 (整数)
$a Expression 4 (整数)
Write-Output $a Expression 4 (整数)
$a+2 Expression 6 (整数)
Write-Output $a+2 引数 "4+2" (string)
$- 引数 "$-" (コマンド)
Write-Output $- 引数 "$-" (string)
a$a Expression "a$a" (コマンド)
Write-Output a$a 引数 "a4" (string)
a'$a' Expression "a$a" (コマンド)
Write-Output a'$a' 引数 "a$a" (string)
a"$a" Expression "a$a" (コマンド)
Write-Output a"$a" 引数 "a4" (string)
a$(2) Expression "a$(2)" (コマンド)
Write-Output a$(2) 引数 "a2" (string)

すべてのトークンは、 ブール 型や 文字列型など、何らかの種類のオブジェクト型として解釈できます。 PowerShell は、 式からオブジェクトの種類を決定しようとします。 オブジェクトの種類は、コマンドで想定されるパラメーターの型と、引数を正しい型に変換する方法を PowerShell が認識しているかどうかによって異なります。 次の表は、式によって返される値に割り当てられた型のいくつかの例を示しています。

モード 結果
Write-Output !1 引数 "!1" (string)
Write-Output (!1) expression False (ブール値)
Write-Output (2) expression 2 (整数)
Set-Variable AB A,B 引数 'A','B' (配列)
CMD /CECHO A,B 引数 'A,B' (string)
CMD /CECHO $AB expression 'A B' (配列)
CMD /CECHO :$AB 引数 ':A B' (string)

特殊文字の処理

バックティック文字 (`) を使用して、式内の任意の特殊文字をエスケープできます。 これは、メタ文字ではなくリテラル文字として使用する引数モードメタ文字をエスケープする場合に最も便利です。 たとえば、ドル記号 ($) を展開可能な文字列のリテラルとして使用するには、次のようにします。

"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 によって解析されます。 解析された引数は 1 つの文字列に結合され、各パラメーターはスペースで区切られます。

たとえば、次のコマンドはプログラムを icacls.exe 呼び出します。

icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

PowerShell 2.0 でこのコマンドを実行するには、PowerShell がかっこを誤って解釈しないようにエスケープ文字を使用する必要があります。

icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F

停止解析トークン

PowerShell 3.0 以降では、 停止解析 (--%) トークンを使用して、PowerShell が入力を PowerShell コマンドまたは式として解釈するのを停止できます。

注意

停止解析トークンは、Windows プラットフォームでのネイティブ コマンドの使用のみを目的としています。

ネイティブ コマンドを呼び出すときは、プログラム引数の前に停止解析トークンを配置します。 この手法は、誤った解釈を防ぐためにエスケープ文字を使用するよりもはるかに簡単です。

停止解析トークンが検出されると、PowerShell は行の残りの文字をリテラルとして扱います。 実行する唯一の解釈は、 などの %USERPROFILE%標準の Windows 表記を使用する環境変数の値を置き換える方法です。

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 では、ネイティブ コマンドのコマンド ラインの解析方法が変更されました。

注意事項

新しい動作は、Window PowerShell 5.1 の動作からの 破壊的変更 です。 これにより、ネイティブ アプリケーションを呼び出す際のさまざまな問題に対処するスクリプトと自動化が中断される場合があります。 必要に応じネイティブ引数が渡されないようにするには、停止解析トークン (--%) または Start-Process コマンドレットを使用します。

この動作は、新しい $PSNativeCommandArgumentPassing ユーザー設定変数によって制御されます。 この変数により、ランタイム時の動作を選択することができます。 有効な値は、LegacyStandardWindows です。 既定の動作は、プラットフォームに固有です。 Windows プラットフォームの場合、既定の設定は Windows で、Windows 以外のプラットフォームでは既定で Standard です。

Legacy は過去の動作です。 Windows および Standard モードの動作は同じですが、Windows モードでは、次のファイルの呼び出しで Legacy スタイル引数の受け渡しが自動的に使用されます。

  • cmd.exe
  • cscript.exe
  • wscript.exe
  • .bat で終わる
  • .cmd で終わる
  • .js で終わる
  • .vbs で終わる
  • .wsf で終わる

$PSNativeCommandArgumentPassingLegacy または Standard のいずれかに設定されている場合、パーサーはこれらのファイルのチェックは行いません。

注意

次の例では、TestExe.exe ツールを使用します。 ソース コードから TestExe をビルドすることができます。 PowerShell ソース リポジトリの TestExe に関するページを参照してください。

この変更によって利用可能になった新しい動作は次のとおりです。

  • リテラルまたは展開可能な文字列に引用符が埋め込まれ、その引用符が保持されるようになりました。

    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\" をネイティブ コマンドに渡すことです。

または Standard モードではWindows、次の例では期待される結果が生成されます。

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 ではエスケープ文字として認識されません。 これは、 ProcessStartInfo.ArgumentList の基になる API によって使用されるエスケープ文字です。

PowerShell 7.3 では、ネイティブ コマンドのパラメーター バインドをトレースする機能も追加されました。 詳しくは、「トレース-コマンド」をご覧ください。

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

この例では、 の Name パラメーターに New-Item 文字列が必要です。 チルダ文字はリテラル文字として扱われます。 新しく作成されたディレクトリに変更するには、チルダ文字でパスを修飾する必要があります。

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

関連項目