在机器上返回.NET框架版本的PowerShell脚本是什么?

我的第一个猜测是与WMI有关。还有更好的办法吗?

它应该是一行程序,在每一行上只返回。net安装的最新版本。


当前回答

好的解决方案

尝试使用可下载的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框架>= 4.*:

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

但它将无法工作(安装/导入),例如与PS v2.0 (Win 7, Win Server 2010标准)由于不兼容…

“遗产”的动机功能如下

(你可以跳过阅读下面的代码)

We had to work with PS 2.0 on some machines and could not install/import the above DotNetVersionLister. On other machines we wanted to update (from PS 2.0) to PS 5.1 (which in turn needs .NET Framework >= 4.5) with the help of two company-custom Install-DotnetLatestCompany and Install-PSLatestCompany. To guide admins nicely through the install/update process we would have to determine the .NET version in these functions on all machines and PS versions existing. Thus we used also the below functions to determine them more safely in all environments...

用于遗留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

其他回答

这纯粹是因为当它应该被广泛使用时,我不得不花时间制作/编辑它,所以我把它提供给其他人。

下面的脚本将输出两个CSV文件到TEMP,其中包含所选OU(代码中)中每台机器的版本和漏洞状态。您将能够远程“安全审计”计算机OU。

连接测试线路需要Powershell 7.0 RSAT需要得到AD模块 获得powershell 7.0所需的Visual Studio代码(win7上)

当您阅读本文时,文件中的版本列表可能已经过期。使用此网站https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/versions-and-dependencies添加新的dotnet条目。它只是DotNet4Builds中的一堆键值

如果在compresedcheck .csv中,一台机器显示为=0,那么它已经手动关闭了安全性,您应该提出是供应商做的,还是可疑员工做的。

我希望这有助于人们搜索它为他们的业务。

     <#
        Script Name : Get-DotNetVersions_Tweaked.ps1
        Description : This script reports the various .NET Framework versions installed on the local or a remote set of computers
        Author      : Original by Martin Schvartzman - Edited by Mark Purnell
        Reference   : https://msdn.microsoft.com/en-us/library/hh925568
#>

$ErrorActionPreference = "Continue”
import-module ActiveDirectory
$searchOU = "OU=OU LEVEL 1,OU=OU LEVEL 2,OU=MACHINES,OU=OUR LAPTOPS,DC=PUT,DC=MY,DC=DOMAIN,DC=CONTROLLER,DC=HERE,DC=OK"
$computerList = Get-ADComputer -searchbase $searchOU -Filter *


function Get-DotNetFrameworkVersion($computerList)
{
    $dotNetter = @()
    $compromisedCheck = @()
    
    $dotNetRoot = 'SOFTWARE\Microsoft\.NETFramework'
    $dotNetRegistry  = 'SOFTWARE\Microsoft\NET Framework Setup\NDP'
    $dotNet4Registry = 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full'
    $dotNet4Builds = @{
        '30319'  = @{ Version = [System.Version]'4.0'                                                     }
        '378389' = @{ Version = [System.Version]'4.5'                                                     }
        '378675' = @{ Version = [System.Version]'4.5.1'   ; Comment = '(8.1/2012R2)'                      }
        '378758' = @{ Version = [System.Version]'4.5.1'   ; Comment = '(8/7 SP1/Vista SP2)'               }
        '379893' = @{ Version = [System.Version]'4.5.2'                                                   }
        '380042' = @{ Version = [System.Version]'4.5'     ; Comment = 'and later with KB3168275 rollup'   }
        '393295' = @{ Version = [System.Version]'4.6'     ; Comment = '(Windows 10)'                      }
        '393297' = @{ Version = [System.Version]'4.6'     ; Comment = '(NON Windows 10)'                  }
        '394254' = @{ Version = [System.Version]'4.6.1'   ; Comment = '(Windows 10)'                      }
        '394271' = @{ Version = [System.Version]'4.6.1'   ; Comment = '(NON Windows 10)'                  }
        '394802' = @{ Version = [System.Version]'4.6.2'   ; Comment = '(Windows 10 Anniversary Update)'   }
        '394806' = @{ Version = [System.Version]'4.6.2'   ; Comment = '(NON Windows 10)'                  }
        '460798' = @{ Version = [System.Version]'4.7'     ; Comment = '(Windows 10 Creators Update)'      }
        '460805' = @{ Version = [System.Version]'4.7'     ; Comment = '(NON Windows 10)'                  }
        '461308' = @{ Version = [System.Version]'4.7.1'   ; Comment = '(Windows 10 Fall Creators Update)' }
        '461310' = @{ Version = [System.Version]'4.7.1'   ; Comment = '(NON Windows 10)'                  }
        '461808' = @{ Version = [System.Version]'4.7.2'   ; Comment = '(Windows 10 April & Winserver)'    }
        '461814' = @{ Version = [System.Version]'4.7.2'   ; Comment = '(NON Windows 10)'                  }
        '528040' = @{ Version = [System.Version]'4.8'     ; Comment = '(Windows 10 May 2019 Update)'  }
        '528049' = @{ Version = [System.Version]'4.8'     ; Comment = '(NON Windows 10)'  }
    }

    foreach($computerObject in $computerList)
    {
        $computerName = $computerObject.DNSHostName
        write-host("PCName is " + $computerName)

        if(test-connection -TargetName $computerName -Quiet -TimeOutSeconds 1 -count 2){
            if($regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computerName))           
            {
                $os = (Get-WMIObject win32_operatingsystem -ComputerName SPL305350).Name
                if(!$?){
                    write-host("wim not available")
                    $dotNetter += New-Object -TypeName PSObject -Property @{
                        'ComputerName' = $computerName
                        'OS' = "WIM not available"
                        'Build' = "WIM not available"
                        'Version' = "WIM not available"
                        'Comment' = "WIM not available"
                    }
                }
                else{
                    if ($netRegKey = $regKey.OpenSubKey("$dotNetRegistry"))
                    {
                        foreach ($versionKeyName in $netRegKey.GetSubKeyNames())
                        {
                            if ($versionKeyName -match '^v[123]') {
                                $versionKey = $netRegKey.OpenSubKey($versionKeyName)
                                $version = [System.Version]($versionKey.GetValue('Version', ''))
                                
                                write-host("adding old dotnet")
                                $dotNetter += New-Object -TypeName PSObject -Property @{
                                        ComputerName = $computerName
                                        OS = $os
                                        Build = $version.Build
                                        Version = $version
                                        Comment = ''
                                }
                            }
                        }
                    }
                    if ($net4RegKey = $regKey.OpenSubKey("$dotNet4Registry"))
                    {
                        if(-not ($net4Release = $net4RegKey.GetValue('Release')))
                        {
                            $net4Release = 30319
                        }
                        
                        write-host("adding new dotnet")
                        $dotNetter += New-Object -TypeName PSObject -Property @{
                                'ComputerName' = $computerName
                                'OS' = $os
                                'Build' = $net4Release
                                'Version' = $dotNet4Builds["$net4Release"].Version
                                'Comment' = $dotNet4Builds["$net4Release"].Comment
                        }
                    }
                    if ($netRegKey = $regKey.OpenSubKey("$dotNetRoot")){
                        write-host("Checking for hacked keys")
                        foreach ($versionKeyName in $netRegKey.GetSubKeyNames())
                        {
                            if ($versionKeyName -match '^v[1234]') {
                                $versionKey = $netRegKey.OpenSubKey($versionKeyName)
                                write-host("versionKeyName is" + $versionKeyName)
                                write-host('ASPNetEnforceViewStateMac = ' + $versionKey.GetValue('ASPNetEnforceViewStateMac', ''))
                                $compromisedCheck += New-Object -TypeName PSObject -Property @{
                                    'ComputerName' = $computerName
                                    'version' = $versionKeyName
                                    'compromisedCheck' = ('ASPNetEnforceViewStateMac = ' + $versionKey.GetValue('ASPNetEnforceViewStateMac', ''))
                                }
                            }
                        }
                    }
                }
            }
        }
        else{
            write-host("could not connect to machine")
            $dotNetter += New-Object -TypeName PSObject -Property @{
                    'ComputerName' = $computerName
                    'OS' = $os
                    'Build' = "Could not connect"
                    'Version' = "Could not connect"
                    'Comment' = "Could not connect"
            }
        }
    }
    $dotNetter | export-CSV c:\temp\DotNetVersions.csv
    $compromisedCheck | export-CSV C:\temp\CompromisedCheck.csv
}
get-dotnetframeworkversion($computerList)

没有可靠的方法可以使用一个简单的脚本为所有平台和体系结构做到这一点。如果你想学习如何可靠地完成它,请从博客文章更新的。net框架检测代码样本开始,它可以进行更深入的检查。

如果你要使用注册表,你必须递归才能得到完整版本的4。x框架。前面的答案都返回了。net 3.0系统上的根数(其中WCF和WPF的数字,嵌套在3.0下,更高——我无法解释),而4.0则没有返回任何东西……

编辑:对于。net 4.5及以上版本,这又发生了轻微的变化,所以现在有一篇很好的MSDN文章解释了如何将发布值转换为。net版本号,这完全是一场灾难:-(

这对我来说是正确的(注意它在3.0上为WCF和WPF输出单独的版本号。我不知道那是怎么回事)。它还输出客户端和完整的4.0(如果你有他们都安装):

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

事实上,由于我必须不断更新这个答案,这里有一个脚本,从该网页的markdown源代码生成上面的脚本(带有一点额外的内容)。这可能会在某个时候崩溃,所以我保持上面的当前副本。

# 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 }}
"@

以下是我对这个问题的看法:

$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版本。

如果您已经在计算机上安装了Visual Studio,那么打开Visual Studio开发人员命令提示符并键入以下命令: clrver

它将列出该机器上所有已安装的。net Framework版本。