function Find-MSBuild { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [ref]$VCVersion, [Parameter(Mandatory=$true)] $MSToolsVersion, [Parameter(Mandatory=$true)] [ref]$Toolset, [Parameter(Mandatory=$true)] [xml]$configInfo) $msbuildexe="" $VisualStudioVersion=$VCVersion.Value $Toolsetv=$Toolset.Value $WSDK71Set="Windows7.1SDK" Write-Debug "VCVersion=$VCVersionv $env:VisualStudioVersion" [int]$toolsnum=0 # # Determine VisualStudioVersion # if (("$VisualStudioVersion" -eq "") -And ($configInfo -ne $null)) { $VisualStudioVersion=$configInfo.Configuration.vcversion } if ("$VisualStudioVersion" -eq "") { $VisualStudioVersion = $env:VisualStudioVersion # VC11 or later version of C++ command prompt sets this variable } if ("$VisualStudioVersion" -eq "") { if ("${env:WindowsSDKVersionOverride}" -eq "v7.1") { # SDK7.1+ command prompt $VisualStudioVersion = "10.0" } elseif ("${env:VCInstallDir}" -ne "") { # C++ command prompt if ("${env:VCInstallDir}" -match "Visual Studio\s*(\S+)\\VC\\$") { $VisualStudioVersion = $matches[1] } } } $refnum="" # neither C++ nor SDK prompt if ("$VisualStudioVersion" -eq "") { if ((Find-VSDir 15) -ne "") { # VC15 is installed (current official) $VisualStudioVersion = "15.0" } elseif ((Find-VSDir 16) -ne "") { # VC16 is installed $VisualStudioVersion = "16.0" } elseif ((Find-VSDir 17) -ne "") { #VC 17 is installed $VisualStudioVersion = "17.0" } elseif ("${env:VS140COMNTOOLS}" -ne "") { # VC14 is installed $VisualStudioVersion = "14.0" } elseif ("${env:VS120COMNTOOLS}" -ne "") { # VC12 is installed $VisualStudioVersion = "12.0" } elseif ("${env:VS100COMNTOOLS}" -ne "") { # VC10 is installed $VisualStudioVersion = "10.0" } elseif ("${env:VS110COMNTOOLS}" -ne "") { # VC11 is installed $VisualStudioVersion = "11.0" } else { throw "Visual Studio >= 10.0 not found" } } if ([int]::TryParse($VisualStudioVersion, [ref]$refnum)) { $VisualStudioVersion="${refnum}.0" } # Check VisualStudioVersion and prepare for ToolsVersion switch ($VisualStudioVersion) { "10.0" { $toolsout = 4 } "11.0" { $toolsout = 4 } "12.0" { $toolsout = 12 } "14.0" { $toolsout = 14 } "15.0" { $toolsout = 15 } "16.0" { $toolsout = 16 } "17.0" { $toolsout = 17 } default { throw "Selected Visual Studio is Version ${VisualStudioVersion}. Please use VC10 or later"} } # # Determine ToolsVersion # [int]$toolsnum=$toolsout if ("$MSToolsVersion" -eq "") { $MSToolsVersion=$env:ToolsVersion } if ("$MSToolsVersion" -ne "") { if ([int]::TryParse($MSToolsVersion, [ref]$refnum)) { $toolsout=[int]$refnum } } if ($toolsnum -lt 12) { $toolsnum=$toolsout } # # Determine MSBuild executable # Write-Debug "ToolsVersion=$MSToolsVersion VisualStudioVersion=$VisualStudioVersion" try { $msbver = msbuild.exe /ver /nologo if ("$msbver" -match "^(\d+)\.(\d+)") { $major1 = [int] $matches[1] $minor1 = [int] $matches[2] if ($MSToolsVersion -match "^(\d+)\.(\d+)") { $bavail = $false $major2 = [int] $matches[1] $minor2 = [int] $matches[2] if ($major1 -gt $major2) { Write-Debug "$major1 > $major2" $bavail = $true } elseif ($major1 -eq $major2 -And $minor1 -ge $minor2) { Write-Debug "($major1, $minor1) >= ($major2, $minor2)" $bavail = $true } if ($bavail) { $msbuildexe = "MSBuild" } } } } catch {} if ("$msbuildexe" -eq "") { Write-Debug "tools version $toolsnum" if ($toolsnum -gt 14) { # VC15 ~ VC?? $msbuildexe = msbfind_15_xx $toolsnum } else { # VC10 ~ VC14 $msbuildexe = msbfind_10_14 "${toolsnum}.0" if ($toolsnum -eq 4) { if ((Find-VSDir $VisualStudioVersion) -eq "") { throw "MSBuild ${toolsnum}.0 found but VisualStudioVersion $VisualStudioVersion not Found" } } } if ("$msbuildexe" -eq "") { throw "MSBuild ToolsVersion ${toolsnum}.0 not Found" } } # # Determine PlatformToolset # if (("$Toolsetv" -eq "") -And ($configInfo -ne $null)) { $Toolsetv=$configInfo.Configuration.toolset } if ("$Toolsetv" -eq "") { $Toolsetv=$env:PlatformToolset } if ("$Toolsetv" -eq "") { switch ($VisualStudioVersion) { "10.0" { if (Test-path "HKLM:\Software\Microsoft\Microsoft SDKs\Windows\v7.1") { $Toolsetv=$WSDK71Set } else { $Toolsetv="v100" } } "11.0" {$Toolsetv="v110_xp"} "12.0" {$Toolsetv="v120_xp"} "14.0" {$Toolsetv="v140_xp"} "15.0" {$Toolsetv="v141_xp"} "16.0" {$Toolsetv="v142"} "17.0" {$Toolsetv="v143"} } } # avoid a bug of Windows7.1SDK PlatformToolset if ($Toolsetv -eq $WSDK71Set) { $env:TARGET_CPU="" } # $VCVersion.value=$VisualStudioVersion $Toolset.value=$Toolsetv if ("$MSToolsVersion" -eq "") { if ([int]$toolsout -gt 15) { $MSToolsVersion="Current" } else { $MSToolsVersion="${toolsout}.0" } } return $msbuildexe, $MSToolsVersion } # find msbuild.exe for VC10 ~ VC14 function msbfind_10_14 { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [string]$toolsver) $msbindir="" $regKey="HKLM:\Software\Wow6432Node\Microsoft\MSBuild\ToolsVersions\${toolsver}" if (Test-Path -path $regkey) { $msbitem=Get-ItemProperty $regKey if ($msbitem -ne $null) { $msbindir=$msbitem.MSBuildToolsPath } } else { $regKey="HKLM:\Software\Microsoft\MSBuild\ToolsVersions\${toolsver}" if (Test-Path -path $regkey) { $msbitem=Get-ItemProperty $regKey if ($msbitem -ne $null) { $msbindir=$msbitem.MSBuildToolsPath } } else { return "" } } return "${msbindir}msbuild" } # find msbuild.exe for VC15 ~ VC?? function msbfind_15_xx { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [string]$toolsver) # via vssetup module $vsdir = find_vs_installation $toolsver # vssetup module is unavailable return find_default_msbuild_path $toolsver $vsdir } $dumpbinexe = "" $addPath="" function Find-Dumpbin { [CmdletBinding()] Param([int]$CurMaxVC = 16) if ("$dumpbinexe" -ne "") { if ("$addPath" -ne "") { if (${env:PATH}.indexof($addPath) -lt 0) { $env:PATH = "${addPath};" + $env:PATH } } return $dumpbinexe } $addPath="" $vsdir="" try { $dum = dumpbin.exe /NOLOGO $dumpbinexe="dumpbin" } catch [Exception] { # $dumpbinexe="$env:DUMPBINEXE" if ($dumpbinexe -eq "") { $searching = $true for ($i = $CurMaxVc; $searching -and ($i -ge 14); $i--) # VC15 ~ VC?? { $vsdir = Find-VSDir $i if ("$vsdir" -ne "") { $lslist = @(Get-ChildItem "${vsdir}VC\Tools\MSVC\*\bin\HostX86\x86\dumpbin.exe" -ErrorAction SilentlyContinue) if ($lslist.Count -gt 0) { $dumpbinexe=$lslist[0].FullName $searching = $false break } } } for (; $searching -and ($i -ge 10); $i--) # VC10 ~ VC14 { $vsdir = Find-VSDir $i if ("$vsdir" -ne "") { $dumpbinexe="${vsdir}VC\bin\dumpbin.exe" if (Test-Path -Path $dumpbinexe) { $searching = $false break } } } if ($searching) { throw "dumpbin doesn't exist" } elseif ($i -eq 10) { $addPath = "${vsdir}Common7\ide" } } } Set-Variable -Name dumpbinexe -Value $dumpbinexe -Scope 1 Set-Variable -Name addPath -Value $addPath -Scope 1 if ("$addPath" -ne "") { if (${env:PATH}.indexof($addPath) -lt 0) { $env:PATH = "${addPath};" + $env:PATH } } return $dumpbinexe } function dumpbinRecurs { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [string]$dllname, [Parameter(Mandatory=$true)] [string]$dllfolder, [array]$instarray) $tmem=& ${dumpbinexe} /imports "$dllfolder\${dllname}" | select-string -pattern "^\s*(\S*\.dll)" | foreach-object {$_.Matches.Groups[1].Value} | where-object {test-path ("${dllfolder}\" + $_)} if ($LASTEXITCODE -ne 0) { throw "Failed to dumpbin ${dllfolder}\${dllname}" } if ($tmem -eq $Null) { return $instarray } if ($tmem.GetType().Name -eq "String") { [String []]$tarray = @($tmem) } else { $tarray = $tmem } $iarray=@() for ($i=0; $i -lt $tarray.length; $i++) { if (-not($instarray -contains $tarray[$i])) { $iarray += $tarray[$i] } } if ($iarray.length -eq 0) { return $instarray } $instarray += $iarray for ($i=0; $i -lt $iarray.length; $i++) { $instarray=dumpbinRecurs $iarray[$i] $dllfolder $instarray } return $instarray } function Get-RelatedDlls { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [string]$dllname, [Parameter(Mandatory=$true)] [string]$dllfolder) Find-Dumpbin | Out-Null $libpqmem=@() $libpqmem=dumpbinRecurs $dllname $dllfolder $libpqmem return $libpqmem } function env_vcversion_no() { $viver = $env:VisualStudioVersion if ("$viver" -ne "") { if ("$viver" -match "(\d+)\.0") { return [int]$matches[1] } } return 0 } function Find-VSDir { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [string]$vcversion) [int]$vcversion_no = [int]$vcversion if ("${vcversion}" -match "^(\d+)") { $vcversion_no = $matches[1] } if ((env_vcversion_no) -eq $vcversion_no) { return $env:VSINSTALLDIR } if ($vcversion_no -gt 14) { # VC15 ~ VC?? return find_vsdir_15_xx ${vcversion_no} } else { # VC10 ~ VC14 $comntools = [environment]::getenvironmentvariable("VS${vcversion_no}0COMNTOOLS") if ("$comntools" -eq "") { return "" } return (Split-Path (Split-Path $comntools -Parent) -Parent) + "\" } } [bool]$vssetup_available = $true $vssetup = $null # find vs installation path for VC15 ~ VC?? function find_vs_installation { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [string]$toolsver) $vsdir = "" # vssetup module is available? if ($vssetup_available -and ($vsseup -eq $null)) { try { $vssetup = @(Get-VssetupInstance) } catch [Exception] { $vssetup_available = $false } } $toolsnum = [int]$toolsver if ($vssetup -ne $null) { $lslist = @($vssetup | where-object { $_.InstallationVersion.Major -eq $toolsnum } | foreach-object { $_.InstallationPath }) if ($lslist.Count -gt 0) { $vsdir = $lslist[0] } } return $vsdir } $vsarray = @{VC15 = "2017"; VC16 = "2019"; VC17 = "2022"} # find VS dir for VC15 ~ VC?? function find_default_msbuild_path { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [string]$toolsver, [string]$vsdir) if ($vsdir -eq "") { $toolsnum = [int]$toolsver # As of Visual Studio 2022 (VC17), MSBuild is 64-bit and so is always in ProgramFiles if ($env:PROCESSOR_ARCHITECTURE -eq "x86" -or $toolsver -ge 17) { $pgmfs = "$env:ProgramFiles" } else { $pgmfs = "${env:ProgramFiles(x86)}" } $vsverdir = $vsarray["VC$toolsnum"] Write-Debug "$pgmfs\Microsoft Visual Studio\$vsverdir\*\MSBuild\*\Bin\MSBuild.exe" $lslist = @(Get-ChildItem "$pgmfs\Microsoft Visual Studio\$vsverdir\*\MSBuild\*\Bin\MSBuild.exe" -ErrorAction SilentlyContinue) } else { $lslist = @(Get-ChildItem "$vsdir\MSBuild\*\Bin\MSBuild.exe" -ErrorAction SilentlyContinue) } if ($lslist.Count -gt 0) { return $lslist[0].FullName } return "" } # find VS dir for VC15 ~ VC?? function find_vsdir_15_xx { [CmdletBinding()] Param([Parameter(Mandatory=$true)] [string]$toolsver) # via vssetup module $vsdir = find_vs_installation $toolsver if ($vsdir -ne "") { return $vsdir } # vssetup module is unavailable $msbpath = find_default_msbuild_path $toolsver $vsdir if ($msbpath -ne "") { return (Split-Path (Split-Path (Split-Path (Split-Path $msbpath -Parent) -Parent) -Parent) -Parent) + "\" } return "" } Export-ModuleMember -function Find-MSBuild, Find-Dumpbin, Get-RelatedDlls, Find-VSDir