about_Parsing

簡単な説明

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

長い説明

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

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

Write-Host book

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

注

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

  • 非効率的です。 これにより、PowerShell が複数回検索されます。
  • 同じ名前の外部プログラムが最初に解決されるため、意図したコマンドレットを実行できません。
  • Get-Help と Get-Command は動詞のない名前を認識しません。

表現モード

式モードは、スクリプト言語での値操作に必要な式を組み合わせることを目的としています。 式は 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という 2 つの引数になります。
  • 引用符 (' および ") が文字列を開始する

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

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

  • 括弧 (()) は新しい式を開始するために使われる

  • 部分式演算子 ($()) は、埋め込み式を開始する

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

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

    • 後に追加の文字が続くと、最初の追加文字は新しい個別の引数の先頭と見なされます。
    • 引用符で囲まれていないリテラルが前に付くと、$() は展開可能な文字列のように機能し、() は式である新しい引数を開始し、@() は式である新しい引数を開始する()リテラル@と見なされます。
  • それ以外はすべて、エスケープが必要なメタ文字を除き、展開可能な文字列として扱われます。

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

例示

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

例 モード 結果
2 表現 2 (整数)
`2 表現 "2" (コマンド)
Write-Output 2 表現 2 (整数)
2+2 表現 4 (整数)
Write-Output 2+2 引数 "2+2" (文字列)
Write-Output(2+2) 表現 4 (整数)
$a 表現 4 (整数)
Write-Output $a 表現 4 (整数)
$a+2 表現 6 (整数)
Write-Output $a+2 引数 "4+2" (文字列)
$- 引数 "$-" (コマンド)
Write-Output $- 引数 "$-" (文字列)
a$a 表現 "a$a" (コマンド)
Write-Output a$a 引数 "a4" (文字列)
a'$a' 表現 "a$a" (コマンド)
Write-Output a'$a' 引数 "a$a" (文字列)
a"$a" 表現 "a$a" (コマンド)
Write-Output a"$a" 引数 "a4" (文字列)
a$(2) 表現 "a$(2)" (コマンド)
Write-Output a$(2) 引数 "a2" (文字列)

すべてのトークンは、ブール型の や文字列など、何らかの種類のオブジェクト型として解釈できます。 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' (文字列)

ネイティブ コマンドに引数を渡す

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> が定義された環境変数を参照していない場合、トークンは as-is.

ストリームリダイレクト ( >file.txt など) は、ターゲットコマンドの引数としてそのまま渡されるため、使用できません。

引用符文字を含む引数を渡す

一部のネイティブ コマンドでは、引用符文字を含む引数が必要です。 通常、PowerShell のコマンド ライン解析では、指定した引用符文字が削除されます。 解析された引数は、各パラメーターがスペースで区切られた 1 つの文字列に結合されます。 この文字列は、 オブジェクトの ProcessStartInfo プロパティに割り当てられます。 文字列内の引用符は、余分な引用符または円記号 (\) 文字を使用してエスケープする必要があります。

注

円記号 (\) 文字は、PowerShell によってエスケープ文字として認識されません。 これは、 ProcessStartInfo.Argumentsの基になるAPIで使用されるエスケープ文字です。

エスケープ要件の詳細については、 ProcessStartInfo.Arguments のドキュメントを参照してください。

次の例は、 TestExe.exe ツールを使用しています。 このツールは、PowerShell ソース リポジトリの Pester テストで使用されます。 これらの例の目的は、パスを引用符で囲まれた文字列として受け取ることができるように、ネイティブ コマンドに "C:\Program Files (x86)\Microsoft\" ディレクトリ パスを渡すことです。

の TestExe パラメーターには、実行可能ファイルの引数として受け取った値が表示されます。 このツールを使用して、引数内の文字が正しくエスケープされていることを確認できます。

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 --% """C:\Program Files (x86)\Microsoft\\""
TestExe -echoargs --% """%ProgramFiles(x86)%\Microsoft\\""

出力はすべての例で同じです。

Arg 0 is <"C:\Program Files (x86)\Microsoft\">

ソース コードから TestExe をビルドできます。 TestExeを参照してください。

PowerShell コマンドに引数を渡す

PowerShell 3.0 以降では、end-of-parameters トークン (--) を使用して、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>

こちらも参照ください