如何从字符串执行任意本地命令?

问题描述:

我可以用下面的场景表达我的需要:编写一个函数,接受一个字符串作为本机命令运行。如何从字符串执行任意本地命令?

这并没有太多的想法:如果你与公司其他地方的其他命令行实用程序接口,它提供给你一个命令来运行逐字。由于您不控制命令,您需要接受任何有效命令作为输入。这些是主要的打嗝我一直无法容易地克服:

  1. 该命令可能在路径执行程序与生活在其中的空间:

    $command = '"C:\Program Files\TheProg\Runit.exe" Hello'; 
    
  2. 该命令可以有参数带空格:

    $command = 'echo "hello world!"'; 
    
  3. 该命令可能有单,双刻度:

    $command = "echo `"it`'s`""; 
    

实现这一点的任何干净的方式?我只能设计出奢华和丑陋的解决方法,但对于脚本语言,我觉得这应该是简单的。

Invoke-Expression,也被别名为iex。下面将在你的例子#2,#3的工作:

iex $command 

一些字符串将不会运行原样,比如你的例子#1,因为这个exe是在引号。这将作为-是,因为字符串的内容究竟如何,你会直接从PowerShell命令提示符下运行:

$command = 'C:\somepath\someexe.exe somearg' 
iex $command 

但是,如果这个exe是在引号,你需要的&帮助得到它的运行,如在本例中,从命令行运行:

>> &"C:\Program Files\Some Product\SomeExe.exe" "C:\some other path\file.ext" 

的脚本,然后:

$command = '"C:\Program Files\Some Product\SomeExe.exe" "C:\some other path\file.ext"' 
iex "& $command" 

可能的是,你可以通过处理几乎所有的案例如果检测命令字符串的第一个字符是",就像这个幼稚的做法:

function myeval($command) { 
    if ($command[0] -eq '"') { iex "& $command" } 
    else { iex $command } 
} 

但你可能会发现,在用不同的方式来调用其他一些情况下。在这种情况下,您需要使用try{}catch{},或许用于特定的异常类型/消息,或者检查命令字符串。

如果您始终接收绝对路径而不是相对路径,则不应在上述2之外有许多特殊情况(如果有)。

+2

别名是伟大的。请记住,如果您移动到另一台机器或将该脚本发送给其他别名可能不会设置的其他人。首选PowerShell功能的全名。 – 2011-06-14 01:17:01

+0

@Doug:大部分时间我都是这样做的,或者使用内置的别名(特别是为了简化命令行)。 “eval”的东西是半开玩笑的,因为这就是其他许多脚本语言所称的,这不是我见过的第一个问题,那里有人不知道“invoke-expression”。而OP的情况听起来只是内部脚本。 – 2011-06-14 01:25:35

+0

我试过这个,但它不起作用: $ command ='“C:\ Program Files \ Windows Media Player \ mplayer2.exe”“H:\ Audio \ Music \ Stevie Wonder \ Stevie Wonder - 迷信。 mp3“' – 2011-06-14 04:40:14

当试图解析注册表中的卸载字符串并执行它们时,我接受的答案不适用于我。事实证明,我并不需要致电Invoke-Expression

我终于碰到这个nice template来抓看到如何执行卸载字符串:

$path = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall' 
$app = 'MyApp' 
$apps= @{} 
Get-ChildItem $path | 
    Where-Object -FilterScript {$_.getvalue('DisplayName') -like $app} | 
    ForEach-Object -process {$apps.Set_Item(
     $_.getvalue('UninstallString'), 
     $_.getvalue('DisplayName')) 
    } 

foreach ($uninstall_string in $apps.GetEnumerator()) { 
    $uninstall_app, $uninstall_arg = $uninstall_string.name.split(' ') 
    & $uninstall_app $uninstall_arg 
} 

这对我的作品,即因为$app是在内部应用程序,我知道只会有两个参数。对于更复杂的卸载字符串,您可能需要使用join operator。另外,我只是使用了哈希映射,但实际上,您可能想要使用一个数组。

此外,如果您确实安装了同一应用程序的多个版本,则此卸载程序将一次遍历所有应用程序,这会混淆MsiExec.exe,所以也是如此。

另请参阅此Microsoft Connect报告,本质上讲,blummin如何使用PowerShell运行shell命令非常困难(哦,具有讽刺意味)。

http://connect.microsoft.com/PowerShell/feedback/details/376207/

他们建议使用--%,以此来迫使PowerShell来停止试图解释文本的权利。

例如:

MSBuild /t:Publish --% /p:TargetDatabaseName="MyDatabase";TargetConnectionString="Data Source=.\;Integrated Security=True" /p:SqlPublishProfilePath="Deploy.publish.xml" Database.sqlproj