2025-04-17 05:00:02

MSBuild路径

如何以编程方式从正在运行.exe的机器获取到MSBuild的路径?

我可以从环境中获得。net版本,但是是否有一种方法可以获得。net版本的正确文件夹?


当前回答

您可能认为这里没有太多需要添加的内容,但也许现在是时候在所有版本中使用统一的方式来执行此操作了。我将注册表查询方法(VS2015及以下)与vwhere (VS2017及以上)的使用结合起来,得出了这样的结果:

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
}

其他回答

您可能认为这里没有太多需要添加的内容,但也许现在是时候在所有版本中使用统一的方式来执行此操作了。我将注册表查询方法(VS2015及以下)与vwhere (VS2017及以上)的使用结合起来,得出了这样的结果:

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
}

你也可以把MSBuild.exe的路径打印到命令行:

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

有很多正确答案。然而,这里是我在PowerShell中使用的一行程序来确定最新版本的MSBuild路径:

Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\' | 
    Get-ItemProperty -Name MSBuildToolsPath | 
    Sort-Object PSChildName | 
    Select-Object -ExpandProperty MSBuildToolsPath -first 1

对于Windows 7中的cmd shell脚本,我在批处理文件中使用以下片段来查找. net Framework版本4中的MSBuild.exe。我假设版本4存在,但不假设是子版本。这不是完全通用的,但对于快速脚本来说可能是有帮助的:

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

对于我的使用,我退出批处理文件的错误,如果这不起作用:

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

这个powershell方法从多个源获取msBuild的路径。按顺序尝试:

首先使用vwhere(因为Visual Studio似乎有更多最新版本的msBuild)。 C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\MSBuild.exe 如果没有发现尝试注册表(框架版本)。 C:\Windows\ Microsoft.NET \ Framework64 \ v4.0.30319 \ msbuild.exe

Powershell代码:

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://stackoverflow.com/a/57214958/146513
        $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
}