Resolve-MSBuild.ps1
<#PSScriptInfo .VERSION 1.2.1 .AUTHOR Roman Kuzmin .COPYRIGHT (c) Roman Kuzmin .TAGS Invoke-Build, MSBuild .GUID 53c01926-4fc5-4cbd-aa46-32e415b2373b .LICENSEURI http://www.apache.org/licenses/LICENSE-2.0 .PROJECTURI https://github.com/nightroman/Invoke-Build #> <# .Synopsis Finds the specified or latest MSBuild. .Description The script finds the path to the specified or latest version of MSBuild. It is designed to work for MSBuild 2.0-15.0 and support future versions. For MSBuild 15.0+ the command uses VSSetup module from PSGallery. If it is not installed then some default locations are checked. Thus, VSSetup module is required for not default installations. MSBuild 15.0+ resolution precedence: Enterprise, Professional, Community, another product. If this is not suitable then use VSSetup module directly. For MSBuild 2.0-14.0 the information is taken from the registry. .Parameter Version Specifies the required MSBuild version. If it is omitted, empty, or * then the command finds and returns the latest installed version path. The optional suffix x86 tells to use 32-bit MSBuild. .Outputs The full path to MSBuild.exe .Example Resolve-MSBuild 15.0 Gets location of MSBuild installed with Visual Studio 2017. .Link https://www.powershellgallery.com/packages/VSSetup #> [CmdletBinding()] param( [string]$Version ) function Get-MSBuild15Path($Bitness) { if ([System.IntPtr]::Size -eq 4 -or $Bitness -eq 'x86') { 'MSBuild\15.0\Bin\MSBuild.exe' } else { 'MSBuild\15.0\Bin\amd64\MSBuild.exe' } } function Get-MSBuild15VSSetup($Bitness, [switch]$Prerelease) { if (!(Get-Module VSSetup -ListAvailable)) {return} Import-Module VSSetup $vs = Get-VSSetupInstance -Prerelease:$Prerelease | Select-VSSetupInstance -Version 15.0 -Require Microsoft.Component.MSBuild -Product * if (!$vs) { if (!$Prerelease) { Get-MSBuild15VSSetup -Bitness:$Bitness -Prerelease } return } $vs = if ($r = $vs | Select-VSSetupInstance -Product Microsoft.VisualStudio.Product.Enterprise) {$r} elseif ($r = $vs | Select-VSSetupInstance -Product Microsoft.VisualStudio.Product.Professional) {$r} elseif ($r = $vs | Select-VSSetupInstance -Product Microsoft.VisualStudio.Product.Community) {$r} else {$vs} Join-Path @($vs)[0].InstallationPath (Get-MSBuild15Path $Bitness) } function Get-MSBuild15Guess($Bitness, [switch]$Prerelease) { $Folder = if ($Prerelease) {'Preview'} else {'2017'} if (!($root = ${env:ProgramFiles(x86)})) {$root = $env:ProgramFiles} if (Test-Path -LiteralPath "$root\Microsoft Visual Studio\$Folder") { $paths = @( foreach($_ in Resolve-Path "$root\Microsoft Visual Studio\$Folder\*\$(Get-MSBuild15Path $Bitness)" -ErrorAction 0) { $_.ProviderPath } ) if ($paths) { if ($r = $paths -like '*\Enterprise\*') {return $r} if ($r = $paths -like '*\Professional\*') {return $r} if ($r = $paths -like '*\Community\*') {return $r} return $paths[0] } } if (!$Prerelease) { Get-MSBuild15Guess -Bitness:$Bitness -Prerelease } } function Get-MSBuild15($Bitness) { if ($path = Get-MSBuild15VSSetup $Bitness) { $path } else { Get-MSBuild15Guess $Bitness } } function Get-MSBuildOldVersion($Version, $Bitness) { if ([System.IntPtr]::Size -eq 8 -and $Bitness -eq 'x86') { $key = "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSBuild\ToolsVersions\$Version" } else { $key = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\$Version" } $rp = [Microsoft.Win32.Registry]::GetValue($key, 'MSBuildToolsPath', '') if ($rp) { Join-Path $rp MSBuild.exe } } function Get-MSBuildOldLatest($Bitness) { $rp = @(Get-ChildItem HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions | Sort-Object {[Version]$_.PSChildName}) if ($rp) { Get-MSBuildOldVersion $rp[-1].PSChildName $Bitness } } $ErrorActionPreference = 1 try { if ($Version -match '^(.*?)(x86)$') { $Version = $matches[1] $Bitness = $matches[2] } else { $Bitness = '' } $v15 = [Version]'15.0' $vMax = [Version]'9999.0' if (!$Version) {$Version = '*'} $vRequired = if ($Version -eq '*') {$vMax} else {[Version]$Version} if ($vRequired -eq $v15) { if ($path = Get-MSBuild15 $Bitness) { return $path } } elseif ($vRequired -lt $v15) { if ($path = Get-MSBuildOldVersion $Version $Bitness) { return $path } } elseif ($vRequired -eq $vMax) { if ($path = Get-MSBuild15 $Bitness) { return $path } if ($path = Get-MSBuildOldLatest $Bitness) { return $path } } throw 'The specified version is not found.' } catch { Write-Error "Cannot resolve MSBuild $Version : $_" } |