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?
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?
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.
reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0" /v MSBuildToolsPath
dir HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\
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
/reg:32
or /reg:64
on both bitnessess of cmd
(or whatever process you are running) to explicitly get that path. –
Calliecalligraphy Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\MSBuild\ToolsVersions\4.0\MSBuildToolsPath
–
Sudbury Instructions for finding MSBuild:
&"${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe
"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe
Instructions for finding VSTest:
&"${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
"%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.
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 vswhere.exe
and use it directly. –
Amparoampelopsis VSSetup
cmdlet to simplify, github.com/microsoft/vssetup.powershell –
Origan 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
$dotNetVersion
12.0 (vs 2013) and 14.0 (vs 2015) (if installed of course) –
Normi HKLM:\software\Microsoft\MSBuild\ToolsVersions
key. Instead you need to get the VS2017 install dir from HKLM:\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7\15.0
, then append MSBuild\15.0\Bin\MSBuild.exe
to get the MSBuild EXE location. –
Amparoampelopsis 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
set bb.build.msbuild.exe=
for? Is it required or just an artifact of your setup? –
Supat You can use this very trial PowerShell Command to get the MSBuildToolsPath
from the registry.
Resolve-Path HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\* |
Get-ItemProperty -Name MSBuildToolsPath
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
Resolve-Path "C:\Program Files (x86)\MSBuild\*\Bin\amd64\MSBuild.exe"
Resolve-Path "C:\Program Files (x86)\MSBuild\*\Bin\MSBuild.exe"
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
powershell Resolve-Path 'C:\Program Files*\Microsoft Visual Studio\*\Professional\Msbuild\Current\bin\MSBuild.exe'
–
Archibald @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
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
}
vswhere -products *
, as specified in github.com/Microsoft/vswhere/wiki/Find-MSBuild. –
Lichtenfeld 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:
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.
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 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
easiest way might be to open PowerShell and enter
dir HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\
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)
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)
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 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
-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 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:
This powershell method gets the path to msBuild from multiple sources. Trying in order:
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
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
}
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).
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
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
}
vswhere
or how to acquire it, so this isn't a complete answer. –
Origan 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.
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/
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;
}
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.
© 2022 - 2024 — McMap. All rights reserved.