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

问题描述

| 我可以在以下情况下表达自己的需求:编写一个函数,该函数接受要作为本机命令运行的字符串。 这个想法不是太牵强:如果您正在与公司中其他地方的其他命令行实用程序交互,这些实用程序向您提供了逐字运行命令。因为您不控制命令,所以您需要接受任何有效的命令作为输入。这些是我一直无法轻松克服的主要问题: 该命令可能会执行一个程序,该程序位于其中带有空格的路径中:
$command = \'\"C:\\Program Files\\TheProg\\Runit.exe\" Hello\';
该命令的参数中可能带有空格:
$command = \'echo \"Hello World!\"\';
该命令可能同时具有单刻度和双刻度:
$command = \"echo `\"it`\'s`\"\";
有什么干净的方法可以做到这一点吗?我只能设计出繁琐而丑陋的解决方法,但是对于脚本语言,我觉得这应该变得非常简单。     

解决方法

        
Invoke-Expression
,也别名为
iex
。以下将对示例2和示例3起作用:
iex $command
某些字符串无法按原样运行,例如您的示例#1,因为exe用引号引起来。这将按原样工作,因为字符串的内容正是从Powershell命令提示符直接运行它的方式:
$command = \'C:\\somepath\\someexe.exe somearg\'
iex $command
但是,如果该exe用引号引起来,则需要ѭ7的帮助才能使其运行,如本示例所示,从命令行运行:
>> &\"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\"
可能,您可以通过检测命令字符串的第一个字符是否为ѭ10handle来处理几乎所有情况,例如在此简单的实现中:
function myeval($command) {
    if ($command[0] -eq \'\"\') { iex \"& $command\" }
    else { iex $command }
}
但是您可能会发现必须以其他方式调用其他情况。在这种情况下,您可能需要对特定的异常类型/消息使用“ 12”,或者检查命令字符串。 如果您总是收到绝对路径而不是相对路径,那么上面的2种情况下应该没有太多特殊情况。     ,        另请参阅此Microsoft Connect报告,该报告本质上是使用PowerShell运行Shell命令有多困难(噢,具有讽刺意味的)。 http://connect.microsoft.com/PowerShell/feedback/details/376207/ 他们建议使用ѭ13来强制PowerShell停止尝试在右侧解释文本。 例如:
MSBuild /t:Publish --% /p:TargetDatabaseName=\"MyDatabase\";TargetConnectionString=\"Data Source=.\\;Integrated Security=True\" /p:SqlPublishProfilePath=\"Deploy.publish.xml\" Database.sqlproj
    ,        尝试解析注册表中的卸载字符串并执行它们时,可接受的答案对我不起作用。原来我根本不需要打到
Invoke-Expression
。 我终于遇到了这个漂亮的模板,以了解如何执行卸载字符串:
$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运算符。另外,我只是使用了哈希映射,但实际上,您可能想使用数组。 另外,如果您确实安装了同一应用程序的多个版本,则此卸载程序将一次循环浏览所有这些版本,这会使ѭ18感到困惑,所以也是如此。     ,        如果要使用调用运算符,则参数可以是存储在变量中的数组:
$prog = \'c:\\windows\\system32\\cmd.exe\'
$myargs = \'/c\',\'dir\',\'/x\'
& $prog $myargs
调用运算符也可以使用ApplicationInfo对象。
$prog = get-command cmd
$myargs = -split \'/c dir /x\'
& $prog $myargs