【问题标题】:Powershell: Call operator (&) with escape param (--%) not working with non-static argsPowershell:带有转义参数(--%)的调用运算符(&)不适用于非静态参数
【发布时间】:2014-02-18 15:11:27
【问题描述】:

我的 Powershell 脚本需要使用一组非常复杂的参数调用 EXE。我正在使用 Powershell 3.0,并且必须坚持使用该版本。唉,即使是“魔法”转义运算符 (--%) 也没有帮助我。例如,使用 Call 运算符,考虑如下:

& other.exe --% action /mode fast /path:"location with spaces" /fancyparam { /dothis /dothat:"arg with spaces" } /verbose

现在,如果就这么简单,我的脚本可以很容易地正常工作。但这并不是那么简单。 “other.exe”的参数可能不同,这取决于我脚本前面的用户选择。所以相反,我需要提前建立这些参数,可能是这样的:

$commandArgs = 'action /mode ' + $userMode + ' /path:"location with spaces" /fancyparam { /dothis /dothat:"' + $userArgs + " } /verbose'

因此我会这样调用:

& other.exe --% $commandArgs

...好吧,期望--% 意味着它只是传递$commandArgs 的原始字符串。但是如果没有--%,powershell 会自动引用 $commandArgs 的内容,这确实会弄乱内部引号(更不用说打破 other.exe 首先需要的前面的 'action' 参数)。换句话说,我已经尝试将--% 嵌入到我的 $commandArgs 字符串中,但是在它被解析的时候已经造成了损坏(我认为它甚至不会那样工作)。

请注意,这个示例只占我需要执行的实际命令的 1/4 左右——其中包括更多的用户参数、引号和其他有趣的字符,这些字符会让我匆忙逃离地狱!我也已经在使用 echoargs.exe 工具,这就是我看到我遇到的麻烦的方式。哦,我也需要示例中的所有空格(即大括号字符周围需要空格)。

所以在寻找答案之后,我向你寻求帮助。提前致谢。

【问题讨论】:

    标签: powershell parameters escaping call operator-keyword


    【解决方案1】:

    好的,回答我自己的问题可能很奇怪,但是在昨天又花了一天时间解决这个问题之后,我自己可能已经意识到了答案。至少,这是我发现的有效方法。但是我在这里发帖以获得进一步的反馈,以防我真的在做一些不推荐的事情......使用 Invoke-Expression :-)

    我很早就意识到,你们中的一些人在回复中证实了这一点,--% 阻止了所有进一步的扩展(包括我的 $variables)。我的问题是,在尝试使用呼叫运算符(&) 时,我仍然需要扩展很多东西。如果在使用--% 之前我的命令行已经准备就绪,我的问题就会得到解决,所以我就是这样做的。

    我创建了一个新字符串,由以下内容组成:

    $fullCommand = '& "other.exe" --% ' + $commandArgs
    

    (EXE 路径中实际上有空格,因此是引号。)然后,将其全部构建好(包括需要的--%),我将其作为新脚本调用:

    Invoke-Expression $fullCommand
    

    到目前为止,我的成绩非常好。但到目前为止,我知道在我的搜索中,Invoke-Expression 听起来像是人们不应该使用的坏东西。大家想好了吗?

    【讨论】:

      【解决方案2】:

      --% 的目的是抑制参数处理,因此不会代表 PowerShell 在该参数之后扩展变量。不过,您可以通过使用环境变量来解决此问题:

      $env:UserMode = 'foo'
      $env:UserArgs = 'bar baz'
      
      & other.exe --% action /mode %UserMode% /path:"location with spaces" /fancyparam { /dothis /dothat:"%userArgs%" } /verbose

      【讨论】:

      • 这绝对是一个可行的解决方案,虽然确实需要大量变量“复制”(到环境变量中),随着我的命令行增长可能会变得有点笨拙......?我现在为此添加 +1 投票...:-)(或者,我会投票,但我还没有足够的声誉,哦,好吧)
      【解决方案3】:

      我总是建议人们将命令行参数构建到一个变量中,然后将该变量传递给Start-Process cmdlet 的-ArgumentList 参数。

      $Program = '{0}\other.exe' -f $PSScriptRoot;
      $UserMode = 'fast';
      $Path = 'c:\location with\spaces';
      $ArgWithSpaces = 'arg with spaces';
      $ArgumentList = 'action /mode {0} /path:"{1}" /fancyparam { /dothis /dothat:"{2}" } /verbose' -f $UserMode, $Path, $ArgWithSpaces;
      
      $Output = '{0}\{1}.log' -f $env:Temp, [System.Guid]::NewGuid().ToString();
      Start-Process -Wait -FilePath $Program -ArgumentList $ArgumentList -RedirectStandardOutput $Output;
      

      【讨论】:

      • 嗯,这比我想的要复杂一些。 :-)
      • 一旦你真正理解并习惯它,它实际上更容易。我还加入了 .NET 字符串格式的概念,这不是必需的,但使编译参数更加模块化。
      • 这是否按预期工作? -ArgumentList 参数应该是一个字符串数组,但您只给了它一个字符串,因此 $ArgumentList 中的整个字符串应该作为第一个参数传递。
      • @poizan42 是的,它工作得很好。自己试一试。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-04
      • 2016-01-16
      • 1970-01-01
      • 2021-06-30
      • 1970-01-01
      相关资源
      最近更新 更多