PowerShell Invoke-Expression 命令混淆问题

3

我正在尝试从PowerShell脚本中调用一个命令。当从普通的命令行运行该命令时,它可以正常工作。以下是完整的命令(抱歉,它很长,但如果我截断它,我担心会遗漏一些重要的内容)。

C:\Users\Dave.Work\Desktop\wix36-binaries\candle.exe C:\Users\Dave.Work\Developer\MapCreator\install\win\product.wxs -arch x64 -dPlatform=x64 -dProductVersion=0.9.1.0 -dKarteReleaseBinDir=C:\Users\Dave.Work\Developer\MapCreator\karte-build-release\release -out C:\Users\Dave.Work\Developer\MapCreator\install\win\obj\

如果我使用Invoke-Expression调用这个完全相同的命令,它会失败。它会从可执行文件candle.exe中返回一个错误信息,但由于从命令行运行时工作正常,问题显然是powershell在某种程度上篡改了字符串。这是我的调用:

Invoke-Expression 'C:\Users\Dave.Work\Desktop\wix36-binaries\candle.exe C:\Users\Dave.Work\Developer\MapCreator\install\win\product.wxs -arch x64 -dPlatform=x64 -dProductVersion=0.9.1.0 -dKarteReleaseBinDir=C:\Users\Dave.Work\Developer\MapCreator\karte-build-release\release -out C:\Users\Dave.Work\Developer\MapCreator\install\win\obj\'

这会导致产生以下错误:
candle.exe : error CNDL0103 : The system cannot find the file '.9.1.0' with type 'Source'.

数字版本号出现了问题?但是在命令行中它可以很好地工作。

如何将此命令传递给PowerShell?

[注意] 最终,此命令是由变量生成的,即实际命令将类似于:

$WixDir\candle.exe $ScriptDir\product.wxs -arch $Platform -dPlatform=$Platform -dProductVersion=$ProductVersion -dKarteReleaseBinDir=$KarteReleaseBinDir -out $ScriptDir\obj\

我使用Invoke-Expression,因为我在使用例如调用运算符时扩展变量遇到了很大的问题。但是即使没有变量扩展,我也无法使其正常工作。因此,如果解决方案是转义命令字符串的某些部分,我还需要知道如何将这些转义应用于变量。


首先尝试使用“-dProductVersion=0.9.1.0”并用引号括起来。 - Roman Kuzmin
@RomanKuzmin:是的,就是这样。而且看起来使用变量版本(使用双引号)是 " ... -dPlatform=$Platform ""-dProductVersion=$ProductVersion"" -dKarteReleaseBinDir= ... " 如果你想把它放在答案中,我会标记它为已接受的。我也很好奇为什么它能工作。我认为单引号应该保留字符串。 - Dave Mateer
或者用'。我的 get-arg 工具显示原始命令被分割为:-dProductVersion=0.9.1.0 是不同的参数。 - Roman Kuzmin
1个回答

7
尝试使用引号 " 或 ' 包裹 "-dProductVersion=0.9.1.0"。我的 Get-Arg 实用程序显示,原始命令被解析为 -dProductVersion=0.9.1.0 两个不同的参数。如果需要,这是我的 Get-Arg.exe(C#):
using System;
class GetArg
{
    static void Main(string[] args)
    {
        foreach(string s in args)
        {
            Console.WriteLine(s);
        }
    }
}

这很有用,可以用于检查这些情况。


这里有一个更简单的例子,这段代码:

function Get-Argument {
    $args
}

Get-Argument -dProductVersion=0.9.1.0

获取此输出:

-dProductVersion=0
.9.1.0

这意味着PowerShell将这样的命令视为具有两个参数。


解释

PowerShell 2.0语言规范中,我们可以看到针对参数的说明。

parameter-char:
Any Unicode character except
{   }   (   )   ;   ,   |   &   .   [
colon
whitespace
new-line-character

注意:这里包括“=”,但不包括“.”。在我们的情况下,我们有:
-dProductVersion=0.9.1.0

根据规范,'.'之前的所有字符都是有效的参数字符。因此,我们得到第一个结果参数是-dProductVersion=0
然后解析器在'.'处卡住了。从技术上讲,我们好像违反了规则,将'.'包含在以'-'开头的参数中。这就是为什么我们应该用单引号或双引号括起整个参数的原因。
这对其他被排除的字符也可能适用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接