如何可靠地检测已安装的实际.NET 4.5版本?

54

我的实际问题是我遇到了两个.NET 4.5完整安装程序的版本:

  • (可能)较旧的版本,在下载SQL Server数据工具时也可用
    • 大小:50,349,920
    • MD5:a5e81d1b3905ada0a6e35fd6c6a2e1f4
  • 今天早上从这里下载的(可能)更新版:http://www.microsoft.com/visualstudio/eng/downloads
    • 大小:50,352,408
    • MD5:d02dc8b69a702a47c083278938c4d2f1

两个安装程序的版本均为4.5.50709.17929,但内部主要区别在于netfx_Full.mzz文件。但是,使用7-zip提取内容后,即使文件内容不同(我随机检查了约20个文件中的约426个),但最终得到的许多文件版本都相同,因此我无法确定哪个是更新版。

是否有一种可靠的方法来检测已安装的.NET 4.5运行时的实际版本,以便仅在确实需要时运行设置?

更新

我检查了所有内容不同的426个文件,两个安装程序中所有这些文件的ProductVersion和FileVersion都相同。因此,接下来可以使用注册表或文件校验和。

更新2

注册表中列出的版本对于两个安装程序均为4.5.50709

更新3

.NET 4.5.2现已发布:

这个版本的.NET框架可以与.NET Framework 3.5 SP1及之前的版本共存,但会对.NET Framework 4、.NET Framework 4.5和.NET Framework 4.5.1进行就地更新。


2
如果它们都安装了某种形式的.NET 4.5,那么你的问题是什么? 您可以使用注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP检查“net 4.5”。 - wal
我想安装最新版本,同时避免重新安装“以确保”。请参考丹尼尔的答案,了解使用最新版本的好处。 - alexandrul
1
好的,现在我唯一能建议的是在同一台计算机上或不同的计算机上安装两个版本并比较注册表中的位置(因为您已经说过两个安装的版本都相同)。还有一件事,您的客户或安装人员是否可能会使用随 SQL Server Data Tools 一起提供的 .NET4.5 安装程序? - wal
我真的无法确定,因为这不是一个受控环境,足够多的用户可以安装他们需要的任何东西。 - alexandrul
5个回答

112
最近,微软修补了.NET 4.5以恢复与某些情况下的.NET 4.0的向后兼容性(请参阅http://blogs.msdn.com/b/dotnet/archive/2012/10/17/net-framework-4-5-off-to-a-great-start.aspx)。
可能是微软更新了这些更改的安装程序(以便升级到.NET 4.5的用户不会遇到兼容性问题),尽管我不知道为什么他们不会在安装程序上更改版本号。
此外,请注意.NET版本号和由System.Environment.Version报告的运行时版本号之间存在差异。对于.NET 4.5,后者仍然是4.0.30319.*,只有修订号发生了变化(随着.NET 4.5更新以及每个安全更新)。
以下是一些已观察到的运行时版本示例:
基础4.0
  • 4.0.30319.1 = .NET 4.0 RTM
  • 4.0.30319.269 = .NET 4.0 在 Windows XP SP3、7、7 SP1 上 (带有 MS12-035 GDR 安全更新)
  • 4.0.30319.276 = .NET 4.0 在 Windows XP SP3 上 (4.0.3 运行时更新)
  • 4.0.30319.296 = .NET 4.0 在 Windows XP SP3、7 上 (带有 MS12-074 GDR 安全更新)
  • 4.0.30319.544 = .NET 4.0 在 Windows XP SP3、7、7 SP1 上 (带有 MS12-035 LDR 安全更新)
  • 4.0.30319.1008 = .NET 4.0 在 Windows XP SP3、7、7 SP1 上 (带有 MS13-052 GDR 安全更新)
  • 4.0.30319.1022 = .NET 4.0 在 Windows XP SP3、7、7 SP1 上 (带有 MS14-009 GDR 安全更新)
  • 4.0.30319.1026 = .NET 4.0 在 Windows XP SP3、7、7 SP1 上 (带有 MS14-057 GDR 安全更新)
  • 4.0.30319.2034 = .NET 4.0 在 Windows XP SP3、7、7 SP1 上 (带有 MS14-009 LDR 安全更新)

4.5

  • 4.0.30319.17626 = .NET 4.5 RC(开发版)
  • 4.0.30319.17929 = .NET 4.5 RTM(正式版)
  • 4.0.30319.18010 = .NET 4.5 在 Windows 8 上
  • 4.0.30319.18052 = .NET 4.5 在 Windows 7 SP1 64位上
  • 4.0.30319.18063 = .NET 4.5 在 Windows 7 SP1 64位上(带有 MS14-009 安全更新)

4.5.1

  • 4.0.30319.18408 = 在Windows 7 SP1 64位上使用.NET 4.5.1
  • 4.0.30319.18444 = 在Windows 7 SP1 64位上使用.NET 4.5.1(带有MS14-009安全更新)
  • 4.0.30319.34014 = 在Windows 8.1 64位上使用.NET 4.5.1

4.5.2

  • 4.0.30319.34209 = Windows 7 SP1 64位上的.NET 4.5.2
  • 4.0.30319.34209 = Windows 8.1 64位上的.NET 4.5.2

4.6及更高版本

  • 4.0.30319.42000
我在Windows更新历史记录中没有看到任何.NET更新,所以我猜v18010的更新是作为KB 2756872的一部分安装的。
更新:显然微软由于原始下载中数字签名的错误而更新了.NET 4.5设置。KB 2770445

首先,非常感谢您提供的信息(我给您点赞 +1)。我知道有关 System.Environment.Version 的“问题”,但是我可以忍受它。由于对我而言运行更新安装程序比寻找热修复程序更容易,因此我有兴趣检测是否需要运行“最新”的安装程序(检查给定 dll/exe 的 md5 摘要不太可靠)。 - alexandrul
两个安装程序中包含的许多文件都是“4.0.30319.17929”。 - alexandrul
4.0.30319.544是.NET 4.0的安全更新:http://support.microsoft.com/kb/2604121 - BrianH
@alexandrul:今天在查看Windows更新时,我找到了这个问题的解决方案:KB 2770445。其中提到,.NET 4.5安装程序下载已于2012年10月9日进行了更新。 - Daniel
@Daniel:那个KB链接只连接到网络安装程序 :( - alexandrul
5
注意:在.NET 4.6中,Environment.Version 返回的是“4.0.30319.42000”。 - Wai Ha Lee

4
public class DA {
    public static class VersionNetFramework {
        public static string Get45or451FromRegistry()
        {//https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx
            using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\"))
            {
                int releaseKey = Convert.ToInt32(ndpKey.GetValue("Release"));
                if (true)
                {
                    return (@"Version: " + CheckFor45DotVersion(releaseKey));
                }
            }
        }
        // Checking the version using >= will enable forward compatibility, 
        // however you should always compile your code on newer versions of
        // the framework to ensure your app works the same.
        private static string CheckFor45DotVersion(int releaseKey)
        {//https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx
            if (releaseKey >= 394271)
                return "4.6.1 installed on all other Windows OS versions or later";
            if (releaseKey >= 394254)
                return "4.6.1 installed on Windows 10 or later";
            if (releaseKey >= 393297)
                return "4.6 installed on all other Windows OS versions or later";
            if (releaseKey >= 393295)
                return "4.6 installed with Windows 10 or later";
            if (releaseKey >= 379893)
                return "4.5.2 or later";
            if (releaseKey >= 378758)
                return "4.5.1 installed on Windows 8, Windows 7 SP1, or Windows Vista SP2 or later";
            if (releaseKey >= 378675)
                return "4.5.1 installed with Windows 8.1 or later";
            if (releaseKey >= 378389)
                return "4.5 or later";

            return "No 4.5 or later version detected";
        }
        public static string GetVersionFromRegistry()
        {//https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx
            string res = @"";
            // Opens the registry key for the .NET Framework entry.
            using (RegistryKey ndpKey =
                RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "").
                OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
            {
                // As an alternative, if you know the computers you will query are running .NET Framework 4.5 
                // or later, you can use:
                // using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, 
                // RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"))
                foreach (string versionKeyName in ndpKey.GetSubKeyNames())
                {
                    if (versionKeyName.StartsWith("v"))
                    {

                        RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName);
                        string name = (string)versionKey.GetValue("Version", "");
                        string sp = versionKey.GetValue("SP", "").ToString();
                        string install = versionKey.GetValue("Install", "").ToString();
                        if (install == "") //no install info, must be later.
                            res += (versionKeyName + "  " + name) + Environment.NewLine;
                        else
                        {
                            if (sp != "" && install == "1")
                            {
                                res += (versionKeyName + "  " + name + "  SP" + sp) + Environment.NewLine;
                            }

                        }
                        if (name != "")
                        {
                            continue;
                        }
                        foreach (string subKeyName in versionKey.GetSubKeyNames())
                        {
                            RegistryKey subKey = versionKey.OpenSubKey(subKeyName);
                            name = (string)subKey.GetValue("Version", "");
                            if (name != "")
                                sp = subKey.GetValue("SP", "").ToString();
                            install = subKey.GetValue("Install", "").ToString();
                            if (install == "") //no install info, must be later.
                                res += (versionKeyName + "  " + name) + Environment.NewLine;
                            else
                            {
                                if (sp != "" && install == "1")
                                {
                                    res += ("  " + subKeyName + "  " + name + "  SP" + sp) + Environment.NewLine;
                                }
                                else if (install == "1")
                                {
                                    res += ("  " + subKeyName + "  " + name) + Environment.NewLine;
                                }
                            }
                        }
                    }
                }
            }
            return res;
        }
        public static string GetUpdateHistory()
        {//https://msdn.microsoft.com/en-us/library/hh925567(v=vs.110).aspx
            string res=@"";
            using (RegistryKey baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\Updates"))
            {
                foreach (string baseKeyName in baseKey.GetSubKeyNames())
                {
                    if (baseKeyName.Contains(".NET Framework") || baseKeyName.StartsWith("KB") || baseKeyName.Contains(".NETFramework"))
                    {

                        using (RegistryKey updateKey = baseKey.OpenSubKey(baseKeyName))
                        {
                            string name = (string)updateKey.GetValue("PackageName", "");
                            res += baseKeyName + "  " + name + Environment.NewLine;
                            foreach (string kbKeyName in updateKey.GetSubKeyNames())
                            {
                                using (RegistryKey kbKey = updateKey.OpenSubKey(kbKeyName))
                                {
                                    name = (string)kbKey.GetValue("PackageName", "");
                                    res += ("  " + kbKeyName + "  " + name) + Environment.NewLine;

                                    if (kbKey.SubKeyCount > 0)
                                    {
                                        foreach (string sbKeyName in kbKey.GetSubKeyNames())
                                        {
                                            using (RegistryKey sbSubKey = kbKey.OpenSubKey(sbKeyName))
                                            {
                                                name = (string)sbSubKey.GetValue("PackageName", "");
                                                if (name == "")
                                                    name = (string)sbSubKey.GetValue("Description", "");
                                                res += ("    " + sbKeyName + "  " + name) + Environment.NewLine;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                    }
                }
            }
            return res;
        }
    }
}

这个问题的来源是什么?我想将其更新到4.8.1版本,你的回答比微软官方答案(https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed)更完整,包括操作系统。 - Scott

2
如果有人需要根据 .net 版本获取 System.Environment.Version 值,并将其排列在一个表格中(需要使用 Excel 等进行 =Vlookup 操作),可以参考我创建的这个plunker。 进入上面的链接,您将能够复制此表格图片:enter image description here

1
你可以随时前往 Windows/Microsoft.net/Framework/4.0.30319 并查看 system.dll 文件...右键属性,然后查看详细信息...应该会显示版本号... 4.5.2 版本的 system.dll

你确定这是真的吗?我查看了一下,.NET DLLs 的版本号不同。2016年3月9日:system.dll 是4.0.30319.34239,而System.Web.Dll则是4.0.30319.34274。最好在资源管理器中添加“文件版本”列,并按照该列进行排序。 - SQL Police

0

您可以使用PowerShell获取所有已安装的版本:

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 | Select -ExpandProperty Version | Sort-Object Version

前面的PowerShell命令将查看注册表键并按版本降序打印所有键。

输出示例:

4.8.03761
3.5.30729.4926
4.0.0.0
4.8.03761
3.0.30729.4926
2.0.50727.4927
3.0.6920.4902
3.0.4506.4926

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接