你如何从一个string执行一个任意的本地命令?

我可以用下面的场景expression我的需要: 编写一个函数,接受一个string作为本机命令运行。

这并没有太多的想法:如果你与公司其他地方的其他命令行实用程序进行交互,那么它将提供一个命令来逐字运行。 由于您不控制命令,因此您需要接受任何有效的命令作为input 。 这些是我一直无法克服的主要障碍:

  1. 该命令可能会执行一个程序,其中有一个空间的path:

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

     $command = 'echo "hello world!"'; 
  3. 该命令可能有单个和双个ticks:

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

没有干净的方式来完成这个? 我只能devise出奢华而丑陋的解决方法,但对于脚本语言,我觉得这应该是简单的。

Invoke-Expression ,也被称为iex 。 以下将在你的例子#2和#3上工作:

 iex $command 

一些string不会按原样运行,比如您的示例#1,因为exe文件在引号中。 这将按原样工作,因为string的内容正好如何从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" 

可能的话,通过检测命令string的第一个字符是否“可以处理几乎所有的情况" ,就像在这个天真的实现中一样:

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

但是你可能会发现一些其他的情况必须以不同的方式被调用。 在这种情况下,您需要使用try{}catch{} ,也许用于特定的exceptiontypes/消息,或者检查命令string。

如果你总是收到绝对path而不是相对path,那么除了上述2之外,你不应该有许多特殊情况(如果有的话)。

关于本质上的微软连接报告,请看看blummin如何使用PowerShell来运行shell命令(呃,讽刺)。

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

他们build议使用--%作为强制PowerShell停止尝试解释文本的方法。

例如:

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

尝试parsingregistry中的卸载string时,接受的答案不适用于我,并执行它们。 事实certificate,毕竟我并不需要调用Invoke-Expression

我终于遇到了这个很好的模板 ,看看如何执行卸载string:

 $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是一个内部应用程序,我知道只有两个参数。 对于更复杂的卸载string,您可能需要使用连接运算符 。 另外,我只是使用了一个哈希映射,但实际上,你可能想要使用一个数组。

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