Path to MSBuild
Asked Answered
T

23

218

How can I programatically get the path to MSBuild from a machine where my .exe is running?

I can get the .NET version from the Environment but is there a way of getting the correct folder for a .NET version?

Touristy answered 29/11, 2008 at 21:12 Comment(0)
B
162

Poking around the registry, it looks like

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\2.0
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\3.5
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0

may be what you're after; fire up regedit.exe and have a look.

Query via command line (per Nikolay Botev)

reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0" /v MSBuildToolsPath

Query via PowerShell (per MovGP0)

dir HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\
Bresnahan answered 29/11, 2008 at 22:59 Comment(8)
I have installed Visual Studio 2017 RC and starting the Developer Command Prompt, the MSBuild version is 15.+, but this version doesn't show in the registry. How do I get access to the same MSBuild that the Dev Cmd Prompt is using?Breakwater
MSBuild 15 is located at `C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\amd64`Automata
Only if you installed VS2017 there, I couldn't find a single entry point in the registry for MsBuildToolsPath for the 15.0 toolsetCucullate
As per David Moore on developercommunity.visualstudio.com/content/problem/2813/… there is a way through the registry : HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7 for base VS2017 installation pathCucullate
learn.microsoft.com/en-us/visualstudio/msbuild/… "MSBuild is now installed in a folder under each version of Visual Studio. For example, C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild" and "ToolsVersion values are no longer set in the registry"Islas
@Hulvej: So, what's the solution? How can external build scripts find MSBuild?Oilskin
I guess, either ensure that msbuild is set in the $PATH or knowing what version of MS build tools in installed. Or use Docker :)Islas
@O.R.Mapper Microsoft offers a project on GitHub for determining paths of Visual Studio 2017/msbuild 15.x instances. It is a single executable which can be used by your build software/scripts.Fourfold
H
146

You can also print the path of MSBuild.exe to the command line:

reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0" /v MSBuildToolsPath
Hemistich answered 16/3, 2013 at 7:13 Comment(4)
Please note that if you want to build a windows phone app, that needs the 32 bits msbuild. Querying the registry gives only the 64 bit msbuild on a 64 bit machine.Antitank
@VictorIonescu: You can use /reg:32 or /reg:64 on both bitnessess of cmd (or whatever process you are running) to explicitly get that path.Calliecalligraphy
this will give you the path to an old (4.0) location - the one you probably want is actually elsewhere see #32008371Softcover
In my case it was under Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\MSBuild\ToolsVersions\4.0\MSBuildToolsPathSudbury
A
88

Instructions for finding MSBuild:

  • PowerShell: &"${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe
  • CMD: "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe

Instructions for finding VSTest:

  • PowerShell: &"${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.PackageGroup.TestTools.Core -find Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe
  • CMD: "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.PackageGroup.TestTools.Core -find Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe

(Note that the instructions above are slightly modified from Microsoft's official ones. In particular, I've included the -prerelease flag to allow Preview and RC installations to be picked up, and the -products * to detect Visual Studio Build Tools installations. Configure as required by your use case.)


It only took over two years but finally in 2019, Microsoft has listened and given us a way to find these vital executables! If you have Visual Studio 2017 or newer installed, the vswhere utility can be queried for the location of MSBuild et al. Since vswhere is guaranteed by Microsoft to be located at %ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe, there is no bootstrapping, no path hardcoding, and no registry probing required any more.

The magic is the -find parameter, added in version 2.6.2. You can determine the version you have installed by running vswhere, or checking its file properties. If you have an older version, you can simply download the latest one and overwrite the existing %ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe.

vswhere.exe is a standalone executable, so you can download and run it from anywhere you have an internet connection. That means your build scripts can check if the environment they're running on is setup correctly, to name one option.

If you have Chocolatey installed, you can also use the relevant vswhere package.

Amparoampelopsis answered 15/11, 2018 at 12:39 Comment(7)
There are already 3 answers that mention vswhere, including your comment to that effect under one of them. Adding this answer just makes the answer soup worse.Miun
4 now. I found this answer helpful, whereas I did not find the other vswhere answers helpful.Mudguard
Worth noting that just because VSWHERE says that is the msbuild.exe to use, it does not mean that if you type msbuild at the command line (especially the Visual Studio command line if using that), that is the one that will get used. To see what gets used if you type msbuild at the command line, do this: where msbuild. If that's not reporting the same as VSWHERE says the latest and greatest is, then either you have to do a full path to the msbuild.exe you want to use, or make adjustments to your PATH variables to suit.Crocodile
So the next question is how do you find the path to vswhere....Imprudent
@Imprudent Microsoft guarantees that it will always be at "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe". That's your starting point. Alternatively, as noted in the last 2 paragraphs, you can download vswhere.exe and use it directly.Amparoampelopsis
it picks up only BuildTools MSBuild in my case (i.e. not those ones installed with a full Visual Studio)Hearts
The PowerShell version should use VSSetup cmdlet to simplify, github.com/microsoft/vssetup.powershellOrigan
S
37

If you want to use MSBuild for .Net 4 then you can use the following PowerShell command to get the executable's path. If you want version 2.0 or 3.5 then just change the $dotNetVersion variable.

To run the executable you'll need to prepend the $msbuild variable with &. That will execute the variable.

# valid versions are [2.0, 3.5, 4.0]
$dotNetVersion = "4.0"
$regKey = "HKLM:\software\Microsoft\MSBuild\ToolsVersions\$dotNetVersion"
$regProperty = "MSBuildToolsPath"

$msbuildExe = join-path -path (Get-ItemProperty $regKey).$regProperty -childpath "msbuild.exe"

&$msbuildExe
Stupefaction answered 20/11, 2012 at 17:32 Comment(2)
works also for $dotNetVersion 12.0 (vs 2013) and 14.0 (vs 2015) (if installed of course)Normi
Does not work for VS 2017, which does not add a value under the HKLM:\software\Microsoft\MSBuild\ToolsVersions key. Instead you need to get the VS2017 install dir from HKLM:\SOFTWARE\WOW6432Node\Microsoft\VisualStud‌​io\SxS\VS7\15.0, then append MSBuild\15.0\Bin\MSBuild.exe to get the MSBuild EXE location.Amparoampelopsis
D
31

For cmd shell scripting in Windows 7, I use the following fragment in my batch file to find MSBuild.exe in the .NET Framework version 4. I assume version 4 is present, but don't assume the sub-version. This isn't totally general-purpose, but for quick scripts it may be helpful:

set msbuild.exe=
for /D %%D in (%SYSTEMROOT%\Microsoft.NET\Framework\v4*) do set msbuild.exe=%%D\MSBuild.exe

For my uses I'm exiting the batch file with an error if that didn't work:

if not defined msbuild.exe echo error: can't find MSBuild.exe & goto :eof
if not exist "%msbuild.exe%" echo error: %msbuild.exe%: not found & goto :eof
Dasteel answered 6/12, 2012 at 21:2 Comment(2)
@Dasteel What's set bb.build.msbuild.exe= for? Is it required or just an artifact of your setup?Supat
@Elisée Oops, sorry, that's a copy/paste typo. In my environment I call the variable bb.build.msbuild.exe, I neglected to fix that instance when I pasted into the answer. Fixed now, thanks for pointing that out.Dasteel
L
31

You can use this very trial PowerShell Command to get the MSBuildToolsPath from the registry.

PowerShell (from registry)

Resolve-Path HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\* | 
Get-ItemProperty -Name MSBuildToolsPath

Output

MSBuildToolsPath : C:\Program Files (x86)\MSBuild\12.0\bin\amd64\
PSPath           : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\12.0
PSParentPath     : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions
PSChildName      : 12.0
PSDrive          : HKLM
PSProvider       : Microsoft.PowerShell.Core\Registry

MSBuildToolsPath : C:\Program Files (x86)\MSBuild\14.0\bin\amd64\
PSPath           : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0
PSParentPath     : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions
PSChildName      : 14.0
PSDrive          : HKLM
PSProvider       : Microsoft.PowerShell.Core\Registry

MSBuildToolsPath : C:\Windows\Microsoft.NET\Framework64\v2.0.50727\
PSPath           : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\2.0
PSParentPath     : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions
PSChildName      : 2.0
PSDrive          : HKLM
PSProvider       : Microsoft.PowerShell.Core\Registry

MSBuildToolsPath : C:\Windows\Microsoft.NET\Framework64\v3.5\
PSPath           : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\3.5
PSParentPath     : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions
PSChildName      : 3.5
PSDrive          : HKLM
PSProvider       : Microsoft.PowerShell.Core\Registry

MSBuildToolsPath : C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
PSPath           : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0
PSParentPath     : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions
PSChildName      : 4.0
PSDrive          : HKLM
PSProvider       : Microsoft.PowerShell.Core\Registry

or from the filesystem

PowerShell (from file system)

Resolve-Path "C:\Program Files (x86)\MSBuild\*\Bin\amd64\MSBuild.exe"
Resolve-Path "C:\Program Files (x86)\MSBuild\*\Bin\MSBuild.exe"

Output

Path
----
C:\Program Files (x86)\MSBuild\12.0\Bin\amd64\MSBuild.exe
C:\Program Files (x86)\MSBuild\14.0\Bin\amd64\MSBuild.exe
C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe
C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe
Leporide answered 3/9, 2015 at 8:23 Comment(3)
The best answer on this topic.Ianthe
Unfortunately this is no longer best because newer versions are delivered within VisualStudio and not registered hereOperative
@Leporide Thanks for this answer. If anyone is looking for MSBuild.exe with Visual Studio - this works for VS2019 & VS2022 PowerShell (from file system) powershell Resolve-Path 'C:\Program Files*\Microsoft Visual Studio\*\Professional\Msbuild\Current\bin\MSBuild.exe' Archibald
L
17

@AllenSanborn has a great powershell version, but some folks have a requirement to use only batch scripts for builds.

This is an applied version of what @bono8106 answered.

msbuildpath.bat

@echo off

reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v MSBuildToolsPath > nul 2>&1
if ERRORLEVEL 1 goto MissingMSBuildRegistry

for /f "skip=2 tokens=2,*" %%A in ('reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v MSBuildToolsPath') do SET "MSBUILDDIR=%%B"

IF NOT EXIST "%MSBUILDDIR%" goto MissingMSBuildToolsPath
IF NOT EXIST "%MSBUILDDIR%msbuild.exe" goto MissingMSBuildExe

exit /b 0

goto:eof
::ERRORS
::---------------------
:MissingMSBuildRegistry
echo Cannot obtain path to MSBuild tools from registry
goto:eof
:MissingMSBuildToolsPath
echo The MSBuild tools path from the registry '%MSBUILDDIR%' does not exist
goto:eof
:MissingMSBuildExe
echo The MSBuild executable could not be found at '%MSBUILDDIR%'
goto:eof

build.bat

@echo off
call msbuildpath.bat
"%MSBUILDDIR%msbuild.exe" foo.csproj /p:Configuration=Release

For Visual Studio 2017 / MSBuild 15, Aziz Atif (the guy who wrote Elmah) wrote a batch script

build.cmd Release Foo.csproj

https://github.com/linqpadless/LinqPadless/blob/master/build.cmd

@echo off
setlocal
if "%PROCESSOR_ARCHITECTURE%"=="x86" set PROGRAMS=%ProgramFiles%
if defined ProgramFiles(x86) set PROGRAMS=%ProgramFiles(x86)%
for %%e in (Community Professional Enterprise) do (
    if exist "%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe" (
        set "MSBUILD=%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe"
    )
)
if exist "%MSBUILD%" goto :restore
set MSBUILD=
for %%i in (MSBuild.exe) do set MSBUILD=%%~dpnx$PATH:i
if not defined MSBUILD goto :nomsbuild
set MSBUILD_VERSION_MAJOR=
set MSBUILD_VERSION_MINOR=
for /f "delims=. tokens=1,2,3,4" %%m in ('msbuild /version /nologo') do (
    set MSBUILD_VERSION_MAJOR=%%m
    set MSBUILD_VERSION_MINOR=%%n
)
if not defined MSBUILD_VERSION_MAJOR goto :nomsbuild
if not defined MSBUILD_VERSION_MINOR goto :nomsbuild
if %MSBUILD_VERSION_MAJOR% lss 15    goto :nomsbuild
if %MSBUILD_VERSION_MINOR% lss 1     goto :nomsbuild
:restore
for %%i in (NuGet.exe) do set nuget=%%~dpnx$PATH:i
if "%nuget%"=="" (
    echo WARNING! NuGet executable not found in PATH so build may fail!
    echo For more on NuGet, see https://github.com/nuget/home
)
pushd "%~dp0"
nuget restore ^
 && call :build Debug   %* ^
 && call :build Release %*
popd
goto :EOF

:build
setlocal
"%MSBUILD%" /p:Configuration=%1 /v:m %2 %3 %4 %5 %6 %7 %8 %9
goto :EOF

:nomsbuild
echo Microsoft Build version 15.1 (or later) does not appear to be
echo installed on this machine, which is required to build the solution.
exit /b 1
Looming answered 6/12, 2013 at 19:27 Comment(3)
Note: Since VS2017/msbuild 15.x doesn't use the registry for their paths, vswhere is an alternative to determine the msbuild path.Fourfold
Also, AzizAtif is the man. Take a gander at this for 15.1 builds - github.com/linqpadless/LinqPadless/blob/master/build.cmdLooming
Also, vswhere can be installed via Chocolatey: chocolatey.org/packages/vswhereMudguard
C
8

This works for Visual Studio 2015 and 2017:

function Get-MSBuild-Path {

    $vs14key = "HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0"
    $vs15key = "HKLM:\SOFTWARE\wow6432node\Microsoft\VisualStudio\SxS\VS7"

    $msbuildPath = ""

    if (Test-Path $vs14key) {
        $key = Get-ItemProperty $vs14key
        $subkey = $key.MSBuildToolsPath
        if ($subkey) {
            $msbuildPath = Join-Path $subkey "msbuild.exe"
        }
    }

    if (Test-Path $vs15key) {
        $key = Get-ItemProperty $vs15key
        $subkey = $key."15.0"
        if ($subkey) {
            $msbuildPath = Join-Path $subkey "MSBuild\15.0\bin\amd64\msbuild.exe"
        }
    }

    return $msbuildPath

}
Contentious answered 26/4, 2017 at 0:50 Comment(4)
For VS2017, see also: github.com/Microsoft/vswhere, github.com/Microsoft/vssetup.powershell, and github.com/deadlydog/Invoke-MsBuildAmparoampelopsis
For Build Tools, use vswhere -products *, as specified in github.com/Microsoft/vswhere/wiki/Find-MSBuild.Lichtenfeld
For vswhere you should know the path where it is located. And of course you should have power-shell available for your build system. Just one question: why amd64? Does it have anything specific for building?Yokel
Upvoted because this solution essentially just uses a registry key for MSBuild 15 too, not a third party library or script. Out of curiosity, what does "SxS\VS7" refer to? Will that stay valid across VS versions?Mehalick
R
7

An one-liner based on @dh_cgn's answer:

(Resolve-Path ([io.path]::combine(${env:ProgramFiles(x86)}, 'Microsoft Visual Studio', '*', '*', 'MSBuild', '*' , 'bin' , 'msbuild.exe'))).Path

It selects all existing paths paths of eg. C:\Program Files (x86)\Microsoft Visual Studio\*\*\MSBuild\*\bin\msbuild.exe.

The wildcards stars are:

  • the year (2017)
  • the visual studio edition (community, professional, enterprise)
  • the tools version (15.0)

Be aware that this command is selecting the first path that matches the expression ordered by alphabet. To narrow it down just replace the wildcards with specific elements eg. the year or tools version.

Redfin answered 1/11, 2018 at 1:21 Comment(1)
Add amd64 to find the 64-bit ones: ``` (Resolve-Path ([io.path]::combine(${env:ProgramFiles(x86)}, 'Microsoft Visual Studio', '', '', 'MSBuild', '*' , 'bin' , 'amd64', 'msbuild.exe'))).Path ```Demission
F
5

The Registry locations

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\2.0
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\3.5

give the location for the executable.

But if you need the location where to save the Task extensions, it's on

%ProgramFiles%\MSBuild
Frosting answered 8/12, 2008 at 19:8 Comment(1)
It's pretty old, I know - but anyway: on x64-Systems, the MSBuild-Folder is located in ProgramFiles(x86)Holism
W
4

easiest way might be to open PowerShell and enter

dir HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\
Whicker answered 14/7, 2015 at 10:33 Comment(0)
V
4

On Windows 2003 and later, type this command in cmd:

cmd> where MSBuild
Sample result: C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe

If nothing appears, it means that .NET framework is not included in the system PATH. The MSBuild should be in the .NET installation folder, along with .NET compilers (vbc.exe, csc.exe)

Veron answered 9/9, 2015 at 13:20 Comment(1)
This answer doesn't add much over other answers. It's less robust than this answerMiun
M
4

Starting with MSBuild 2017 (v15), MSBuild is now installed in a folder under each version of Visual Studio

Here are some examples of where MSBuild.exe is found on my machine:

C:\windows\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe  (v2.0.50727.8745  32-bit)
C:\windows\Microsoft.NET\Framework64\v2.0.50727\MSBuild.exe  (v2.0.50727.8745  64-bit)
C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe  (v3.5.30729.8763 32-bit)
C:\Windows\Microsoft.NET\Framework64\v3.5\MSBuild.exe  (v3.5.30729.8763 64-bit)
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe  (v4.7.2053.0 32-bit)
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe  (v4.7.2053.0 64-bit)
C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe  (v12.0.21005.1 32-bit)
C:\Program Files (x86)\MSBuild\12.0\Bin\amd64\MSBuild.exe (v12.0.21005.1 64-bit)
C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe  (v14.0.25420.1 32-bit)
C:\Program Files (x86)\MSBuild\14.0\Bin\amd64\MSBuild.exe  (v14.0.25420.1 64-bit)
C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe  (v15.1.1012+g251a9aec17 32-bit)
C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\amd64\MSBuild.exe (v15.1.1012+g251a9aec17 64-bit)
C:\Program Files (x86)\Microsoft Visual Studio\2017\{LicenceName}\MSBuild\Bin\MSBuild.exe (v15.1.1012.6693 32-bit)
C:\Program Files (x86)\Microsoft Visual Studio\2017\{LicenceName}\MSBuild\Bin\amd64\MSBuild.exe (v15.1.1012.6693 64-bit)
Mudguard answered 18/8, 2017 at 20:1 Comment(2)
According to a previous answer, 2017 does in fact store this information in the registry.Miun
Tools like vswhere and VSSetup were created along with VS2017 to assist locating MSBuild, so even in year 2017 this isn't a good enough answer.Origan
P
3

There are many correct answers. However, here a One-Liner in PowerShell I use to determine the MSBuild path for the most recent version:

Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\' | 
    Get-ItemProperty -Name MSBuildToolsPath | 
    Sort-Object PSChildName | 
    Select-Object -ExpandProperty MSBuildToolsPath -first 1
Pointer answered 26/7, 2019 at 7:17 Comment(1)
+1 Really useful! But in my answer I use -last 1 (instead of -first 1 in order to get the latest version) and also concatenate the file name (to properly get the full path and not only the folder).Eleanoraeleanore
F
2

To retrieve path of msbuild 15 (Visual Studio 2017) with batch from registry w/o additional tools:

set regKey=HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7
set regValue=15.0
for /f "skip=2 tokens=3,*" %%A in ('reg.exe query %regKey% /v %regValue% 2^>nul') do (
    set vs17path=%%A %%B
)
set msbuild15path = %vs17path%\MSBuild\15.0\Bin\MSBuild.exe

Better available tools:

Fourfold answered 22/12, 2017 at 14:10 Comment(5)
you saved my lifeStranger
There is already a PowerShell version of this. Circa 2017, is there any reason to avoid learning Powershell?Miun
@Miun Not every build system has PowerShell available.Fourfold
Every supported Windows release in 2017 has PowerShell preinstalled, so "Not every build system has PowerShell available" isn't true.Origan
PowerShell may be installed, but restricted. You may need to run: "powershell.exe -Command Set-ExecutionPolicy -ExecutionPolicy RemoteSigned" for anything more than a one-liner. Do I really have to wrap every ps script in a cmd to Set-ExecutionPolicy, just in case? Or maybe I just don't understand PS.Leitman
E
1

This powershell method gets the path to msBuild from multiple sources. Trying in order:

  1. First using vswhere (because Visual Studio seems to have more up to date versions of msBuild) e.g.

    C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\MSBuild.exe
    
  2. If not found trying the registry (framework version) e.g.

    C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe
    

Powershell code:

Function GetMsBuildPath {

    Function GetMsBuildPathFromVswhere {
        # Based on https://github.com/microsoft/vswhere/wiki/Find-MSBuild/62adac8eb22431fa91d94e03503d76d48a74939c
        $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
        $path = & $vswhere -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath
        if ($path) {
            $tool = join-path $path 'MSBuild\Current\Bin\MSBuild.exe'
            if (test-path $tool) {
                return $tool
            }
            $tool = join-path $path 'MSBuild\15.0\Bin\MSBuild.exe'
            if (test-path $tool) {
                return $tool
            }
        }
    }

    Function GetMsBuildPathFromRegistry {
        # Based on Martin Brandl's answer: https://mcmap.net/q/104695/-path-to-msbuild
        $msBuildDir = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\' |
            Get-ItemProperty -Name MSBuildToolsPath |
            Sort-Object PSChildName |
            Select-Object -ExpandProperty MSBuildToolsPath -last 1
        $msBuildPath = join-path $msBuildDir 'msbuild.exe'
        if (test-path $msBuildPath) {
            return $msBuildPath
        }
    }

    $msBuildPath = GetMsBuildPathFromVswhere
    if (-Not $msBuildPath) {
        $msBuildPath = GetMsBuildPathFromRegistry
    }
    return $msBuildPath
}
Eleanoraeleanore answered 13/9, 2019 at 21:52 Comment(0)
T
0

For Visual Studio 2017 without knowing the exact edition you could use this in a batch script:

FOR /F "tokens=* USEBACKQ" %%F IN (`where /r "%PROGRAMFILES(x86)%\Microsoft Visual 
Studio\2017" msbuild.exe ^| findstr /v /i "amd64"`) DO (SET msbuildpath=%%F)

The findstr command is to ignore certain msbuild executables (in this example the amd64).

Terris answered 14/11, 2018 at 8:54 Comment(0)
E
0

add vswhere branch for https://github.com/linqpadless/LinqPadless/blob/master/build.cmd, works fine in my computer, and the vswhere branch works on my mate's computer. May be, the vswhere branch should move forward as the first check.

@echo off
setlocal
if "%PROCESSOR_ARCHITECTURE%"=="x86" set PROGRAMS=%ProgramFiles%
if defined ProgramFiles(x86) set PROGRAMS=%ProgramFiles(x86)%
for %%e in (Community Professional Enterprise) do (
    if exist "%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe" (
        set "MSBUILD=%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe"
    )
)
if exist "%MSBUILD%" goto :build

for /f "usebackq tokens=1* delims=: " %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.Component.MSBuild`) do (
  if /i "%%i"=="installationPath" set InstallDir=%%j
)

if exist "%InstallDir%\MSBuild\15.0\Bin\MSBuild.exe" (
  set "MSBUILD=%InstallDir%\MSBuild\15.0\Bin\MSBuild.exe"
)
if exist "%MSBUILD%" goto :build
set MSBUILD=
for %%i in (MSBuild.exe) do set MSBUILD=%%~dpnx$PATH:i
if not defined MSBUILD goto :nomsbuild
set MSBUILD_VERSION_MAJOR=
set MSBUILD_VERSION_MINOR=
for /f "delims=. tokens=1,2,3,4" %%m in ('msbuild /version /nologo') do (
    set MSBUILD_VERSION_MAJOR=%%m
    set MSBUILD_VERSION_MINOR=%%n
)
echo %MSBUILD_VERSION_MAJOR% %MSBUILD_VERSION_MINOR%
if not defined MSBUILD_VERSION_MAJOR goto :nomsbuild
if not defined MSBUILD_VERSION_MINOR goto :nomsbuild
if %MSBUILD_VERSION_MAJOR% lss 15    goto :nomsbuild
if %MSBUILD_VERSION_MINOR% lss 1     goto :nomsbuild
:restore
for %%i in (NuGet.exe) do set nuget=%%~dpnx$PATH:i
if "%nuget%"=="" (
    echo WARNING! NuGet executable not found in PATH so build may fail!
    echo For more on NuGet, see https://github.com/nuget/home
)
pushd "%~dp0"
popd
goto :EOF

:build
setlocal
"%MSBUILD%" -restore -maxcpucount %1 /p:Configuration=%2 /v:m %3 %4 %5 %6 %7 %8 %9
goto :EOF

:nomsbuild
echo Microsoft Build version 15.1 (or later) does not appear to be
echo installed on this machine, which is required to build the solution.
exit /b 1
Elude answered 22/1, 2019 at 1:12 Comment(0)
T
0

You wouldn't think there's much to add here, but perhaps it's time for a unified way of doing this across all versions. I've combined the registry-query approach (VS2015 and below) with use of vswhere (VS2017 and above) to come up with this:

function Find-MsBuild {
    Write-Host "Using VSWhere to find msbuild..."
    $path = & $vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1

    if (!$path) {
        Write-Host "No results from VSWhere, using registry key query to find msbuild (note this will find pre-VS2017 versions)..."
        $path = Resolve-Path HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\* |
                    Get-ItemProperty -Name MSBuildToolsPath |
                    sort -Property @{ Expression={ [double]::Parse($_.PSChildName) }; Descending=$true } |
                    select -exp MSBuildToolsPath -First 1 |
                    Join-Path -ChildPath "msbuild.exe"
    }

    if (!$path) {
        throw "Unable to find path to msbuild.exe"
    }

    if (!(Test-Path $path)) {
        throw "Found path to msbuild as $path, but file does not exist there"
    }

    Write-Host "Using MSBuild at $path..."
    return $path
}
Traveled answered 6/6, 2019 at 9:24 Comment(2)
Compared to other answers, you ignored the path of vswhere or how to acquire it, so this isn't a complete answer.Origan
You're right. I really should complete the spoonfeeding process by including' nugent install Vswhere'Traveled
L
0

My goal is to set the path to MsBuild once as an environment variable, rather than in every script I might write. Sometimes I prefer to not be upgraded tp a new version of a tool, as a result of installing a new version of VS. A one-time script does that. Then I refer to msbuild as

"%MsBuildPath%" arguments here...

In the past I have created a one-line cmd file in my tools folder which is on my path that starts the exe.

"%C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe%" %*

That works but the output may get written to another window, unless you use Start /B

You could also put a symbolic link there. Or you could use pathman to save the parent of the result to the PATH variable.

The advantage of the one-line file is that can be copied by backup or sync tools like dropbox. Symbolic and hard links do not travel across the cloud well.

Building on the better answers that use vswhere, I retrofitted it into a cmd file.

If you know Unix backticks and environment export this will make your eyes hurt, but it is the idiom (idiot?) way Windows forces on you, since PowerShell may be restricted, such as on a build machine:

Rem set MsBuildPath env variable
setx MsBuildPath ""
REM delims=* to avoid parsing spaces filepaths since * is not legal in a filename
FOR /F "usebackq delims=*" %%I IN (
    `"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`
        ) do setx MsBuildPath "%%I"

REM Note "SET MsBuildPath" returns nothing until you open a new cmd/process

Expected output is something like (ignore the SO wrapping):

setx MsBuildPath "C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe"

SUCCESS: Specified value was saved.

I wish

dotnet msbuild

worked on 4.8 and older projects. Someday when I have switched my 150 personal C# projects to Core and SDK projects I will be able to use dotnet msbuild; in others maybe never.

Leitman answered 2/3, 2023 at 5:30 Comment(0)
R
-1

If you are adventurous you can also get the source code and latest release of MsBuild from GitHub now at https://github.com/Microsoft/msbuild/releases/

Rattlesnake answered 18/4, 2019 at 17:44 Comment(2)
Does not answer either of the OP's questionsGrecize
Seems a bit heavy handed when you can create link to MsBuild.exe Or just copy the one of the existing copies to where ever you like, Or just add it to your PATH. (I already have 20 copies of MS spam on a machine I have been using less than 3 months. So this would not be my first choice)Leitman
N
-1

Get latest version of MsBuild. Best way, for all types of msbuild installation, for different processor architecture (Power Shell):

function Get-MsBuild-Path
{
    $msbuildPathes = $null
    $ptrSize = [System.IntPtr]::Size
    switch ($ptrSize) {
        4 {
            $msbuildPathes =
            @(Resolve-Path "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\*\*\MSBuild\*\Bin\msbuild.exe" -ErrorAction SilentlyContinue) +
            @(Resolve-Path "${Env:ProgramFiles(x86)}\MSBuild\*\Bin\MSBuild.exe" -ErrorAction SilentlyContinue) +
            @(Resolve-Path "${Env:windir}\Microsoft.NET\Framework\*\MSBuild.exe" -ErrorAction SilentlyContinue)
        }
        8 {
            $msbuildPathes =
            @(Resolve-Path "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\*\*\MSBuild\*\Bin\amd64\msbuild.exe" -ErrorAction SilentlyContinue) +
            @(Resolve-Path "${Env:ProgramFiles(x86)}\MSBuild\*\Bin\amd64\MSBuild.exe" -ErrorAction SilentlyContinue) +
            @(Resolve-Path "${Env:windir}\Microsoft.NET\Framework64\*\MSBuild.exe" -ErrorAction SilentlyContinue)
        }
        default {
            throw ($msgs.error_unknown_pointersize -f $ptrSize)
        }
    }

    $latestMSBuildPath = $null
    $latestVersion = $null
    foreach ($msbuildFile in $msbuildPathes)
    {
        $msbuildPath = $msbuildFile.Path
        $versionOutput = & $msbuildPath -version
        $fileVersion = (New-Object System.Version($versionOutput[$versionOutput.Length - 1]))
        if (!$latestVersion -or $latestVersion -lt $fileVersion)
        {
            $latestVersion = $fileVersion
            $latestMSBuildPath = $msbuildPath
        }
    }

    Write-Host "MSBuild version detected: $latestVersion" -Foreground Yellow
    Write-Host "MSBuild path: $latestMSBuildPath" -Foreground Yellow

    return $latestMSBuildPath;
}
Nape answered 5/6, 2019 at 7:31 Comment(1)
Clearly this is broken by VS 2022 which is the first x64 build.Origan
B
-2

If You want to compile a Delphi project, look at "ERROR MSB4040 There is no target in the project" when using msbuild+Delphi2009

Correct answer there are said: "There is a batch file called rsvars.bat (search for it in the RAD Studio folder). Call that before calling MSBuild, and it will setup the necessary environment variables. Make sure the folders are correct in rsvars.bat if you have the compiler in a different location to the default."

This bat will not only update the PATH environment variable to proper .NET folder with proper MSBuild.exe version, but also registers other necessary variables.

Belabor answered 15/6, 2017 at 16:18 Comment(2)
That answer is not Delphi-related and not more robust for Delphi users.Belabor
Sorry for being terse. I meant more robust as in, works for more than just Delphi. There might be an easier way to do it in Delphi, but the OP didn't ask about Delphi, and this thread has some 18 answers that few will ever see. If it's important to you that others see this, I'd recommend that you create a new question specific to Delphi, and self-answer. If we got down to 6 or fewer answers that covered every version of MSBuild, I'd be very happyMiun

© 2022 - 2024 — McMap. All rights reserved.