25

Powershell と Psake を使用して、ビジュアル スタジオ ソリューションのパッケージと展開を作成します。msbuild を使用してデータベース プロジェクトを展開しようとしています - msdos Visual Studio コマンド ラインを使用して正しく動作しています

   msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"

powershell から同じメソッドを呼び出すと、エラーが発生する

& msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"

スペースに関連 - この呼び出しを powershell で複製する方法がわかりません - サンプル データベース connectionstring Data Source=.\SQL2008;Initial Catalog=DocumentExecution;Integrated Security=True;

4

7 に答える 7

62

短縮版

引用符を含む引数を 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.exePowerShell 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"


その他のリソース

記事

質問

于 2011-12-12T00:29:38.407 に答える
11

Start-Process-ArgumentListパラメーターを指定してコマンドレットを使用すると、これをすべて簡単に行うことができます。これがまだ言及されていないことに驚いています。

例:

Start-Process -FilePath msbuild.exe -ArgumentList '/target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"';

これが私がもう少しよく使うのが好きな方法です。それは変数の置換を可能にします:

$ConnectionString = 'aConnectionWithSpacesAndSemiColons';
$DatabaseProjectPath = 'aDatabaseProjectPathWithSpaces';
$MsbuildArguments = '/target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="{0}" "{1}"' -f $ConnectionString, $DatabaseProjectPath;
Start-Process -FilePath msbuild.exe -ArgumentList $MsbuildArguments;
于 2012-03-03T05:07:07.230 に答える
4

パラメータ全体を一重引用符で囲みます。

& msbuild /target:Deploy /p:UseSandboxSettings=false '/p:TargetConnectionString="aConnectionWithSpacesAndSemiColons"' "aDatabaseProjectPathWithSpaces"

余分なレベルの引用は、PSH が PSH のルールでコンテンツを処理しないことを意味します。(文字列内の単一引用符はすべて二重にする必要があります。これは、PSH 単一引用符で囲まれた文字列での唯一のエスケープ タイプです)。

于 2011-06-03T08:26:42.057 に答える
1

問題は、PowerShellが引用符をコマンドラインアプリケーションに渡すときに引用符をエスケープしないことです。私は自分でこれに遭遇し、PowerShellが引用符を食べていると思いました。これを行うだけです。

msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetDatabase=UpdatedTargetDatabase '/p:TargetConnectionString=\"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False\"' "C:\program files\MyProjectName.dbproj"
于 2011-06-24T15:58:09.767 に答える
1

@Richard - これをテストすると、有効なプロジェクト ファイルが提供されていないという別のエラーが生成されます。これを echoargs pscx ヘルパーで実行して、より詳細な例をいくつか示しました。

  1. TargetConnectionString を単一引用符で囲む - Powershell は、接続文字列内の各スペースを新しい行として評価します。

    & echoargs /target:Deploy /p:UseSandboxSettings=false    /p:TargetDatabase=UpdatedTargetDatabase /p:TargetConnectionString='"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"' "C:\program files\MyProjectName.dbproj"
    
    Arg 0 is </target:Deploy>
    Arg 1 is </p:UseSandboxSettings=false>
    Arg 2 is </p:TargetDatabase=UpdatedTargetDatabase>
    Arg 3 is </p:TargetConnectionString=Data>
    Arg 4 is <Source=(local)\SQLEXPRESS;Integrated>
    Arg 5 is <Security=True;Pooling=False>
    Arg 6 is <C:\program files\MyProjectName.dbproj>
    
  2. 各パラメーターを逆引用符で区切ると、最初の問題が再現されます = 接続文字列を引用符で囲むことはできません。

    & echoargs /target:Deploy `
    /p:UseSandboxSettings=false `
    

    c /p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False" "C:\program files\MyProjectName.dbproj"

    Arg 0 is </target:Deploy>
    Arg 1 is </p:UseSandboxSettings=false>
    Arg 2 is </p:TargetDatabase=UpdatedTargetDatabase>
    Arg 3 is </p:TargetConnectionString=Data Source=(local)\SQLEXPRESS;Integrated Se
    curity=True;Pooling=False>
    Arg 4 is <C:\program files\MyProjectName.dbproj>
    
  3. 引用符にバッククォートを追加すると、例 1 と同じように動作します。

    & echoargs /target:Deploy `
    /p:UseSandboxSettings=false `
    /p:TargetDatabase=UpdatedTargetDatabase `
    "/p:TargetConnectionString=`"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"`"  `
    "C:\program files\MyProjectName.dbproj"
    
  4. @ 演算子を使用してパラメーターを分割しようとしても、引用符は無視されます。

    $args = @('/target:Deploy','/p:UseSandboxSettings=false','     /p:TargetDatabase=UpdatedTargetDatabase','/p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"','C:\program files\MyProjectName.dbproj'); $args 
    
    /target:Deploy
    /p:UseSandboxSettings=false
    /p:TargetDatabase=UpdatedTargetDatabase
    /p:TargetConnectionString="Data Source=(local)\SQLEXPRESS;Integrated           Security=True;Pooling=False"
    C:\program files\MyProjectName.dbproj
    
    & echoargs $args
    
  5. 行区切り記号を使用して接続文字列をエスケープするバッククォート - 例 1 と同じ結果:

    & echoargs /target:Deploy `
    /p:UseSandboxSettings=false `
    /p:TargetDatabase=UpdatedTargetDatabase `
    "/p:TargetConnectionString=`"Data Source=(local)\SQLEXPRESS;Integrated Security=True;Pooling=False"`" `
    "C:\program files\MyProjectName.dbproj"
    
于 2011-06-04T00:53:32.737 に答える
1

JohnFの回答のおかげで、ついにこれを理解することができました。

echoargs /target:clean`;build`;deploy /p:UseSandboxSettings=false /p:TargetConnectionString=`"Data
Source=.`;Integrated Security=True`;Pooling=False`" .\MyProj.dbproj
Arg 0 is </target:clean;build;deploy>
Arg 1 is </p:UseSandboxSettings=false>
Arg 2 is </p:TargetConnectionString=Data Source=.;Integrated Security=True;Pooling=False>
Arg 3 is <.\MyProj.dbproj>

要するに、二重引用符とセミコロンの前のバッククォートです。それ以下 (またはそれ以上!) だと台無しになります。

于 2011-12-08T22:34:21.293 に答える