.net – How to run MSBuild from Powershell without spawning msbuild.exe process

msbuildnetpowershell

I am considering running MSBuild from a Powershell script by tapping directly to the MSBuild assemblies (as opposed to looking up MSBuild install path and starting msbuild.exe as a child process).

Has anyone done this? What would be the simplest, most straightforward way to run the build? Are there any pros/cons to either technique you'd like to point out? (I'm especially interested in any issues that might arise from running msbuild in the same process/appdomain as the rest of the script).

Currently my thinking is something along these lines:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Engine, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
[void][Microsoft.Build.BuildEngine.Engine]::GlobalEngine.BuildProjectFile("path/main.proj")

Best Answer

The simplest embedded-build invocation that worked and produced output was:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Engine, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
$engine = New-Object Microsoft.Build.BuildEngine.Engine
$engine.RegisterLogger((New-Object Microsoft.Build.BuildEngine.ConsoleLogger))
$engine.BuildProjectFile('fullPath\some.proj')

However, it turns out embedding MSBuild directly in Powershell (V1) is problematic:

'MSBUILD : warning MSB4056: The MSBuild engine must be called on
a single-threaded-apartment. Current threading model is "MTA".
Proceeding, but some tasks may not function correctly.'

Why oh why are we still paying COM tax in 2009 while working in a managed environment?

My conclusion is that embedding MSBuild in Powershell (V1) is not a good idea. For reference, I'm also including the process-based approach I ended up using:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Utilities.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
$msbuild = [Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFrameworkFile("msbuild.exe", "VersionLatest")
&$msbuild fullPath\some.proj