Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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")
like image 567
Milan Gardian Avatar asked Jan 23 '09 06:01

Milan Gardian


People also ask

How do I run MSBuild from command line?

To run MSBuild at a command prompt, pass a project file to MSBuild.exe, together with the appropriate command-line options. Command-line options let you set properties, execute specific targets, and set other options that control the build process.

Where do I find MSBuild path?

For example, the path to MSBuild.exe installed with Visual Studio 2019 Community is C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe You can also use the following PowerShell module to locate MSBuild: vssetup.

How do I run a PowerShell project?

Task Overview Add the Windows PowerShell script to your solution and to source control. Create a command that invokes your Windows PowerShell script. Escape any reserved XML characters in your command. Create a target in your custom MSBuild project file and use the Exec task to run your command.


3 Answers

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
like image 158
Milan Gardian Avatar answered Nov 07 '22 05:11

Milan Gardian


I would very highly suggest looking at PSake.

Let me quote a portion of that page:

Remember that psake is syntactic sugar around PowerShell. So anything you can do in PowerShell, you can do in psake. That means that you can run MSBuild, NAnt, or other scripts. There is no need to completely replace your current build system. You can use psake to automate and extend it!

psake automatically adds the appropriate version of .NET Framework to its path. So you can access MSBuild, csc.exe, vbc.exe, or any other tools installed in $env:windir\Microsoft.NET\Framework\$version\ without the fully qualified path.

like image 24
EBGreen Avatar answered Nov 07 '22 07:11

EBGreen


A different and potentially more usable approach would be to make an msbuild cmdlet. MsBuild has a nice API and there are many samples out there on how to use it from a compiled language such as C#/VB. It would be very easy to build a cmdlet that would provide a much nicer syntax to your powershell scripts.

like image 3
JaredPar Avatar answered Nov 07 '22 05:11

JaredPar