1 
Find-MSBuildnull2 function Find-MSBuild
3 {
4     [CmdletBinding()]
5 
6     Param([Parameter(Mandatory=$true)]
7           [ref]$VCVersion,
8           [Parameter(Mandatory=$true)]
9           $MSToolsVersion,
10           [Parameter(Mandatory=$true)]
11           [ref]$Toolset,
12           [Parameter(Mandatory=$true)]
13           [xml]$configInfo)
14 
15 	$msbuildexe=""
16 	$VisualStudioVersion=$VCVersion.Value
17 	$Toolsetv=$Toolset.Value
18 
19 	$WSDK71Set="Windows7.1SDK"
20 	Write-Debug "VCVersion=$VCVersionv $env:VisualStudioVersion"
21 	[int]$toolsnum=0
22 #
23 #	Determine VisualStudioVersion
24 #
25 	if (("$VisualStudioVersion" -eq "") -And ($configInfo -ne $null)) {
26 		$VisualStudioVersion=$configInfo.Configuration.vcversion
27 	}
28 	if ("$VisualStudioVersion" -eq "") {
29 		$VisualStudioVersion = $env:VisualStudioVersion # VC11 or later version of C++ command prompt sets this variable
30 	}
31 	if ("$VisualStudioVersion" -eq "") {
32 		if ("${env:WindowsSDKVersionOverride}" -eq "v7.1") { # SDK7.1+ command prompt
33 			$VisualStudioVersion = "10.0"
34 		} elseif ("${env:VCInstallDir}" -ne "") { # C++ command prompt
35 			if ("${env:VCInstallDir}" -match "Visual Studio\s*(\S+)\\VC\\$") {
36 				$VisualStudioVersion = $matches[1]
37 			}
38 		}
39 	}
40 	$refnum=""
41 #	neither C++ nor SDK prompt
42 	if ("$VisualStudioVersion" -eq "") {
43 		if ((Find-VSDir 15) -ne "") {	# VC15 is installed (current official)
44 			$VisualStudioVersion = "15.0"
45 		} elseif ((Find-VSDir 16) -ne "") {	# VC16 is installed
46 			$VisualStudioVersion = "16.0"
47 		} elseif ("${env:VS140COMNTOOLS}" -ne "") { # VC14 is installed
48 			$VisualStudioVersion = "14.0"
49 		} elseif ("${env:VS120COMNTOOLS}" -ne "") { # VC12 is installed
50 			$VisualStudioVersion = "12.0"
51 		} elseif ("${env:VS100COMNTOOLS}" -ne "") { # VC10 is installed
52 			$VisualStudioVersion = "10.0"
53 		} elseif ("${env:VS110COMNTOOLS}" -ne "") { # VC11 is installed
54 			$VisualStudioVersion = "11.0"
55 		} else {
56 			throw "Visual Studio >= 10.0 not found"
57 		}
58 	}
59 	if ([int]::TryParse($VisualStudioVersion, [ref]$refnum)) {
60 		$VisualStudioVersion="${refnum}.0"
61 	}
62 #	Check VisualStudioVersion and prepare for ToolsVersion
63 	switch ($VisualStudioVersion) {
64 	 "10.0"	{ $toolsout = 4 }
65 	 "11.0"	{ $toolsout = 4 }
66 	 "12.0"	{ $toolsout = 12 }
67 	 "14.0"	{ $toolsout = 14 }
68 	 "15.0"	{ $toolsout = 15 }
69 	 "16.0"	{ $toolsout = 16 }
70 	 default { throw "Selected Visual Stuidio is Version ${VisualStudioVersion}. Please use VC10 or later"}
71 	}
72 #
73 #	Determine ToolsVersion
74 #
75 	[int]$toolsnum=$toolsout
76 	if ("$MSToolsVersion" -eq "") {
77 		$MSToolsVersion=$env:ToolsVersion
78 	}
79 	if ("$MSToolsVersion" -ne "") {
80 		if ([int]::TryParse($MSToolsVersion, [ref]$refnum)) {
81 			$toolsout=[int]$refnum
82 		}
83 	}
84 	if ($toolsnum -lt 12) {
85 		$toolsnum=$toolsout
86 	}
87 #
88 #	Determine MSBuild executable
89 #
90 	Write-Debug "ToolsVersion=$MSToolsVersion VisualStudioVersion=$VisualStudioVersion"
91 	try {
92 		$msbver = msbuild.exe /ver /nologo
93 		if ("$msbver" -match "^(\d+)\.(\d+)") {
94 			$major1 = [int] $matches[1]
95 			$minor1 = [int] $matches[2]
96 			if ($MSToolsVersion -match "^(\d+)\.(\d+)") {
97 				$bavail = $false
98 				$major2 = [int] $matches[1]
99 				$minor2 = [int] $matches[2]
100 				if ($major1 -gt $major2) {
101 					Write-Debug "$major1 > $major2"
102 					$bavail = $true
103 				}
104 				elseif ($major1 -eq $major2 -And $minor1 -ge $minor2) {
105 					Write-Debug "($major1, $minor1) >= ($major2, $minor2)"
106 					$bavail = $true
107 				}
108 				if ($bavail) {
109 					$msbuildexe = "MSBuild"
110 				}
111 			}
112 		}
113 	} catch {}
114 	if ("$msbuildexe" -eq "") {
115 		if ($toolsnum -gt 14) {	# VC15 ~ VC16
116 			$msbuildexe = msbfind_15_xx $toolsnum
117 		} else {			# VC10 ~ VC14
118 			$msbuildexe = msbfind_10_14 "${toolsnum}.0"
119 			if ($toolsnum -eq 4) {
120 				if ((Find-VSDir $VisualStudioVersion) -eq "") {
121 					throw "MSBuild ${toolsnum}.0 found but VisualStudioVersion $VisualStudioVersion not Found"
122 				}
123 			}
124 		}
125 		if ("$msbuildexe" -eq "") {
126 			throw "MSBuild ToolsVersion ${toolsnum}.0 not Found"
127 		}
128 	}
129 #
130 #	Determine PlatformToolset
131 #
132 	if (("$Toolsetv" -eq "") -And ($configInfo -ne $null)) {
133 		$Toolsetv=$configInfo.Configuration.toolset
134 	}
135 	if ("$Toolsetv" -eq "") {
136 		$Toolsetv=$env:PlatformToolset
137 	}
138 	if ("$Toolsetv" -eq "") {
139 		switch ($VisualStudioVersion) {
140 		 "10.0"	{
141 				if (Test-path "HKLM:\Software\Microsoft\Microsoft SDKs\Windows\v7.1") {
142 					$Toolsetv=$WSDK71Set
143 				} else {
144 					$Toolsetv="v100"
145 				}
146 			}
147 		 "11.0"	{$Toolsetv="v110_xp"}
148 		 "12.0"	{$Toolsetv="v120_xp"}
149 		 "14.0"	{$Toolsetv="v140_xp"}
150 		 "15.0"	{$Toolsetv="v141_xp"}
151 		 "16.0"	{$Toolsetv="v142"}
152 		}
153 	}
154 #	avoid a bug of Windows7.1SDK PlatformToolset
155 	if ($Toolsetv -eq $WSDK71Set) {
156 		$env:TARGET_CPU=""
157 	}
158 #
159 	$VCVersion.value=$VisualStudioVersion
160 	$Toolset.value=$Toolsetv
161 
162 	if ("$MSToolsVersion" -eq "") {
163 		if ([int]$toolsout -gt 15) {
164 			$MSToolsVersion="Current"
165 		} else {
166 			$MSToolsVersion="${toolsout}.0"
167 		}
168 	}
169 	return $msbuildexe, $MSToolsVersion
170 }
171 
172 #	find msbuild.exe for VC10 ~ VC14
msbfind_10_14null173 function msbfind_10_14
174 {
175     [CmdletBinding()]
176 
177     Param([Parameter(Mandatory=$true)]
178           [string]$toolsver)
179 
180 	$msbindir=""
181 	$regKey="HKLM:\Software\Wow6432Node\Microsoft\MSBuild\ToolsVersions\${toolsver}"
182 	if (Test-Path -path $regkey) {
183 		$msbitem=Get-ItemProperty $regKey
184 		if ($msbitem -ne $null) {
185 			$msbindir=$msbitem.MSBuildToolsPath
186 		}
187 	} else {
188 		$regKey="HKLM:\Software\Microsoft\MSBuild\ToolsVersions\${toolsver}"
189 		if (Test-Path -path $regkey) {
190 			$msbitem=Get-ItemProperty $regKey
191 			if ($msbitem -ne $null) {
192 				$msbindir=$msbitem.MSBuildToolsPath
193 			}
194 		} else {
195 			return ""
196 		}
197 	}
198 	return "${msbindir}msbuild"
199 }
200 
201 #	find msbuild.exe for VC15 ~ VC16
msbfind_15_xx()202 function msbfind_15_xx
203 {
204     [CmdletBinding()]
205 
206     Param([Parameter(Mandatory=$true)]
207           [string]$toolsver)
208 
209 # via vssetup module
210 	$vsdir = find_vs_installation $toolsver
211 # vssetup module is unavailable
212 	return find_default_msbuild_path $toolsver $vsdir
213 }
214 
215 $dumpbinexe = ""
216 $addPath=""
217 
Find-Dumpbinnull218 function Find-Dumpbin
219 {
220     [CmdletBinding()]
221 
222     Param([int]$CurMaxVC = 16)
223 
224 	if ("$dumpbinexe" -ne "") {
225 		if ("$addPath" -ne "") {
226 			if (${env:PATH}.indexof($addPath) -lt 0) {
227 				$env:PATH = "${addPath};" + $env:PATH
228 			}
229 		}
230 		return $dumpbinexe
231 	}
232 	$addPath=""
233 	$vsdir=""
234 	try {
235 		$dum = dumpbin.exe /NOLOGO
236 		$dumpbinexe="dumpbin"
237 	} catch [Exception] {
238 #		$dumpbinexe="$env:DUMPBINEXE"
239 		if ($dumpbinexe -eq "") {
240 			$searching = $true
241 			for ($i = $CurMaxVc; $searching -and ($i -ge 14); $i--)	# VC15 ~ VC16
242 			{
243 				$vsdir = Find-VSDir $i
244 				if ("$vsdir" -ne "") {
245 					$lslist = @(Get-ChildItem "${vsdir}VC\Tools\MSVC\*\bin\HostX86\x86\dumpbin.exe" -ErrorAction SilentlyContinue)
246 					if ($lslist.Count -gt 0) {
247 						$dumpbinexe=$lslist[0].FullName
248 						$searching = $false
249 						break
250 					}
251 				}
252 			}
253 			for (; $searching -and ($i -ge 10); $i--)	# VC10 ~ VC14
254 			{
255 				$vsdir = Find-VSDir $i
256 				if ("$vsdir" -ne "") {
257 					$dumpbinexe="${vsdir}VC\bin\dumpbin.exe"
258 					if (Test-Path -Path $dumpbinexe) {
259 						$searching = $false
260 						break
261 					}
262 				}
263 			}
264 			if ($searching) {
265 				throw "dumpbin doesn't exist"
266 			}
267 			elseif ($i -eq 10) {
268 				$addPath = "${vsdir}Common7\ide"
269 			}
270 		}
271 	}
272 
273 	Write-Host "Dumpbin=$dumpbinexe"
274 	Set-Variable -Name dumpbinexe -Value $dumpbinexe -Scope 1
275 	Set-Variable -Name addPath -Value $addPath -Scope 1
276 	if ("$addPath" -ne "") {
277 		if (${env:PATH}.indexof($addPath) -lt 0) {
278 			$env:PATH = "${addPath};" + $env:PATH
279 		}
280 	}
281 	return $dumpbinexe
282 }
283 
dumpbinRecurs()284 function dumpbinRecurs
285 {
286     [CmdletBinding()]
287 
288     Param([Parameter(Mandatory=$true)]
289           [string]$dllname,
290           [Parameter(Mandatory=$true)]
291           [string]$dllfolder,
292           [array]$instarray)
293 
294 	$tmem=& ${dumpbinexe} /imports "$dllfolder\${dllname}" | select-string -pattern "^\s*(\S*\.dll)" | foreach-object {$_.Matches.Groups[1].Value} | where-object {test-path ("${dllfolder}\" + $_)}
295 	if ($LASTEXITCODE -ne 0) {
296 		throw "Failed to dumpbin ${dllfolder}\${dllname}"
297 	}
298 	if ($tmem -eq $Null) {
299 		return $instarray
300 	}
301 	if ($tmem.GetType().Name -eq "String") {
302 		[String []]$tarray = @($tmem)
303 	} else {
304 		$tarray = $tmem
305 	}
306 	$iarray=@()
307 	for ($i=0; $i -lt $tarray.length; $i++) {
308 		if (-not($instarray -contains $tarray[$i])) {
309 			$iarray += $tarray[$i]
310 		}
311 	}
312 	if ($iarray.length -eq 0) {
313 		return $instarray
314 	}
315 	$instarray += $iarray
316 	for ($i=0; $i -lt $iarray.length; $i++) {
317 		$instarray=dumpbinRecurs $iarray[$i] $dllfolder $instarray
318 	}
319 	return $instarray
320 }
321 
Get-RelatedDlls()322 function Get-RelatedDlls
323 {
324     [CmdletBinding()]
325 
326     Param([Parameter(Mandatory=$true)]
327           [string]$dllname,
328           [Parameter(Mandatory=$true)]
329           [string]$dllfolder)
330 
331 	Find-Dumpbin | Out-Null
332 	$libpqmem=@()
333 	$libpqmem=dumpbinRecurs $dllname $dllfolder $libpqmem
334 
335 	return $libpqmem
336 }
337 
env_vcversion_no()338 function env_vcversion_no()
339 {
340 	$viver = $env:VisualStudioVersion
341 	if ("$viver" -ne "") {
342 		if ("$viver" -match "(\d+)\.0") {
343 			return [int]$matches[1]
344 		}
345 	}
346 	return 0
347 }
348 
Find-VSDir()349 function Find-VSDir
350 {
351     [CmdletBinding()]
352 
353     Param([Parameter(Mandatory=$true)]
354           [string]$vcversion)
355 
356 	[int]$vcversion_no = [int]$vcversion
357 	if ("${vcversion}" -match "^(\d+)") {
358 		$vcversion_no = $matches[1]
359 	}
360 	if ((env_vcversion_no) -eq $vcversion_no) {
361 		return $env:VSINSTALLDIR
362 	}
363 	if ($vcversion_no -gt 14) {	# VC15 ~ VC16
364 		return find_vsdir_15_xx ${vcversion_no}
365 	} else {	# VC10 ~ VC14
366 		$comntools = [environment]::getenvironmentvariable("VS${vcversion_no}0COMNTOOLS")
367 		if ("$comntools" -eq "") {
368 			return ""
369 		}
370 		return (Split-Path (Split-Path $comntools -Parent) -Parent) + "\"
371 	}
372 }
373 
374 [bool]$vssetup_available = $true
375 $vssetup = $null
376 #	find vs installation path for VC15 ~ VC16
find_vs_installation()377 function find_vs_installation
378 {
379     [CmdletBinding()]
380 
381     Param([Parameter(Mandatory=$true)]
382           [string]$toolsver)
383 
384 	$vsdir = ""
385 # vssetup module is available?
386 	if ($vssetup_available -and ($vsseup -eq $null)) {
387 		try {
388 			$vssetup = @(Get-VssetupInstance)
389 		} catch [Exception] {
390 			$vssetup_available = $false
391 		}
392 	}
393 	$toolsnum = [int]$toolsver
394 	if ($vssetup -ne $null) {
395 		$lslist = @($vssetup | where-object { $_.InstallationVersion.Major -eq $toolsnum } | foreach-object { $_.InstallationPath })
396 		if ($lslist.Count -gt 0) {
397 			$vsdir = $lslist[0]
398 		}
399 	}
400 	return $vsdir
401 }
402 
403 $vsarray = @{VC15 = "2017"; VC16 = "2019"}
404 #	find VS dir for VC15 ~ VC16
find_default_msbuild_path()405 function find_default_msbuild_path
406 {
407     [CmdletBinding()]
408 
409     Param([Parameter(Mandatory=$true)]
410           [string]$toolsver,
411           [string]$vsdir)
412 
413 	if ($vsdir -eq "")
414 	{
415 		$toolsnum = [int]$toolsver
416 		if ($env:PROCESSOR_ARCHITECTURE -eq "x86") {
417 			$pgmfs = "$env:ProgramFiles"
418 		} else {
419 			$pgmfs = "${env:ProgramFiles(x86)}"
420 		}
421 		$vsverdir = $vsarray["VC$toolsnum"]
422 		$lslist = @(Get-ChildItem "$pgmfs\Microsoft Visual Studio\$vsverdir\*\MSBuild\*\Bin\MSBuild.exe" -ErrorAction SilentlyContinue)
423 	} else {
424 		$lslist = @(Get-ChildItem "$vsdir\MSBuild\*\Bin\MSBuild.exe" -ErrorAction SilentlyContinue)
425 	}
426 	if ($lslist.Count -gt 0) {
427 		return $lslist[0].FullName
428 	}
429 
430 	return ""
431 }
432 
433 #	find VS dir for VC15 ~ VC16
find_vsdir_15_xx()434 function find_vsdir_15_xx
435 {
436     [CmdletBinding()]
437 
438     Param([Parameter(Mandatory=$true)]
439           [string]$toolsver)
440 
441 # via vssetup module
442 	$vsdir = find_vs_installation $toolsver
443 	if ($vsdir -ne "") {
444 		return $vsdir
445 	}
446 # vssetup module is unavailable
447 	$msbpath = find_default_msbuild_path $toolsver $vsdir
448 	if ($msbpath -ne "") {
449 		return (Split-Path (Split-Path (Split-Path (Split-Path $msbpath -Parent) -Parent) -Parent) -Parent) + "\"
450 	}
451 
452 	return ""
453 }
454 
455 Export-ModuleMember -function Find-MSBuild, Find-Dumpbin, Get-RelatedDlls, Find-VSDir
456