正确使用Invoke-Expression?

时间:2009-08-31 03:47:59

标签: powershell scripting

我刚刚在powershell中完成了我的第一个夜间构建脚本(第一个重要的任何脚本,真的)。我似乎有一些工作得很好,如果还没有健壮(我还没有处理过重要的错误检查),但我发现自己陷入Invoke-Expression cmdlet周围的成语,我想知道我是不是正确使用它。

具体来说,我使用一系列变量来构建我将用于构建解决方案的命令行,然后运行解决方案的单元测试。例如:

$tmpDir = "C:\Users\<myuser>\Development\Autobuild"
$solutionPath=$tmpDir+"\MyProj\MyProj.sln"
$devenv="C:\Program Files (x86)\Microsoft Visual Studio 10.0\common7\ide\devenv"
$releaseProfile="Release"
$releaseCommandLine="`"$devenv`" `"$solutionPath`" /build `"$releaseProfile`""

这很好用,$releaseCommandLine包含我想要在执行时执行的命令行。然后我通过这一行执行它:

$output = Invoke-Expression "& $releaseCommandLine"

这是从powershell脚本执行手动构建的命令行的正确方法吗?我最初认为Invoke-Command会做到这一点,但我一定做错了,因为我半小时都无法完成这项工作,而且我几乎立刻就开始工作了。

我在同一个脚本中已经按照相同的模式进行了几次。这是最佳做法吗?

2 个答案:

答案 0 :(得分:10)

对我来说很好看。我唯一要改变的是使用更多的Powershell功能代替脆弱的假设。 E.g:

  • 使用Join-Path代替字符串连接

  • 使用Env:\提供程序查找%programfiles(x86)%目录(或者更好的是,使用HKML:\提供程序查找路径 - 它位于SOFTWARE \ Microsoft \ VisualStudio \ \ INSTALLDIR)

  • 当我必须编写包含文字双引号变量扩展的字符串时,我通常会回到下面的语法。个人偏好,显然。

    '"{0}" "{1}" /build "{2}"' -f $devenv, $solutionPath, $releaseProfile
    

在某些情况下,我倾向于使用Process.Start(),以便我可以捕获标准输出和输出。 stderr独立流(甚至可能以交互方式控制stdin,具体取决于应用程序)。

PS - '&amp;'并非绝对必要。

答案 1 :(得分:10)

我认为没有必要在这里使用Invoke-Expression。我用很多构建脚本完成了这个,它通常看起来像这样:

$vsroot = "$env:ProgramFiles(x86)\Microsoft Visual Studio 9.0"
$devenv = "$vsroot\Common7\IDE\devenv.exe"
$sln = Join-Path <source_root> Source\MyProj\MyProj.sln
& $devenv $sln /build Release

& $devenv $sln /build "Release|Any CPU"

虽然最近我使用devenv.exe(行为不当的插件等)遇到了一些麻烦,所以现在我使用msbuild.exe:

$msbuild = 'C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe'
& $msbuild $sln /p:Configuration=Release

目前MSBuild可以处理C#,VB和C ++(调用vcbuild),但它无法使用setup&amp; amp处理解决方案。其中的部署项目。但是,我发现它比使用devenv.exe更可靠。

顺便说一句,您通常需要在构建脚本中调用其他工具(sn.exe,signtool.exe,mt.exe等),这些工具特定于您要构建的Visual Studio / .NET版本。因此,通常最好以与VS 2008命令提示符相同的方式配置环境变量。安装PowerShell Community Extensions后,您可以在PSCX配置文件头中启用一行以启用.NET 3.5 / VS 2008设置:

$Pscx:Preferences["ImportVisualStudioVars"] = $true