about_Parsing

簡単な説明

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

長い説明

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

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

Write-Host book

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

注意

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

  • 非効率的です。 これにより、PowerShell が複数回検索されます。
  • 同じ名前の外部プログラムが最初に解決されるため、目的のコマンドレットを実行することはできません。
  • Get-HelpGet-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 と文字列リテラル の 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" (文字列)
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 $- 引数 "$-" (string)
a$a Expression "a$a" (コマンド)
Write-Output a$a 引数 "a4" (文字列)
a'$a' Expression "a$a" (コマンド)
Write-Output a'$a' 引数 "a$a" (string)
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 引数 "!1" (文字列)
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 以降では、 stop-parsing (--%) トークンを使用して、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"

注意

Windows システム上の一部のコマンドは、Windows バッチ ファイルとして実装されます。 たとえば、Azure CLI のその az コマンドは Windows バッチ ファイルです。

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

一部のネイティブ コマンドでは、引用符文字を含む引数が必要です。 PowerShell 7.3 では、ネイティブ コマンドのコマンド ラインの解析方法が変更されました。

注意事項

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

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

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

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

$PSNativeCommandArgumentPassingが または StandardLegacy設定されている場合、パーサーはこれらのファイルをチェックしません。

注意

次の例では、 ツールを 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 では、ネイティブ コマンドのパラメーター バインドをトレースする機能も追加されました。 詳細については、「 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>

こちらもご覧ください