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

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

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


当前回答

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

下面的脚本将输出两个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的最新版本。

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

大致是这样的:

获取.NET Framework目录中名称匹配的容器的子项 模式vnumber·number。按名称降序排序,取第一个对象, 并返回其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

正确的语法:

[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   

如果你要使用注册表,你必须递归才能得到完整版本的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版本。