about_Parsing

簡単な説明

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

詳細な説明

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

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

Write-Host book

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

Note

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

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

式モード

式モードは、スクリプト言語での値操作に必要な式を組み合わせることを目的としています。 式は PowerShell 構文での値の表現であり、単純または複合にすることができます。次に例を示します。

リテラル式は、その値を直接表現します。

'hello'
32

変数式は、参照する変数の値を保持します。

$x
$script:path

演算子は、評価のために他の式を結合します。

-12
-not $Quiet
3 + 7
$input.Length -gt 1
  • 文字列リテラルは 引用符で囲む必要があります。
  • 数値 は、(エスケープされない限り) 一連の文字としてではなく数値として扱われます。
  • 項演算子 (like、二項演算子など--not) を含む演算子は演算子+-gtとして解釈され、それぞれの演算が引数 (オペランド) に適用されます。
  • 属性式と変換式は式 として解析され、下位式に適用されます。 (例: [int] '7')。
  • 変数参照 は値に対して評価されますが、 スプラッティング は禁止され、パーサー エラーが発生します。
  • それ以外は、呼び出されるコマンドとして扱われます。

引数モード

解析時に、PowerShell はまず入力を式として解釈します。 ただし、コマンド呼び出しが発生すると、解析は引数モードで続行されます。 パスなどのスペースを含む引数がある場合は、それらの引数値を引用符で囲む必要があります。

引数モードは、シェル環境のコマンドの引数とパラメーターを解析するために設計されています。 次のいずれかの構文を使用しない限り、すべての入力は展開可能な文字列として扱われます。

  • ドル記号 ($) の後に変数名が続いて変数参照が開始されます。それ以外の場合は、展開可能な文字列の一部として解釈されます。 変数参照には、メンバー アクセスまたはインデックス作成を含めることができます。

    • 単純な変数参照の後に続く追加の文字 (例: $HOME) は、同じ引数の一部と見なされます。 変数名を中かっこ ({}) で囲んで、後続の文字から区切ります。 たとえば、${HOME} のようにします。
    • 変数参照にメンバー アクセスが含まれている場合、最初の追加文字は新しい引数の先頭と見なされます。 たとえば、 $HOME.Length-more 値と文字列リテラルの 2 つの引数 $HOME.Length が返されます -more
  • 引用符 (' および ") の開始文字列

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

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

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

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

  • 先頭記号 (@) は、スプラッティング ()、配列 ()、ハッシュ テーブル リテラル (@(1,2,3)@args@{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" (文字列)

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

モード 結果
Write-Output !1 argument "!1" (文字列)
Write-Output (!1) 式 (expression) False (ブール値)
Write-Output (2) 式 (expression) 2 (整数)
Set-Variable AB A,B argument 'A','B' (配列)
CMD /CECHO A,B argument 'A,B' (文字列)
CMD /CECHO $AB 式 (expression) 'A B' (配列)
CMD /CECHO :$AB argument ':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 によって解析されます。 解析された引数は、各パラメーターがスペースで区切られた 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 コマンドまたは式として解釈するのを停止できます。

Note

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

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

停止解析トークンが検出されると、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"

Note

PowerShell コマンドレットを使用する場合、停止解析トークンは必要ありません。 ただし、これらの引数を使用してネイティブ コマンドを呼び出すために設計された PowerShell 関数に引数を渡すと便利な場合があります。

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

一部のネイティブ コマンドでは、引用符文字を含む引数が必要です。 PowerShell 7.2 には、ネイティブ コマンドの コマンド ラインの解析方法を変更する PSNativeCommandArgumentPassing 試験的機能が含まれています。 詳細については、「試験的機能の使用」を参照してください

注意

新しい動作は、 Windows 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 のいずれかに設定されている場合、パーサーはこれらのファイルのチェックは行いません。

Note

次の例では、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\\""

Note

バックスラッシュ (\) 文字は、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>

関連項目