我可以用以下场景表达我的需求:编写一个函数,该函数接受要作为本机命令运行的字符串。
这个想法并不太牵强:如果您正在与公司其他地方的其他命令行实用程序交互,这些实用程序为您提供逐字运行的命令。因为您不控制命令,所以您需要接受任何有效的命令作为输入。这些是我无法轻易克服的主要问题:
该命令可能会执行一个包含空格的路径中的程序: $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 在引号中,则需要 &
的帮助才能使其运行,如本例所示,从命令行运行:
>> &"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 之外,您不应该有很多特殊情况(如果有的话)。
另请参阅此 Microsoft Connect 报告,从本质上讲,使用 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
尝试解析注册表以查找卸载字符串并执行它们时,接受的答案对我不起作用。事实证明,我根本不需要调用 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
感到困惑,所以也有。
如果要使用调用运算符,参数可以是存储在变量中的数组:
$prog = 'c:\windows\system32\cmd.exe'
$myargs = '/c','dir','/x'
& $prog $myargs
呼叫运算符也适用于 ApplicationInfo 对象。
$prog = get-command cmd
$myargs = -split '/c dir /x'
& $prog $myargs
& $wsl (-split "--install -d Ubuntu-20.04")
不定期副业成功案例分享
eval
是半开玩笑的,因为许多其他脚本语言都这么称呼它,而且这不是我看到的第一个有人不知道invoke-expression
的问题。而 OP 的案例听起来只是内部脚本。Invoke-Expression "& $command"