短縮版
引用符を含む引数を PowerShell からネイティブ コマンドに渡すにはどうすればよいですか?
引数文字列では、二重引用符の代わりに単一引用符を使用してください:
→
"/p:Target='Data Source=(local)\SQL;Integrated Security=True'"
/p:Target='Data Source=(local)\SQL;Integrated Security=True'
引数文字列の二重引用符にはバックスラッシュ エスケープを使用します∗ :
→
'/p:Target=\"Data Source=(local)\SQL;Integrated Security=True\"'
/p:Target="Data Source=(local)\SQL;Integrated Security=True"
埋め込まれた引用符が、引数をパラメーターの必須部分ではなく、単一の文字列として扱うためにのみ使用されている場合は、次を使用できます。
引数に引用符を埋め込む代わりに、引数文字列全体を引用します:
→
'/p:Target=Data Source=(local)\SQL;Integrated Security=True'
/p:Target=Data Source=(local)\SQL;Integrated Security=True
すべての PowerShell 特殊文字をバッククォートでエスケープします∗ (これはインライン引数としてのみ実行できます):
または
→
/p:Target=`"Data Source=`(local`)\SQL`;Integrated Security=True`"
/p:Target=Data` Source=`(local`)\SQL`;Integrated` Security=True
/p:Target=Data Source=(local)\SQL;Integrated Security=True
完全なコマンド ラインの例 (2 番目の方法を使用):
PS> [string[]]$arguments = @(
'/target:Deploy',
'/p:UseSandboxSettings=False',
'/p:TargetDatabase=UpdatedTargetDatabase',
'/p:TargetConnectionString=\"Data Source=(local)\SQL;Integrate Security=True\"',
'C:\program files\MyProjectName.dbproj'
)
PS> ./echoargs $arguments
Arg 0 は </target:Deploy> です
引数 1 は </p:UseSandboxSettings=False> です
引数 2 は </p:TargetDatabase=UpdatedTargetDatabase> です
Arg 3 は </p:TargetConnectionString="Data Source=(local)\SQL;Integrate Security=True"> です
Arg 4 は <C:\program files\MyProjectName.dbproj> です。
ロングバージョン
ネイティブ コマンドの呼び出しは、人々が従来の cmd システムと PowerShell の間を移動するときにかなり発生するものです (「コンマでパラメーターを区切る」という問題とほぼ同じです;)。
ここでは、PowerShell (v2 および v3) でのコマンド呼び出しに関して知っているすべてのことを、収集できるすべての例と参照と共にまとめてみました。
1) ネイティブ コマンドを直接呼び出す
1.1)環境パスにある実行可能ファイルの場合、PowerShell コマンドレットを呼び出すのと同じように、コマンドを直接呼び出すことができます。
PS> Get-ItemProperty echoargs.exe -Name IsReadOnly
...
IsReadOnly : True
PS> attrib echoargs.exe
A R C:\Users\Emperor XLII\EchoArgs.exe
1.2)環境パスの外側で、特定のディレクトリ (現在のディレクトリを含む) 内のコマンドの場合、コマンドへの完全パスまたは相対パスを使用できます。アイデアは、たまたま同じ名前を持つ任意のファイルをその場所で実行させるのではなく、オペレーターに「このファイルを呼び出したい」と明示的に宣言させることです ( PowerShell セキュリティの詳細については、この質問を参照してください)。必要なときにパスを使用しないと、「用語が認識されません」というエラーが発生します。
PS> echoargs arg
The term 'echoargs' is not recognized as the name of a cmdlet, function, script file,
or operable program...
PS> ./echoargs arg
Arg 0 is <arg>
PS> C:\Windows\system32\attrib.exe echoargs.exe
A R C:\Users\Emperor XLII\EchoArgs.exe
1.3) パスに特殊文字が含まれている場合は、呼び出し演算子またはエスケープ文字を使用できます。たとえば、数字で始まる実行可能ファイル、またはスペースを含むディレクトリにある実行可能ファイルです。
PS> $env:Path
...;C:\tools\;...
PS> Copy-Item EchoArgs.exe C:\tools\5pecialCharacter.exe
PS> 5pecialCharacter.exe special character
Bad numeric constant: 5.
PS> & 5pecialCharacter.exe special character
Arg 0 is <special>
Arg 1 is <character>
PS> `5pecialCharacter.exe escaped` character
Arg 0 is <escaped character>
PS> C:\Users\Emperor XLII\EchoArgs.exe path with spaces
The term 'C:\Users\Emperor' is not recognized as the name of a cmdlet, function,
script file, or operable program...
PS> & 'C:\Users\Emperor XLII\EchoArgs.exe' path with spaces
Arg 0 is <path>
Arg 1 is <with>
Arg 2 is <spaces>
PS> C:\Users\Emperor` XLII\EchoArgs.exe escaped` path with` spaces
Arg 0 is <escaped path>
Arg 1 is <with spaces>
2) ネイティブ コマンドを間接的に呼び出す
2.1)対話的にコマンドを入力するのではなく、パスを変数に格納している場合、call 演算子を使用して、変数で指定されたコマンドを呼び出すこともできます。
PS> $command = 'C:\Users\Emperor XLII\EchoArgs.exe'
PS> $command arg
Unexpected token 'arg' in expression or statement.
PS> & $command arg
Arg 0 is <arg>
2.2)コマンドに渡される引数は、変数に格納することもできます。変数の引数は、個別に渡すことも、配列で渡すこともできます。スペースを含む変数の場合、PowerShell は自動的にスペースをエスケープして、ネイティブ コマンドが単一の引数として認識できるようにします。(call 演算子は最初の値をコマンドとして扱い、残りの値を引数として扱うことに注意してください。引数をコマンド変数と組み合わせてはなりません。)
PS> $singleArg = 'single arg'
PS> $mushedCommand = "$command $singleArg"
PS> $mushedCommand
C:\Users\Emperor XLII\EchoArgs.exe single arg
PS> & $mushedCommand
The term 'C:\Users\Emperor XLII\EchoArgs.exe single arg' is not recognized as the
name of a cmdlet, function, script file, or operable program...
PS> & $command $singleArg
Arg 0 is <single arg>
PS> $multipleArgs = 'multiple','args'
PS> & $command $multipleArgs
Arg 0 is <multiple>
Arg 1 is <args>
2.3) 配列形式は、ネイティブ コマンドの引数の動的リストを作成する場合に特に便利です。各引数が個別のパラメーターとして認識されるようにするには、引数を配列変数に格納することが重要であり、1 つの文字列にまとめて変更するだけではありません。(一般的な省略形$args
は PowerShell の自動変数であり、保存された値が上書きされる可能性があることに注意してください。代わりに、$msbuildArgs
名前の競合を避けるために、わかりやすい名前を使用することをお勧めします。)
PS> $mungedArguments = 'initial argument'
PS> $mungedArguments += 'second argument'
PS> $mungedArguments += $(if( $someVariable ) { 'dynamic A' } else { 'dynamic B' })
PS> ./echoargs $mungedArguments
Arg 0 is <initial argumentsecond argumentdynamic B>
PS> $arrayArguments = @('initial argument')
PS> $arrayArguments += 'second argument'
PS> $arrayArguments += $(if( $someVariable ) { 'dynamic A' } else { 'dynamic B' })
PS> ./echoargs $arrayArguments
Arg 0 is <initial argument>
Arg 1 is <second argument>
Arg 2 is <dynamic B>
2.4)また、スクリプト、関数、コマンドレットなどの場合、PowerShell v2 は、「スプラッティング」と呼ばれる手法を使用して、パラメーターの順序を気にすることなく、ハッシュテーブルに含まれる名前付き引数を送信できます。これは、PowerShell オブジェクト モデルに参加せず、文字列値のみを処理できるネイティブ コマンドでは機能しません。
PS> $cmdletArgs = @{ Path = 'EchoArgs.exe'; Name = 'IsReadOnly' }
PS> $cmdlet = 'Get-ItemProperty'
PS> & $cmdlet $cmdletArgs # hashtable object passed to cmdlet
Cannot find path 'C:\Users\Emperor XLII\System.Collections.Hashtable'...
PS> & $cmdlet @cmdletArgs # hashtable values passed to cmdlet
...
IsReadOnly : True
PS> ./echoargs @cmdletArgs
Arg 0 is <Name>
Arg 1 is <IsReadOnly>
Arg 2 is <Path>
Arg 3 is <EchoArgs.exe>
3) 複雑な引数でネイティブ コマンドを呼び出す
3.1)単純な引数の場合、通常、ネイティブ コマンドに使用される自動エスケープで十分です。ただし、かっこ、ドル記号、スペースなどの場合、 PowerShell で使用される文字は、パーサーによって解釈されることなく、そのままネイティブ コマンドに送信されるようにエスケープする必要があります。これは、バックティック エスケープ文字 を`
使用するか、単一引用符文字列内に引数を配置することで実行できます。
PS> ./echoargs money=$10.00
Arg 0 is <money=.00>
PS> ./echoargs money=`$10.00
Arg 0 is <money=$10.00>
PS> ./echoargs value=(spaces and parenthesis)
The term 'spaces' is not recognized as the name of a cmdlet, function, script file,
or operable program...
PS> ./echoargs 'value=(spaces and parenthesis)'
Arg 0 is <value=(spaces and parenthesis)>
3.2)残念ながら、二重引用符が含まれている場合、これはそれほど単純ではありません。ネイティブ コマンドの引数処理の一環として、PowerShell プロセッサは引数のすべての二重引用符を正規化して、引数の内容 (引用符なし) が単一の値としてネイティブ コマンドに渡されるようにします。ネイティブ コマンド パラメーターの処理は、解析後に別のステップとして行われるため、通常のエスケープは二重引用符に対しては機能しません。エスケープされた一重引用符、またはバックスラッシュでエスケープされた二重引用符のみを使用できます。
PS> ./echoargs value="double quotes"
Arg 0 is <value=double quotes>
PS> ./echoargs 'value="string double quotes"'
Arg 0 is <value=string>
Arg 1 is <double>
Arg 2 is <quotes>
PS> ./echoargs value=`"escaped double quotes`"
Arg 0 is <value=escaped double quotes>
PS> ./echoargs 'value=\"backslash escaped double quotes\"'
Arg 0 is <value="backslash escaped double quotes">
PS> ./echoargs value='single quotes'
Arg 0 is <value=single quotes>
PS> ./echoargs "value='string single quotes'"
Arg 0 is <value='string single quotes'>
PS> ./echoargs value=`'escaped` single` quotes`'
Arg 0 is <value='escaped single quotes'>
3.3) PowerShell v3 では、新しい解析停止記号が追加されました--%
(「参考文献」を参照about_Parsing
)。複雑な引数の前に使用すると、cmd のような値--%
を除いて、解析や変数展開を行わずに引数をそのまま渡し%ENVIRONMENT_VARIABLE%
ます。
PS> ./echoargs User:"$env:UserName" "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash>
PS> ./echoargs User: "$env:UserName" --% "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>
PS> ./echoargs --% User: "%USERNAME%" "Hash"#555
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>
これは、複数の引数を表す単一の文字列を de-munge するためにも使用できます。これは、文字列∗に解析停止記号を渡すことによって可能です (ただし、ベスト プラクティスは、最初から引数を変更しないことです)。
PS> $user = 'User:"%USERNAME%"'
PS> $hash = 'Hash#' + $hashNumber
PS> $mungedArguments = $user,$hash -join ' '
PS> ./echoargs $mungedArguments
Arg 0 is <User:%USERNAME% Hash#555>
PS> ./echoargs --% $mungedArguments
Arg 0 is <$mungedArguments>
PS> ./echoargs '--%' $mungedArguments
Arg 0 is <User:Emperor XLII>
Arg 1 is <Hash#555>
4) ネイティブ コマンドのデバッグ
PowerShell がネイティブ コマンドに渡す引数をデバッグするための主要なツールが 2 つあります。
4.1) 1 つ目はEchoArgs.exe
、PowerShell Community Extensionsのコンソール アプリケーションで、渡された引数を山かっこで囲んで単純に書き戻します (上記の例を参照)。
4.2) 2 つ目はTrace-Command
、PowerShell がパイプラインを処理する方法の多くの詳細を表示できるコマンドレットです。特に、NativeCommandParameterBinder
トレース ソースは、PowerShell が受信してネイティブ コマンドに渡すものを示します。
PS> Trace-Command *NativeCommand* { ./echoargs value="double quotes" } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string: "value=double quotes"
DEBUG: NativeCommandParameterBinder : Argument 0: value=double quotes
PS> Trace-Command *NativeCommand* { ./echoargs 'value="double quotes"' } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string: "value="double quotes""
DEBUG: NativeCommandParameterBinder : Argument 0: value=double
DEBUG: NativeCommandParameterBinder : Argument 1: quotes
PS> Trace-Command *NativeCommand* { ./echoargs value=`"double quotes`" } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string: value="double quotes"
DEBUG: NativeCommandParameterBinder : Argument 0: value=double quotes
PS> Trace-Command *NativeCommand* { ./echoargs 'value=\"double quotes\"' } -PSHost
DEBUG: NativeCommandParameterBinder : Raw argument string: "value=\"double quotes\""
DEBUG: NativeCommandParameterBinder : Argument 0: value="double quotes"
その他のリソース
記事
質問