带有嵌套引号的 Powershell 调用 msbuild [英] Powershell call msbuild with nested quotation marks
问题描述
使用 Powershell 和 Psake 为 Visual Studio 解决方案创建包和部署.尝试使用 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 中复制此调用 - 示例数据库连接字符串数据源=.SQL2008;初始目录=DocumentExecution;集成安全=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"'代码>
→/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=`"数据源=`(本地`)SQL`;Integrated Security=True`"
或/p:Target=Data`来源=`(本地`)SQL`;集成`Security=True
→/p:Target=Data Source=(local)SQL;集成 Security=True
完整的命令行示例(使用第二种选择):
PS>[字符串[]]$arguments = @('/目标:部署','/p:UseSandboxSettings=False','/p:TargetDatabase=UpdatedTargetDatabase','/p:TargetConnectionString="数据源=(本地)SQL;Integrate Security=True"','C:程序文件MyProjectName.dbproj')PS>./echoargs $参数
<上一页>Arg 0 是 </target:Deploy>Arg 1 是 </p:UseSandboxSettings=False>Arg 2 是 </p:TargetDatabase=UpdatedTargetDatabase>Arg 3 是 </p:TargetConnectionString="Data Source=(local)SQL;Integrate Security=True">Arg 4 是 <C:program filesMyProjectName.dbproj>
加长版
当人们在旧的 cmd 系统和 PowerShell 之间移动时,调用本机命令会出现很多情况(几乎与用逗号分隔参数"的陷阱一样多;).
我已经尝试并总结了我所知道的关于 PowerShell(v2 和 v3)中的命令调用主题的所有内容,以及我能收集到的所有示例和参考资料.
1) 直接调用原生命令
1.1) 最简单的情况是,对于位于环境路径中的可执行文件,可以直接调用该命令,就像调用 PowerShell cmdlet 一样.p>
PS>Get-ItemProperty echoargs.exe -Name IsReadOnly...IsReadOnly : 真PS>属性 echoargs.exeA R C:UsersEmperor XLIIEchoArgs.exe
1.2) 在环境路径之外,对于特定目录(包括当前目录)中的命令,可以使用命令的完整路径或相对路径.这个想法是让操作员明确声明我想调用 this 文件",而不是让一个碰巧具有相同名称的任意文件在其位置运行(有关 PowerShell 安全性的更多信息,请参阅此问题).在需要时未能使用路径将导致无法识别术语"错误.
PS>回声参数术语echoargs"未被识别为 cmdlet、函数、脚本文件的名称,或可运行的程序...PS>./echoargs argArg 0 是<arg>PS>C:Windowssystem32attrib.exe echoargs.exeA R C:UsersEmperor XLIIEchoArgs.exe
1.3) 如果路径包含特殊字符,可以使用调用运算符或转义字符.例如,可执行文件以数字开头,或位于包含空格的目录中.
PS>$env:路径...;C:工具;...PS>复制项目 EchoArgs.exe C: ools5pecialCharacter.exePS>5pecialCharacter.exe 特殊字符错误的数字常量:5.PS>&5pecialCharacter.exe 特殊字符Arg 0 是<特殊>Arg 1 是<字符>PS>`5pecialCharacter.exe 转义` 字符Arg 0 是<转义字符>PS>C:UsersEmperor XLIIEchoArgs.exe 带空格的路径术语C:UsersEmperor"未被识别为 cmdlet、函数的名称,脚本文件或可运行的程序...PS>&'C:UsersEmperor XLIIEchoArgs.exe' 带空格的路径Arg 0 是<路径>Arg 1 是 <with>Arg 2 是<空格>PS>C:UsersEmperor` XLIIEchoArgs.exe 转义` 路径与` 空格Arg 0 是<转义路径>Arg 1 是<有空格>
2) 间接调用原生命令
2.1) 当您不以交互方式输入命令,而是将路径存储在变量中时,调用运算符也可用于调用在变量中命名的命令.
PS>$command = 'C:UsersEmperor XLIIEchoArgs.exe'PS>$命令参数表达式或语句中出现意外的标记arg".PS>&$命令参数Arg 0 是<arg>
2.2) 传递给命令的参数也可以存储在变量中.变量中的参数可以单独传递,也可以在数组中传递. 对于包含空格的变量,PowerShell 会自动转义空格,以便本机命令将其视为单个参数.(请注意,调用运算符将第一个值视为命令,其余值视为参数;参数不应与命令变量组合.)
PS>$singleArg = '单个参数'PS>$mushedCommand = "$command $singleArg"PS>$musedCommandC:UsersEmperor XLIIEchoArgs.exe 单参数PS>&$musedCommand术语C:UsersEmperor XLIIEchoArgs.exe single arg"未被识别为cmdlet、函数、脚本文件或可运行程序的名称...PS>&$command $singleArgArg 0 是<单个 arg>PS>$multipleArgs = '多个','args'PS>&$command $multipleArgsArg 0 是<多个>Arg 1 是 <args>
2.3) 数组格式对于为本地命令构建动态参数列表特别有用. 对于要识别为不同参数的每个参数,将参数存储在数组中很重要变量,而不仅仅是在一个字符串中混合在一起.(请注意,常用缩写 $args
是 PowerShell 中的自动变量,这可能会导致其中保存的值被覆盖;相反,最好使用描述性名称,例如 $msbuildArgs
以避免命名冲突.)
PS>$mungedArguments = '初始参数'PS>$mungedArguments += '第二个参数'PS>$mungedArguments += $(if( $someVariable ) { '动态 A' } else { '动态 B' })PS>./echoargs $mungedArgumentsArg 0 是 <initial argumentsecond argumentdynamic B>PS>$arrayArguments = @('初始参数')PS>$arrayArguments += '第二个参数'PS>$arrayArguments += $(if( $someVariable ) { '动态 A' } else { '动态 B' })PS>./echoargs $arrayArgumentsArg 0 是<初始参数>Arg 1 是<第二个参数>Arg 2 是<动态 B>
2.4) 此外,对于脚本、函数、cmdlet 等,PowerShell v2 可以使用称为splatting"的技术发送包含在哈希表中的命名参数,而不必担心参数顺序.这不适用于本机命令,本机命令不参与 PowerShell 对象模型,只能处理字符串值.
PS>$cmdletArgs = @{ 路径 = 'EchoArgs.exe';名称 = 'IsReadOnly' }PS>$cmdlet = '获取项目属性'PS>&$cmdlet $cmdletArgs # 传递给 cmdlet 的哈希表对象找不到路径'C:UsersEmperor XLIISystem.Collections.Hashtable'...PS>&$cmdlet @cmdletArgs # 传递给 cmdlet 的哈希表值...IsReadOnly : 真PS>./echoargs @cmdletArgsArg 0 是<名称>Arg 1 是 <IsReadOnly>Arg 2 是<路径>Arg 3 是 <EchoArgs.exe>
3) 使用复杂参数调用本机命令
3.1) 对于简单的参数,用于本机命令的自动转义通常就足够了.但是,对于括号、美元符号、空格等,PowerShell 使用的字符需要转义才能按原样发送到本机命令,而不需要解析器对其进行解释.这可以通过反引号转义字符 `
或将参数放在单引号字符串中来完成.
PS>./echoargs 钱=$10.00Arg 0 是 <money=.00>PS>./echoargs 钱=`$10.00Arg 0 是 <money=$10.00>PS>./echoargs 值=(空格和括号)术语空格"未被识别为 cmdlet、函数、脚本文件的名称,或可运行的程序...PS>./echoargs '值=(空格和括号)'Arg 0 是<值=(空格和括号)>
3.2) 不幸的是,当涉及双引号时,这并不是那么简单.作为本机命令的参数处理的一部分,PowerShell 处理器尝试对参数中的所有双引号进行规范化,以便将无引号的参数内容作为单个值传递给本机命令.本机命令参数处理在解析后作为单独的步骤发生,因此 正常转义对双引号不起作用;只能使用转义的单引号或反斜杠转义的双引号.
PS>./echoargs value="双引号"Arg 0 是<值=双引号>PS>./echoargs 'value="字符串双引号"'Arg 0 是 <value=string>Arg 1 是 <double>Arg 2 是 <quotes>PS>./echoargs value=`"转义双引号`"Arg 0 是<value=转义的双引号>PS>./echoargs 'value="反斜杠转义双引号"'Arg 0 是 <value="反斜杠转义双引号">PS>./echoargs value='单引号'Arg 0 是<值=单引号>PS>./echoargs "value='字符串单引号'"Arg 0 是<value='字符串单引号'>PS>./echoargs value=`'转义`单`引号`'Arg 0 是<value='转义单引号'>
3.3) PowerShell v3 添加了一个新的停止解析符号 --%
(请参阅 about_Parsing
).在复杂参数之前使用时,--%
将按原样传递参数,无需任何解析或变量扩展,除了类似 cmd 的 %ENVIRONMENT_VARIABLE%
值强>.
PS>./echoargs 用户:"$env:UserName" "Hash"#555Arg 0 是 <User:Emperor XLII>Arg 1 是 <Hash>PS>./echoargs 用户: "$env:UserName" --% "Hash"#555Arg 0 是 <User:Emperor XLII>Arg 1 是 <Hash#555>PS>./echoargs --% 用户:%USERNAME%"哈希"#555Arg 0 是 <User:Emperor XLII>Arg 1 是 <Hash#555>
这也可用于通过在字符串中传递停止解析符号来消除表示多个参数的单个字符串∗ (尽管最好的做法是一开始就不要混淆参数).
PS>$user = '用户:"%USERNAME%"'PS>$hash = '哈希#' + $hashNumberPS>$mungedArguments = $user,$hash -join ' 'PS>./echoargs $mungedArgumentsArg 0 是 <用户:%USERNAME% Hash#555>PS>./echoargs --% $mungedArgumentsArg 0 是 <$mungedArguments>PS>./echoargs '--%' $mungedArgumentsArg 0 是 <User:Emperor XLII>Arg 1 是 <Hash#555>
4) 调试原生命令
有两个关键工具可用于调试 PowerShell 传递给本机命令的参数.
4.1) 第一个是 EchoArgs.exe
,一个来自 PowerShell 社区扩展,它只是在尖括号之间写回传递给它的参数(如上面的示例所示).
4.2) 第二个是Trace-Command
,一个 cmdlet,可以显示 PowerShell 如何处理管道的许多详细信息.特别是,NativeCommandParameterBinder
跟踪源将显示 PowerShell 接收并传递给本机命令的内容.
PS>Trace-Command *NativeCommand* { ./echoargs value="双引号" } -PSHost调试:NativeCommandParameterBinder:原始参数字符串:值=双引号"调试:NativeCommandParameterBinder:参数 0:值 = 双引号PS>跟踪命令 *NativeCommand* { ./echoargs 'value="双引号"' } -PSHost调试:NativeCommandParameterBinder:原始参数字符串:value="双引号""调试:NativeCommandParameterBinder:参数 0:value=double调试:NativeCommandParameterBinder:参数 1:引号PS>Trace-Command *NativeCommand* { ./echoargs value=`"双引号`" } -PSHost调试:NativeCommandParameterBinder:原始参数字符串:value="双引号"调试:NativeCommandParameterBinder:参数 0:值 = 双引号PS>Trace-Command *NativeCommand* { ./echoargs 'value="双引号"' } -PSHost调试:NativeCommandParameterBinder:原始参数字符串:value="双引号"调试:NativeCommandParameterBinder:参数 0:value="双引号"
其他资源
文章
- 2012-01-02 - PowerShell V3 CTP2 为 EXE 提供更好的参数传递
- 2011-03-10 - The从 PowerShell 调用旧版/本机应用程序的问题
- 2010-11-04 - 转义空间
- 2010-02-01 - 将 MSDeploy 与 PowerShell 结合使用的考验和磨难
- 2008-10-17 - 执行需要引号和变量的命令实际上是不可能的 [连接]
- 2006-05-15 - 无法输入包含双引号的参数 [连接]
问题
- 2013-09-11 - powershell 执行外部命令不接受参数
- 2013-02-20 - 带双引号的参数未通过 ArgumentList 正确传递给 Scriptblock
- 2013-01-02 - 错误:描述 = 无效查询
- 2012-09-18 - 如何在 PowerShell 中执行带参数的外部程序?
- 2012-09-10 - 从 powershell 脚本调用可执行文件(带参数)
- 2012-08-16 - 从 PowerShell 运行时,如何在 MSBuild 命令行上传递包含分号的属性值?一个>
- 2012-08-08 - 从 powershell 调用 ruby 脚本
- 2012-08-01 - 括号或引号破坏了 powershell 命令
- 2012-07-13 - 使用 powershell 按标签执行源代码安全获取的问题
- 2012-06-13 - 缺少参数 -m 在 windows powershell 上使用 svn
- 2012-06-01 - Powershell 命令行参数带有空格和大括号?
- 2012-04-18 - 间隔路径、msbuild 和 psake
- 2012-04-12 - 使 Power shell 忽略分号
- 2012-03-08 - 带参数的简单 Powershell Msbuild 失败
- 2012-02-10 - 引用 Powershell 中的疯狂
- 2012-01-18 - Powershell:使用动态创建的参数运行 msiexec
- 2012-01-18 - PowerShell 的调用运算符 (&) 语法和双引号
- 2012-01-16 - PowerShell - 使用空格传递计算路径
- 2012-01-09 - powershell:使用参数启动程序的脚本?
- 2011-12-20 - Powershell - 使用参数中包含的括号调用 icacls
- 2011-12-15 - Msbuild 日志在通过 powershell 执行时不起作用
- 2011-12-06 - 将参数从 Powershell 传递给 InstallUtil
- 2011-11-23 - 使用 Powershell 执行带参数的 exe
- 2011-11-08 - Powershell 在启动进程时删除引号
- 2011-09-16 - 在 PowerShell 中使用引号括起来的变量执行的命令失败.为什么?
- 2011-07-25 - Powershell 奇怪地解析引号(包括 在其中一个答案中对引号解析的简短分析)
- 2011-07-15 - powershell 从命令行参数中去除双引号
- 2011-06-14 - 在 Powershell 中,如何从字符串执行任意本机命令?
- 2011-06-03 - Powershell 使用嵌套引号调用 msbuild
- 2011-05-13 - powershell - 将参数传递给 exe
- 2011-03-02 - 为什么这个 PowerShell 脚本无法正确执行这个外部命令?
- 2011-01-09 - 使用 powershell 脚本执行 EXE 文件
- 2010-12-13 - exe 的命令行参数
- 2010-10-08 - 这个 PowerShell 命令行引用/转义是怎么回事?
- 2010-10-05 - 使用 powershell 从包含空格的目录运行 exe
- 2010-08-28 - 从 Powershell 执行存储在变量中的命令
- 2010-08-17 - 参数有空格时如何从powershell调用msdeploy?
- 2010-04-12 - 如何将 Powershell 命令中的引号抑制为可执行文件
- 2010-01-26 - powershell 向外部命令发送多个参数
- 2009-11-04 - 如何在 powershell 中使用带空格和引号的参数运行 exe
- 2009-03-16 - PowerShell - 启动进程和命令行开关
- 2009-01-14 - 如何在 Powershell 上转义命令行参数?
Using Powershell and Psake to create package and deployment for a visual studio solution. Trying to deploy a database project using msbuild - which is working correctly using msdos visual studio command line
msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"
the same method call results in an error when called from powershell
& msbuild /target:Deploy /p:UseSandboxSettings=false /p:TargetConnectionString="aConnectionWithSpacesAndSemiColons" "aDatabaseProjectPathWithSpaces"
relating to spaces - can't figure out how to replicate this call in powershell - sample database connectionstring Data Source=.SQL2008;Initial Catalog=DocumentExecution;Integrated Security=True;
Short Version
How do you pass an argument containing quotes into a native command from PowerShell?
Use single quotes instead of double quotes in the argument string:
"/p:Target='Data Source=(local)SQL;Integrated Security=True'"
→/p:Target='Data Source=(local)SQL;Integrated Security=True'
Use backslash-escaping for double quotes in the argument string∗:
'/p:Target="Data Source=(local)SQL;Integrated Security=True"'
→/p:Target="Data Source=(local)SQL;Integrated Security=True"
If the embedded quotes are only being used to treat the argument as a single string, rather than being a required part of the parameter, then the following can be used:
Quote the entire argument string, instead of embedding quotes in the argument:
'/p:Target=Data Source=(local)SQL;Integrated Security=True'
→/p:Target=Data Source=(local)SQL;Integrated Security=True
Escape all PowerShell special characters with backticks∗ (this can only be done as an in-line argument):
/p:Target=`"Data Source=`(local`)SQL`;Integrated Security=True`"
or/p:Target=Data` Source=`(local`)SQL`;Integrated` Security=True
→/p:Target=Data Source=(local)SQL;Integrated Security=True
Full command line example (using the second alternative):
PS> [string[]]$arguments = @(
'/target:Deploy',
'/p:UseSandboxSettings=False',
'/p:TargetDatabase=UpdatedTargetDatabase',
'/p:TargetConnectionString="Data Source=(local)SQL;Integrate Security=True"',
'C:program filesMyProjectName.dbproj'
)
PS> ./echoargs $arguments
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)SQL;Integrate Security=True"> Arg 4 is <C:program filesMyProjectName.dbproj>
Long Version
Calling native commands is something that crops up quite a bit as folks move between the legacy cmd system and PowerShell (almost as much as the "separating parameters with commas" gotcha ;).
I've tried and sum up everything I know on the subject of command invocation in PowerShell (v2 and v3) here, along with all the examples and references I can muster.
1) Calling Native Commands Directly
1.1) At its simplest, for an executable located in the environment path, the command can be called directly, just as you would call a PowerShell cmdlet.
PS> Get-ItemProperty echoargs.exe -Name IsReadOnly
...
IsReadOnly : True
PS> attrib echoargs.exe
A R C:UsersEmperor XLIIEchoArgs.exe
1.2) Outside of the environment path, for commands in a specific directory (including the current one), the full or relative path to the command can be used. The idea is to have the operator declare explicitly "I want to invoke this file", rather than let an arbitrary file that happened to have the same name get run in its place (see this question for more info on PowerShell security). Failing to use a path when it is required will result in a "term is not recognized" error.
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:Windowssystem32attrib.exe echoargs.exe
A R C:UsersEmperor XLIIEchoArgs.exe
1.3) If a path contains special characters, the call operator or escape character can be used. For example, an executable starting with a number, or located in a directory containing a space.
PS> $env:Path
...;C: ools;...
PS> Copy-Item EchoArgs.exe C: ools5pecialCharacter.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:UsersEmperor XLIIEchoArgs.exe path with spaces
The term 'C:UsersEmperor' is not recognized as the name of a cmdlet, function,
script file, or operable program...
PS> & 'C:UsersEmperor XLIIEchoArgs.exe' path with spaces
Arg 0 is <path>
Arg 1 is <with>
Arg 2 is <spaces>
PS> C:UsersEmperor` XLIIEchoArgs.exe escaped` path with` spaces
Arg 0 is <escaped path>
Arg 1 is <with spaces>
2) Calling Native Commands Indirectly
2.1) When you are not typing out a command interactively, but instead have the path stored in a variable, the call operator can also be used to invoke the command named in a variable.
PS> $command = 'C:UsersEmperor XLIIEchoArgs.exe'
PS> $command arg
Unexpected token 'arg' in expression or statement.
PS> & $command arg
Arg 0 is <arg>
2.2) The arguments passed to a command can also be stored in variables. Arguments in variables can be passed individually, or in an array. For variables containing spaces, PowerShell will automatically escape the spaces so that the native command sees it as a single argument. (Note that the call operator treats the first value as the command and the remaining values as arguments; the arguments should not be combined with the command variable.)
PS> $singleArg = 'single arg'
PS> $mushedCommand = "$command $singleArg"
PS> $mushedCommand
C:UsersEmperor XLIIEchoArgs.exe single arg
PS> & $mushedCommand
The term 'C:UsersEmperor XLIIEchoArgs.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) The array format is especially useful for building up a dynamic list of arguments for a native command. For each argument to be recognized as a distinct parameter, it is important that the arguments get stored in an array variable, and not just munged together in one string. (Note that the common abbreviation $args
is an automatic variable in PowerShell, which can cause values saved in it to get overwritten; instead, it is better to use a descriptive name like $msbuildArgs
to avoid the naming conflict.)
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) Also, for scripts, functions, cmdlets, and the like, PowerShell v2 can send named arguments contained in a hashtable using a technique called "splatting", without having to worry about parameter order. This does not work with native commands, which do not participate in the PowerShell object model and can only handle string values.
PS> $cmdletArgs = @{ Path = 'EchoArgs.exe'; Name = 'IsReadOnly' }
PS> $cmdlet = 'Get-ItemProperty'
PS> & $cmdlet $cmdletArgs # hashtable object passed to cmdlet
Cannot find path 'C:UsersEmperor XLIISystem.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) Calling Native Commands With Complicated Arguments
3.1) For simple arguments, the automatic escaping used for native commands is generally sufficient. However, for parenthesis, dollar signs, spaces, and such, characters used by PowerShell need to be escaped to be sent as-is to native commands, without having them interpreted by the parser. This can be done with the backtick escape character, `
, or by putting the argument inside a single-quote string.
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) Unfortunately, this is not so simple when double quotes are involved. As part of argument processing for native commands, the PowerShell processor attempts to normalize all double quotes in an argument so that the contents of the argument, sans quotes, is passed as a single value to the native command. The native command parameter processing occurs as a separate step after parsing, so normal escaping will not work for double quotes; only escaped single quotes, or backslash-escaped double quotes can be used.
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 added a new stop-parsing symbol --%
(see about_Parsing
). When used before complicated arguments, --%
will pass arguments as-is without any parsing or variable expansion, except for cmd-like %ENVIRONMENT_VARIABLE%
values.
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>
This can also be used to de-munge a single string representing multiple arguments, by passing the stop-parsing symbol in a string∗ (although the best practice is to not munge arguments in the first place).
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) Debugging Native Commands
There are two key tools for debugging the arguments PowerShell passes to native commands.
4.1) The first is EchoArgs.exe
, a console application from the PowerShell Community Extensions that simply writes back the arguments passed to it between angle brackets (as shown in the examples above).
4.2) The second is Trace-Command
, a cmdlet that can show many details of how PowerShell processes a pipeline. In particular, the NativeCommandParameterBinder
trace source will show what PowerShell receives and passes on to a native command.
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"
Other Resources
Articles
- 2012-01-02 - PowerShell V3 CTP2 Provides Better Argument Passing to EXEs
- 2011-03-10 - The problem with calling legacy/native apps from PowerShell
- 2010-11-04 - Escaping Spaces
- 2010-02-01 - The trials and tribulations of using MSDeploy with PowerShell
- 2008-10-17 - Executing commands which require quotes and variables is practically impossible [Connect]
- 2006-05-15 - Cannot enter an argument containing double quotes [Connect]
Questions
- 2013-09-11 - powershell executing external command not accepting parameter
- 2013-02-20 - Parameters with double quotes are not properly passed to Scriptblock by ArgumentList
- 2013-01-02 - ERROR: Description = Invalid query
- 2012-09-18 - How can I execute an external program with parameters in PowerShell?
- 2012-09-10 - Invoke executable (w/parameters) from powershell script
- 2012-08-16 - How do I pass a property value containing a semicolon on the MSBuild command line when running it from PowerShell?
- 2012-08-08 - Call ruby script from powershell
- 2012-08-01 - Brackets or quotation marks breaking a powershell command
- 2012-07-13 - Problems using powershell to perform a source safe get by label
- 2012-06-13 - Missing argument -m using svn at windows powershell
- 2012-06-01 - Powershell command line argument with spaces and curly brackets?
- 2012-04-18 - Spaced paths, msbuild, and psake
- 2012-04-12 - Make Power shell ignore semicolon
- 2012-03-08 - Simple Powershell Msbuild with parameter fails
- 2012-02-10 - Quote Madness in Powershell
- 2012-01-18 - Powershell: run msiexec with dynamically created parameters
- 2012-01-18 - PowerShell's call operator (&) syntax and double-quotes
- 2012-01-16 - PowerShell - passing calculated paths with spaces
- 2012-01-09 - powershell: script to start a program with parameters?
- 2011-12-20 - Powershell - calling icacls with parantheses included in parameters
- 2011-12-15 - Msbuild log doesn't work when executed through powershell
- 2011-12-06 - Pass parameters to InstallUtil from Powershell
- 2011-11-23 - Executing an exe with arguments using Powershell
- 2011-11-08 - Powershell remove quotes when start process
- 2011-09-16 - Commands executed in PowerShell with variables surrounded in quotes fail. Why?
- 2011-07-25 - Powershell parsing quotes strangely (includes a short analysis of quote parsing in one of the answers)
- 2011-07-15 - powershell stripping double quotes from command line arguments
- 2011-06-14 - In Powershell, how do you execute an arbitrary native command from a string?
- 2011-06-03 - Powershell call msbuild with nested quotation marks
- 2011-05-13 - powershell - passing parameters to exe
- 2011-03-02 - Why does this PowerShell script fail to execute this external command properly?
- 2011-01-09 - Executing an EXE file using powershell script
- 2010-12-13 - Command-line arguments to an exe
- 2010-10-08 - What is up with this PowerShell command line quoting/escaping?
- 2010-10-05 - Running an exe using powershell from a directory with spaces in it
- 2010-08-28 - Executing a Command stored in a Variable from Powershell
- 2010-08-17 - How do you call msdeploy from powershell when the parameters have spaces?
- 2010-04-12 - How to suppress quotes in Powershell commands to executables
- 2010-01-26 - powershell sending multiple parameter to a external command
- 2009-11-04 - How to run exe in powershell with parameters with spaces and quotes
- 2009-03-16 - PowerShell - Start-Process and Cmdline Switches
- 2009-01-14 - How to escape command line arguments on Powershell?
这篇关于带有嵌套引号的 Powershell 调用 msbuild的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!