prb
prb

Reputation: 189

Get path to .NET Framework directory in Powershell

I am trying to use this method to get the .NET Framework directory (e.g. C:\Windows\Microsoft.NET\v4.0.30319)

Add-Type -AssemblyName Microsoft.Build.Utilities

$dotNetDir = [Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFramework([Microsoft.Build.Utilities.TargetDotNetFrameworkVersion]::VersionLatest)

However, it is returning nothing. No error, just blank.

I know there are other ways to get the .NET directory but I am wondering why this method is not working?

Upvotes: 1

Views: 2360

Answers (1)

Lance U. Matthews
Lance U. Matthews

Reputation: 16596

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.

Upvotes: 2

Related Questions