【问题标题】:Powershell Command Processing (Passing in Variables)Powershell命令处理(传入变量)
【发布时间】:2010-10-23 00:00:06
【问题描述】:

我正在创建一个 Powershell 脚本来部署一些代码,其中一部分过程是调用一个名为 RAR.EXE 的命令行压缩工具来备份一些文件夹。

我正在尝试动态构建参数,然后让 powershell 使用变量调用命令,但我遇到了麻烦。它不工作...

运行以下脚本,您应该会看到我在说什么。作为变量传入的参数正在被破坏。如果我传递整个命令 + 参数,我会收到臭名昭著的“不被识别为 cmdlet...”消息。

感谢您的帮助!

echo "this should succeed"
& cmd /c echo foo

echo "why does this echo out an additional double quote?"
$param = "/c echo foo"
& cmd "$param"

echo "this does the same"
$param = "/c echo foo"
& cmd $param

echo "escaping the slash doesn't work either..."
$param = "`/c echo foo"
& cmd $param

echo "this fails, but why?"
$cmd = "cmd /c echo foo"
&$cmd

【问题讨论】:

    标签: command-line powershell parameters arguments command


    【解决方案1】:

    在这种情况下,调用运算符“&”是不必要的。它用于在新范围内调用命令。这通常用于调用由字符串或脚本块指定的命令。它还有一个附带的好处是,在命令完成并且范围消失后,在 PowerShell 脚本中创建的任何变量都会被丢弃。

    但是,由于 cmd 是一个 EXE,它在完全不同的过程中执行。 FWIW,您可以直接从 cmd.exe 获得类似的输出:

    > cmd "/c echo foo"
    foo"
    

    所以最后的额外引号是一个 cmd.exe 问题。通常,当 PowerShell 进行解析以调用命令时,您需要将命令与参数分开,例如

    45> & { $foo = "foo" }
    46> $foo  # Note that $foo wasn't found - it went away with the scope
    47> . { $foo = "foo" } # dotting executes in the current scope
    48> $foo 
    foo
    

    这里值得注意的例外是 Invoke-Expression 的行为类似于“评估此字符串”函数。小心使用,尤其是如果用户提供了字符串。如果他们提供“ri C:\ -r”,你的日子会很糟糕。

    在这种情况下,正如其他人所建议的那样,我会将 /c 从字符串 $param 字符串中提取出来并指定它,例如:

    cmd /c $param
    

    或者使用 Invoke-Expression 但要小心使用。顺便说一句,当您尝试调试从 PowerShell 向 EXE 发送参数的问题时,请查看 PowerShell 社区扩展 (http://pscx.codeplex.com) 中的 echoargs 实用程序。非常方便:

    49> $param = "/c echo foo"
    50> echoargs $param
    Arg 0 is </c echo foo>
    

    这表明 cmd.exe 接收“/c echo foo”作为单个参数。 “/c”应该是与“echo foo”(要执行的命令)分开的参数。

    【讨论】:

    • 数组也适用于构建命令行参数;即 $cmdArgs = @('/c','echo foo'); cmd $cmdArgs
    【解决方案2】:

    过去,在尝试像您尝试的那样调用可执行类型命令时,我遇到了 & 调用运算符的问题。不知道我明白为什么。然而,Invoke-Expression 似乎总是在这种情况下工作:

    PS C:\> $cmd = "cmd /c echo foo"
    PS C:\> Invoke-expression $cmd
    foo
    

    【讨论】:

      【解决方案3】:

      我发现的另一种方法是为命令行创建一个参数数组,并将其与 apersand & 调用运算符一起使用。像这样的:

      $exe = "cmd";
      [Array]$params = "/c", "echo", "foo";
      
      & $exe $params;
      

      对我来说效果很好。

      我最初在这里发现了这种技术: http://techstumbler.blogspot.com/2009/12/windows-commands-with-arguments-in.html

      【讨论】:

        【解决方案4】:

        您的最后一个示例如果失败,因为“&”将字符串视为一个参数,因此它正在寻找一个名为“cmd /c echo foo.exe”的程序。 :)

        这行得通:

        & $cmd $params
        

        至于双引号问题,似乎 cmd 不喜欢 PowerShell 放置的参数周围的引号。它得到了这个:

        cmd "/c echo foo"
        

        所以我认为它将 /c 之后的所有内容都视为确切的命令,就像这样:

        echo foo"
        

        一些命令行程序和时髦的命令行解析(这就是 PowerShell 接管函数和 cmdlet 的这项工作的原因)。在 cmd 的情况下,我建议这样做:

        $param = "echo foo"
        & cmd /c $param
        

        【讨论】:

          【解决方案5】:

          我认为这是使用 cmd /c 的产物。运行

          $param = "echo foo"
          cmd /c $param
          

          工作正常。除非您有真实的代码示例,否则很难排除故障。

          【讨论】:

            【解决方案6】:

            当参数包含在字符串中时,它们的处理方式不同:

            PS D:\> echo "1 2 3"
            1 2 3
            PS D:\> echo 1 2 3
            1
            2
            3
            

            当您为 args 使用变量时会出现相同的结果:

            PS D:\> $param = "1 2 3"
            PS D:\> echo $param
            1 2 3
            

            解决方案是使用数组:

            PS D:\> $param = @(1,2,3)
            PS D:\> echo $param
            1
            2
            3
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-01-16
              • 1970-01-01
              • 2018-10-31
              • 1970-01-01
              • 2019-11-15
              • 1970-01-01
              • 2012-11-07
              • 2020-09-08
              相关资源
              最近更新 更多