PowerShell脚本返回计算机上的.NET Framework版本?


182

在计算机上返回.NET Framework版本的PowerShell脚本是什么?

我的第一个猜测是涉及WMI。有更好的东西吗?

单行返回[每行]的.NET安装仅应为最新版本。


7
一台机器可以(并且将有)具有多个版本的Fx。您要如何处理?然后是Fx2 .. Fx3.5SP1混乱。您想听什么版本?
汉克·霍尔特曼

我认为有必要为每次安装返回完整的版本号。
MattUebel,2010年

1
没有办法通过WMI做到这一点?
Mark Richman

您要求使用PowerShell,我为C#(控制台应用程序)做了一些事情。如果您有兴趣,这里是...
Matt

没有这样的东西真是令人难以置信:asp.net -v
Altimus Prime

Answers:


353

如果要使用注册表,则必须递归以获取4.x Framework的完整版本。较早的答案都返回我的系统上.NET 3.0的根号(嵌套在3.0下的WCF和WPF编号更高-我无法解释),而对于4.0则不返回任何内容。 。

编辑:对于.Net 4.5及更高版本,这再次稍有更改,因此现在这里有一篇不错的MSDN文章,解释了如何将Release值转换为.Net版本号,这是总的火车残骸:-(

这对我来说似乎正确(请注意,它在3.0上为WCF和WPF输出单独的版本号。我不知道那是什么)。它还在4.0上输出ClientFull(如果您同时安装了它们):

Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -recurse |
Get-ItemProperty -name Version,Release -EA 0 |
Where { $_.PSChildName -match '^(?!S)\p{L}'} |
Select PSChildName, Version, Release

根据MSDN文章,您可以构建查找表并返回4.5之后的发行的市场营销产品版本号:

$Lookup = @{
    378389 = [version]'4.5'
    378675 = [version]'4.5.1'
    378758 = [version]'4.5.1'
    379893 = [version]'4.5.2'
    393295 = [version]'4.6'
    393297 = [version]'4.6'
    394254 = [version]'4.6.1'
    394271 = [version]'4.6.1'
    394802 = [version]'4.6.2'
    394806 = [version]'4.6.2'
    460798 = [version]'4.7'
    460805 = [version]'4.7'
    461308 = [version]'4.7.1'
    461310 = [version]'4.7.1'
    461808 = [version]'4.7.2'
    461814 = [version]'4.7.2'
    528040 = [version]'4.8'
    528049 = [version]'4.8'
}

# For One True framework (latest .NET 4x), change the Where-Object match 
# to PSChildName -eq "Full":
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse |
  Get-ItemProperty -name Version, Release -EA 0 |
  Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} |
  Select-Object @{name = ".NET Framework"; expression = {$_.PSChildName}}, 
@{name = "Product"; expression = {$Lookup[$_.Release]}}, 
Version, Release

实际上,由于我必须不断更新此答案,因此这里有一个脚本,用于从该网页的降价来源中生成脚本(上面有一点点)。这可能会在某个时候中断,所以我将当前副本保留在上面。

# Get the text from github
$url = "https://raw.githubusercontent.com/dotnet/docs/master/docs/framework/migration-guide/how-to-determine-which-versions-are-installed.md"
$md = Invoke-WebRequest $url -UseBasicParsing
$OFS = "`n"
# Replace the weird text in the tables, and the padding
# Then trim the | off the front and end of lines
$map = $md -split "`n" -replace " installed [^|]+" -replace "\s+\|" -replace "\|$" |
    # Then we can build the table by looking for unique lines that start with ".NET Framework"
    Select-String "^.NET" | Select-Object -Unique |
    # And flip it so it's key = value
    # And convert ".NET FRAMEWORK 4.5.2" to  [version]4.5.2
    ForEach-Object { 
        [version]$v, [int]$k = $_ -replace "\.NET Framework " -split "\|"
        "    $k = [version]'$v'"
    }

# And output the whole script
@"
`$Lookup = @{
$map
}

# For extra effect we could get the Windows 10 OS version and build release id:
try {
    `$WinRelease, `$WinVer = Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" ReleaseId, CurrentMajorVersionNumber, CurrentMinorVersionNumber, CurrentBuildNumber, UBR
    `$WindowsVersion = "`$(`$WinVer -join '.') (`$WinRelease)"
} catch {
    `$WindowsVersion = [System.Environment]::OSVersion.Version
}

Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse |
    Get-ItemProperty -name Version, Release -EA 0 |
    # For The One True framework (latest .NET 4x), change match to PSChildName -eq "Full":
    Where-Object { `$_.PSChildName -match '^(?!S)\p{L}'} |
    Select-Object @{name = ".NET Framework"; expression = {`$_.PSChildName}}, 
                @{name = "Product"; expression = {`$Lookup[`$_.Release]}}, 
                Version, Release,
    # Some OPTIONAL extra output: PSComputerName and WindowsVersion
    # The Computer name, so output from local machines will match remote machines:
    @{ name = "PSComputerName"; expression = {`$Env:Computername}},
    # The Windows Version (works on Windows 10, at least):
    @{ name = "WindowsVersion"; expression = { `$WindowsVersion }}
"@

这也是我一直在寻找的东西,但是我很难确定我到底在做什么。据我了解,它正在进入NDP注册表,并递归搜索适合'^(?!S)\p{L}'正则表达式的每个文件夹,并获取版本和发行信息。该正则表达式试图限定什么?
约翰拉德

2
@Johnrad PSChildName是注册表项的叶名称。\p{L}是Unicode类别“字母”中的任何字符。(?!S)是一个负面的环视,并且^是字符串的开头。因此,必须以以外的字母开头S。因此,如果仅考虑ASCII,则与$_.PSChildName -cmatch '^[A-RT-Za-z]'(请注意-cmatch)相同。因此它会找到名称以S。开头的字母的键。我不知道如果您要过滤掉以S... 开头的名称,为什么还要关心非ASCII ……绝对让您感到困惑。
jpmc26 2016年

1
现在,我对到底Get-ItemProperty -name Version,Release -EA 0在做什么感到困惑。我知道-EA 0与相同-ErrorAction SilentlyContinue,但是将Get-ItemProperty -name Version,Release所有结果传递给它会产生什么效果?似乎没有从对象中删除任何变量,因为其他变量在管道的后续命令中使用。它会运行,在键中缺少VersionRelease名称时出错,然后将成功的对象传递到管道中的下一个命令中吗?
jpmc26 2016年

3
Get-ChildItem返回所有注册表子项(如果需要,则返回子文件夹)。Get-ItemProperty返回值(特别是:“版本”和“发布”)-我们忽略错误,因为我们不在乎没有这些值的文件夹。因此,是的,基本上,我们找到每个子文件夹,然后查找“版本”或“发行版”(忽略没有一个或两个文件夹的任何文件夹)。
Jaykul '16

3
太棒了!我只修改了该(?!S)子句以(?![SW])进一步排除“ Windows *”条目。(?=[vCF])因为我们真正关心的唯一键是Version根目录以及.NET 4.0+的“ Full”和“ Client”键,所以也可以这样做。;)
Chiramisu 2016年

27
gci 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' |
sort pschildname -des                                  |
select -fi 1 -exp pschildname

如果已安装,此答案不会返回4.5。下面来自@Jaykul并使用递归的答案。


5
gci'HKLM:\ SOFTWARE \ Microsoft \ NET Framework安装程序\ NDP'| 排序pschildname -des | foreach-object {$ _。name; $
_。GetValue

对我来说,答案就在上面,所以在这里链接到它:-):stackoverflow.com/a/3495491/1747983
Tilo 2015年

1
在Windows 10上安装了.NET 4.7.1之后,它仍然返回v4.0。
马特

24

向脚本添加了v4.8支持:

Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -recurse |
Get-ItemProperty -name Version,Release -EA 0 |
Where { $_.PSChildName -match '^(?![SW])\p{L}'} |
Select PSChildName, Version, Release, @{
  name="Product"
  expression={
      switch -regex ($_.Release) {
        "378389" { [Version]"4.5" }
        "378675|378758" { [Version]"4.5.1" }
        "379893" { [Version]"4.5.2" }
        "393295|393297" { [Version]"4.6" }
        "394254|394271" { [Version]"4.6.1" }
        "394802|394806" { [Version]"4.6.2" }
        "460798|460805" { [Version]"4.7" }
        "461308|461310" { [Version]"4.7.1" }
        "461808|461814" { [Version]"4.7.2" }
        "528040|528049" { [Version]"4.8" }
        {$_ -gt 528049} { [Version]"Undocumented version (> 4.8), please update script" }
      }
    }
}

21
[environment]::Version

为您提供CSH Version当前PSH副本正在使用的CLR 实例(如此处所述)。


3
我已经安装了.NET 4,但是PowerShell将仅使用2.0运行时。因此,在这里并没有帮助。
乔伊

@Johannes:看到对您的Q的评论,您需要明确说明您想要的内容。
理查德

9
对于Powershell 2.0,您还可以$PSVersionTable用来查找运行CLR PowerShell的版本。
基思·希尔

6
更高的版本呢?我现在有.NET 4.7.1,该脚本始终返回4.0.30319 Rev.42000。–
Matt

@Matt,您需要翻译该版本的次要部分……并注意,根据Powershell配置中的设置,可能未使用最新的次要/补丁版本。
理查德

13

正确的语法:

[System.Runtime.InteropServices.RuntimeEnvironment]::GetSystemVersion()
#or
$PSVersionTable.CLRVersion

GetSystemVersion函数返回如下字符串:

v2.0.50727        #PowerShell v2.0 in Win 7 SP1

或像这样

v4.0.30319        #PowerShell v3.0 (Windows Management Framework 3.0) in Win 7 SP1

$PSVersionTable是一个只读对象。CLRVersion属性是一个结构化的版本号,如下所示:

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      30319  18444   

1
我在win8上尝试过,它什么也不返回。在Windows 7上,它已经安装4.5.1时返回2。我不知道为什么这在新平台上不可用。在Win sesrver 2008上,它起作用。
最大

第一个选项适用于我的Windows 8、64位环境。第二个选项有效,但是我认为这只是显示当前PowerShell实例所运行的.NET版本,几乎总是最新版本。(编辑:也许他们俩都这么做。)
Vimes

同样在这里。在Windows 7上,我同时具有.net 2.0和4.0,但是命令仅显示v2.0.50727。使用Jaykul的方法。
2014年

Clr版本不等于框架版本,4个以上的框架均基于4 clr
janv8000 '16

更高的版本呢?我现在有.NET 4.7.1,该脚本始终返回4.0.30319 Rev.42000。–
Matt

11

我通过在Powershell for osx中使用制表符补全找到了这一点:

[System.Runtime.InteropServices.RuntimeInformation]::get_FrameworkDescription() .NET Core 4.6.25009.03


1
是的,它返回.NET Framework 4.7.2558.0-但是如何区分4.7与4.7.1(我的Windows 10计算机上为4.7.1)。
马特

1
[version]([Runtime.InteropServices.RuntimeInformation]::FrameworkDescription -replace '^.[^\d.]*','')
拉巴什



2

不错的解决方案

尝试使用可下载的DotNetVersionLister模块(基于注册表信息和一些“版本至营销版本”查找表)。

可以这样使用:

PS> Get-DotNetVersion -LocalHost -nosummary


ComputerName : localhost
>=4.x        : 4.5.2
v4\Client    : Installed
v4\Full      : Installed
v3.5         : Installed
v3.0         : Installed
v2.0.50727   : Installed
v1.1.4322    : Not installed (no key)
Ping         : True
Error        :

或像这样,如果您只想对某些.NET Framework> = 4. *进行测试:

PS> (Get-DotNetVersion -LocalHost -nosummary).">=4.x"
4.5.2

但是它不能正常工作(安装/导入),例如在PS v2.0中Win 7Win Server 2010由于不兼容标准)下 ...

以下“传统”功能的动机

(您可以跳过阅读并使用下面的代码)

我们必须在某些计算机上使用PS 2.0,并且无法安装/导入上述DotNetVersionLister
在其他计算机上,我们希望借助两个公司自定义和来将PS 5.1PS 2.0更新到PS 5.1(后者又需要.NET Framework> = 4.5)。 为了更好地指导管理员完成安装/更新过程,我们必须在所有计算机上的这些功能和现有的PS版本中确定.NET版本。Install-DotnetLatestCompanyInstall-PSLatestCompany

因此,我们还使用以下功能在所有环境中更安全地确定它们。

旧版PS环境的功能(例如PS v2.0

因此,以下代码和下面的(提取的)用法示例在这里很有用(基于此处的其他答案):

function Get-DotNetVersionByFs {
  <#
    .SYNOPSIS
      NOT RECOMMENDED - try using instead:
        Get-DotNetVersion 
          from DotNetVersionLister module (https://github.com/EliteLoser/DotNetVersionLister), 
          but it is not usable/importable in PowerShell 2.0 
        Get-DotNetVersionByReg
          reg(istry) based: (available herin as well) but it may return some wrong version or may not work reliably for versions > 4.5 
          (works in PSv2.0)
      Get-DotNetVersionByFs (this):  
        f(ile) s(ystem) based: determines the latest installed .NET version based on $Env:windir\Microsoft.NET\Framework content
        this is unreliable, e.g. if 4.0* is already installed some 4.5 update will overwrite content there without
        renaming the folder
        (works in PSv2.0)
    .EXAMPLE
      PS> Get-DotnetVersionByFs
      4.0.30319
    .EXAMPLE
      PS> Get-DotnetVersionByFs -All
      1.0.3705
      1.1.4322
      2.0.50727
      3.0
      3.5
      4.0.30319
    .NOTES
      from https://stackoverflow.com/a/52078523/1915920
  #>
    [cmdletbinding()]
  param(
    [Switch]$All  ## do not return only latest, but all installed
  )
  $list = ls $Env:windir\Microsoft.NET\Framework |
    ?{ $_.PSIsContainer -and $_.Name -match '^v\d.[\d\.]+' } |
    %{ $_.Name.TrimStart('v') }
  if ($All) { $list } else { $list | select -last 1 }
}


function Get-DotNetVersionByReg {
  <#
    .SYNOPSIS
      NOT RECOMMENDED - try using instead:
        Get-DotNetVersion
          From DotNetVersionLister module (https://github.com/EliteLoser/DotNetVersionLister), 
          but it is not usable/importable in PowerShell 2.0. 
          Determines the latest installed .NET version based on registry infos under 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP'
    .EXAMPLE
        PS> Get-DotnetVersionByReg
        4.5.51209
    .EXAMPLE
        PS> Get-DotnetVersionByReg -AllDetailed
        PSChildName                                          Version                                             Release
        -----------                                          -------                                             -------
        v2.0.50727                                           2.0.50727.5420
        v3.0                                                 3.0.30729.5420
        Windows Communication Foundation                     3.0.4506.5420
        Windows Presentation Foundation                      3.0.6920.5011
        v3.5                                                 3.5.30729.5420
        Client                                               4.0.0.0
        Client                                               4.5.51209                                           379893
        Full                                                 4.5.51209                                           379893
    .NOTES
      from https://stackoverflow.com/a/52078523/1915920
  #>
    [cmdletbinding()]
    param(
        [Switch]$AllDetailed  ## do not return only latest, but all installed with more details
    )
    $Lookup = @{
        378389 = [version]'4.5'
        378675 = [version]'4.5.1'
        378758 = [version]'4.5.1'
        379893 = [version]'4.5.2'
        393295 = [version]'4.6'
        393297 = [version]'4.6'
        394254 = [version]'4.6.1'
        394271 = [version]'4.6.1'
        394802 = [version]'4.6.2'
        394806 = [version]'4.6.2'
        460798 = [version]'4.7'
        460805 = [version]'4.7'
        461308 = [version]'4.7.1'
        461310 = [version]'4.7.1'
        461808 = [version]'4.7.2'
        461814 = [version]'4.7.2'
    }
    $list = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse |
        Get-ItemProperty -name Version, Release -EA 0 |
        # For One True framework (latest .NET 4x), change match to PSChildName -eq "Full":
        Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} |
        Select-Object `
           @{
               name = ".NET Framework" ; 
               expression = {$_.PSChildName}}, 
           @{  name = "Product" ; 
               expression = {$Lookup[$_.Release]}}, 
           Version, Release
    if ($AllDetailed) { $list | sort version } else { $list | sort version | select -last 1 | %{ $_.version } }
}

用法示例:

PS> Get-DotNetVersionByFs
4.0.30319

PS> Get-DotNetVersionByFs -All
1.0.3705
1.1.4322
2.0.50727
3.0
3.5
4.0.30319

PS> Get-DotNetVersionByReg
4.5.51209

PS> Get-DotNetVersionByReg -AllDetailed

.NET Framework                   Product Version        Release
--------------                   ------- -------        -------
v2.0.50727                               2.0.50727.5420
v3.0                                     3.0.30729.5420
Windows Communication Foundation         3.0.4506.5420
Windows Presentation Foundation          3.0.6920.5011
v3.5                                     3.5.30729.5420
Client                                   4.0.0.0
Client                           4.5.2   4.5.51209      379893
Full                             4.5.2   4.5.51209      379893

看不清定时使用(Get-DotNetVersion -LocalHost -nosummary).">=4.x"
ΩmegaMan

@ΩmegaMan:thx-在上面的答案中更新了您的好建议:)
Andreas Dietrich,

1

不漂亮。绝对不漂亮:

ls $Env:windir\Microsoft.NET\Framework | ? { $_.PSIsContainer } | select -exp Name -l 1

这可能会或可能不会。但是就最新版本而言,这应该是相当可靠的,因为对于旧版本(1.0、1.1)基本上是空的文件夹,而对于较新的版本则没有,这些文件夹只有在安装了适当的框架后才会出现。

不过,我怀疑一定有更好的方法。


您需要多过滤一些,“ V [.0-9] +”应该将匹配限制为.NET文件夹(我那里还有一些其他文件夹)。然后检查是否存在真正的安装...安装的组件上的WMI可能更容易。
理查德

嗯,对……在这台机器上还有一些其他文件夹–我的另一台机器上只有一堆其他文件。不过,整个答案更像是“为我工作”的案例。我确信有一种可靠且预期的方式来获取该信息。
乔伊

6
psake(构建自动化工具)采用了类似的方法并成功使用了它(或者至少没有人因为问题而更改了它)。但是,确实他们不需要完整的框架版本...对于我的计算机,这已经越来越近了:ls $Env:windir\Microsoft.NET\Framework | ? { $_.PSIsContainer -and $_.Name -match '^v\d.[\d\.]+' } | % { $_.Name.TrimStart('v') }
stej 2010年

在答案的所有单线中,stej提供的单线是最干净的,并且按预期运行。如果是的话,我会投赞成票。
Bratch

不幸的是,它不可靠。我现在有.NET 4.7.1,并且脚本始终返回v4.0.30319。
马特

0

如果您在计算机上安装了Visual Studio,则打开Visual Studio开发人员命令提示符,然后键入以下命令:clrver

它将列出该计算机上所有已安装的.NET Framework版本。


此命令获取CLR版本,而不是.NET Framework版本-这是不同的。
user11909

0

这是我根据msft文档对这个问题的看法

$gpParams = @{
    Path        = 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full'
    ErrorAction = 'SilentlyContinue'
}
$release = Get-ItemProperty @gpParams | Select-Object -ExpandProperty Release

".NET Framework$(
    switch ($release) {
        ({ $_ -ge 528040 }) { ' 4.8'; break }
        ({ $_ -ge 461808 }) { ' 4.7.2'; break }
        ({ $_ -ge 461308 }) { ' 4.7.1'; break }
        ({ $_ -ge 460798 }) { ' 4.7'; break }
        ({ $_ -ge 394802 }) { ' 4.6.2'; break }
        ({ $_ -ge 394254 }) { ' 4.6.1'; break }
        ({ $_ -ge 393295 }) { ' 4.6'; break }
        ({ $_ -ge 379893 }) { ' 4.5.2'; break }
        ({ $_ -ge 378675 }) { ' 4.5.1'; break }
        ({ $_ -ge 378389 }) { ' 4.5'; break }
        default { ': 4.5+ not installed.' }
    }
)"

本示例适用于所有PowerShell版本,并将永久使用,因为4.8是最新的.NET Framework版本。


-1

这是一般的想法:

在.NET Framework目录中获取名称与模式v数字点号匹配的容器的子项。按降序对它们进行排序,获取第一个对象,然后返回其name属性。

这是脚本:

(Get-ChildItem -Path $Env:windir\Microsoft.NET\Framework | Where-Object {$_.PSIsContainer -eq $true } | Where-Object {$_.Name -match 'v\d\.\d'} | Sort-Object -Property Name -Descending | Select-Object -First 1).Name

我已经安装了4.6.1,但是您的脚本返回了v4.0.30319
rob

那在我的机器上不起作用(我已经安装了4.7.1)。它会打印v4.0.30319
Matt

-1

我会在PowerShell中尝试以下方法:为我工作!

(Get-ItemProperty“ HKLM:Software \ Microsoft \ NET Framework安装程序\ NDP \ v4 \ Full”)。版本


那没有告诉你真相。产品版本号为4.7.03056,例如产品版本为4.7.2
Jaykul

-2

我没有使用PowerShell语法,但是我认为您可以调用System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion()。这将以字符串形式返回版本(v2.0.50727我认为类似)。


2
对于当前执行的运行时,不一定是最新安装的运行时。
乔伊

对于[System.Runtime.InteropServices.RuntimeEnvironment]::GetSystemVersion()Powershell,正确的语法是:,但是即使在我的情况下安装了v4.6,它也只会返回v4.0.30319。
马特

@matt 4.0.30319是从.Net Framework 4.0到.Net Framework 4.7.1的CLR版本。因此,您的v4.6框架实际上使用4.0.30319作为其CLR版本。请注意,所有版本的.Net框架之间只有版本的修订部分有所不同。另请参见:.NET Framework版本和依赖项-Microsoft文档
walterlv

@walterlv-谢谢您的链接。是的,我知道这一点。微软这样做是犯了一个大错误,远程连接到服务器并找出实际在其中安装了哪个.net版本并不容易。管理员和开发人员的另一个大头疼。
马特

这也可能会有所帮助:Microsoft:如何确定.NET Framework的版本和Service Pack级别。它也显示了找出精确地安装在您的计算机上的东西变得多么复杂... :-(
Matt

-2

这是上一篇文章的衍生版本,但是在我的测试中,它获得了.net framework 4的最新版本。

get-itemproperty -name version,release "hklm:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\FULL"

这将允许您调用命令到远程计算机:

invoke-command -computername server01 -scriptblock {get-itemproperty -name version,release "hklm:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\FULL" | select pscomputername,version,release} 

这用ADModule和命名约定前缀设置了这种可能性:

get-adcomputer -Filter 'name -like "*prefix*"' | % {invoke-command -computername $_.name -scriptblock {get-itemproperty -name version,release "hklm:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\FULL" | select pscomputername,version,release} | ft
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.