TL;DR The Microsoft.Build.Utilities assembly doesn't support framework versions newer than 2.0. Use a newer assembly to get support for newer framework versions.
On 64-bit Windows 10 Professional I get the following output...
PS> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.18362.145
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.18362.145
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
PS> [Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFramework([Microsoft.Build.Utilities.TargetDotNetFrameworkVersion]::VersionLatest)
C:\Windows\Microsoft.NET\Framework\v2.0.50727
I also notice that the VersionLatest enumeration value is an alias for Version20...
PS> [Microsoft.Build.Utilities.TargetDotNetFrameworkVersion]::VersionLatest
Version20
That is, VersionLatest evidently doesn't mean "find the latest installed framework version at runtime", it's just a flexible way to specify the latest available version known at compile-time (of that Microsoft.Build.Utilities assembly), of which there are not many...
PS> $enumType = [Microsoft.Build.Utilities.TargetDotNetFrameworkVersion]
PS> [Enum]::GetNames($enumType) `
| ForEach-Object -Process {
$value = $enumType::$_;
New-Object -TypeName 'PSCustomObject' -Property (
[Ordered] @{
Name = $_;
ValueText = $value;
ValueInt32 = [Int32] $value
}
)
}
Name ValueText ValueInt32
---- --------- ----------
Version11 Version11 0
Version20 Version20 1
VersionLatest Version20 1
Regarding the results you see on different operating systems, Windows 7 has .NET 2.0 installed by default and, if I recall, Windows 10 has .NET 4.0 but not 2.0 installed by default, so if you didn't change anything that would explain why you get outdated results on Windows 7 and no results on Windows 10. I do have .NET 2.0 as an installed feature on Windows 10, which is why the method is able to find that framework directory.
To fix this, you need to use a newer Microsoft.Build.Utilities* assembly, which uses a new name for each version. On my system I have Microsoft.Build.Utilities and Microsoft.Build.Utilities.v3.5 in the GAC, but the latter only supports up to .NET 3.5. Instead, I installed Microsoft.Build.Utilities.Core from NuGet...
PS> Install-Package -Name 'Microsoft.Build.Utilities.Core' -ProviderName 'NuGet'
After passing Microsoft.Build.Utilities.Core.dll and its dependencies to Add-Type, I get a much longer list of Microsoft.Build.Utilities.TargetDotNetFrameworkVersion values using the snippet above...
Name ValueText ValueInt32
---- --------- ----------
Version11 Version11 0
Version20 Version20 1
Version30 Version30 2
Version35 Version35 3
Version40 Version40 4
Version45 Version45 5
Version451 Version451 6
Version46 Version46 7
Version461 Version461 8
Version452 Version452 9
Version462 VersionLatest 10
VersionLatest VersionLatest 10
Version47 Version47 11
Version471 Version471 12
Version472 Version472 13
Latest Latest 9999
Now your original code finally returns the directory for .NET 4.0...
PS> [Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFramework([Microsoft.Build.Utilities.TargetDotNetFrameworkVersion]::VersionLatest)
C:\Windows\Microsoft.NET\Framework64\v4.0.30319
I notice there is a new Latest enumeration value as well which looks like it really does mean "the version of the latest installed framework", though it (currently) returns the same path as passing VersionLatest.
2.0.5+but the newest directory is actually4.0.3+inC:\Windows\Microsoft.NET\Framework64- the newest installed version in the4.0.3+dir is4.7.3+. i have no idea why the numbers are so different.