インストールされている全ての .NET Framework のバージョンを列挙する

# はじめに
システム運用管理の現場ではソフトウェアのバージョン調査という作業が度々発生します。理想的には設計書などのドキュメントに記載されているはずですが、実機とドキュメント情報が乖離していることは少なくありません。そのため、例えばセキュリティパッチがリリースされれば適用要否を判断するために運用されている全サーバ（！）でバージョン調査を実施する必要に迫られるのです。

この記事では Windows OS に標準的に搭載されている .NET Framework について、レジストリから詳細なバージョン情報を取得する方法をまとめます。

# 課題

.NET Framework は Windows OS に標準的に搭載されているソフトウェアです。.NET Framework のバージョン情報は A.B.C.D 形式で表されますが、コントロールパネルの「プログラムと機能」からは確認できません。正確なバージョン情報を確認するためにはレジストリを見る必要があります。

.NET Framework のバージョン情報が格納されているレジストリキーは以下の通りです[^ref2]。

```:バージョン1から4の場合
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\{Version}
```

```:バージョン4.5以上の場合
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
```

バージョン1から4の場合は、レジストリキーにバージョン番号(`{Version}`)が含まれています。面倒なことに、正確なバージョンを知るためにはバージョンの情報が必要になるのです。これは `reg` コマンドでバージョン情報を取得しようとする場合に問題になります。なぜならインストールされる可能性のある全てのバージョンについて `reg` コマンドを実行しなければならないからです。どのようなバージョン名のキーがあるのかを事前に把握しておくことは難しいので、網羅しようとする場合は `for` コマンドが必要になります。

参考に `for` コマンドを使う場合の例をあげます。

```cmd
C:\> for /f "usebackq tokens=*" %k in (`reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP"`) do @(reg query "%k" | find "Version")
    Version    REG_SZ    2.0.50727.4927
    Version    REG_SZ    3.0.30729.4926
    Version    REG_SZ    3.5.30729.4926
```

一方で、バージョン4.5以上の場合は、レジストリキーは固定されています（ただし、キーに v4 が含まれるので今後 v5 が現れるかもしれません）。ただし、こちらはバージョンを表す数値（ID?）が格納されており、バージョンを知りたい場合は数値とバージョン番号の照合が必要です。

参考に、私の PC での実行結果を挙げます。

```cmd
C:\> reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
    CBS    REG_DWORD    0x1
    Install    REG_DWORD    0x1
    InstallPath    REG_SZ    C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
    Release    REG_DWORD    0x60632
    Servicing    REG_DWORD    0x0
    TargetVersion    REG_SZ    4.0.0
    Version    REG_SZ    4.6.01586
```

上記の「バージョンを表す数値」が `Release` であるという点に注意してください。`reg` コマンドの出力結果には `Version` が含まれていますが、そこには `4.6.0...` と表示されています。しかし `Release` が示している（正確な）バージョンは `4.6.2` です[^ref]。

コマンドプロンプトを使う場合、`reg` コマンドの結果から `Release` の値を切り出し、照合してバージョン名を出力するには複雑なコマンドを使わざるを得ません。

# 解決方法

レジストリの情報を取得するには PowerShell を使うことができます。PowerShell はコマンドプロンプトと比較して、高級な構文を備えているため、複雑な処理でも読みやすく記述することができます。

以下は、.NET Framework のバージョン情報をレジストリから取得するための PowerShell スクリプトとその実行結果の例です。

```PowerShell
ls -r "HKLM:\software\microsoft\net framework setup\ndp" | % {
    $_.GetValue("Version") | ? { $_ } | % {
        New-Object PSObject | 
            Add-Member NoteProperty -PassThru -Name "Type" -Value "Version" |
            Add-Member NoteProperty -PassThru -Name "Value" -Value $_
    }
    $_.GetValue("Release") | ? { $_ } | % {
        switch ($_) {
            "378389" { $r = "4.5" }
            "378675" { $r = "4.5.1 installed with Windows 8.1 or Windows Server 2012 R2" }
            "378758" { $r = "4.5.1 installed on Windows 8, Windows 7 SP1, or Windows Vista SP2" }
            "379893" { $r = "4.5.2" }
            "393295" { $r = "4.6 installed on Windows 10" }
            "393297" { $r = "4.6" }
            "394254" { $r = "4.6.1 installed on Windows 10 Novermber Update" }
            "394271" { $r = "4.6.1" }
            "394802" { $r = "4.6.2 installed on Windows 10 Anniversary Update" }
            "394806" { $r = "4.6.2" }
            "460798" { $r = "4.7 installed on Windows 10 Creators Update" }
            "460805" { $r = "4.7"}
            "461308" { $r = "4.7.1 installed on Windows 10 Fall Creators Update"}
            "461310" { $r = "4.7.1"}
            "461808" { $r = "4.7.2 installed on Windows 10 April 2018 Update"}
            "461814" { $r = "4.7.2"}
            "528040" { $r = "4.8 installed on Windows 10 May 2019 Update"}
            "528049" { $r = "4.8"}
            default { $r = "Unknown: $_" }
        }
        New-Object PSObject |
            Add-Member NoteProperty -PassThru -Name "Type" -Value "Release" |
            Add-Member NoteProperty -PassThru -Name "Value" -Value $r
    }
} | Sort -Unique -Property Value

```

```:実行結果の例
Type    Value
----    -----
Version 2.0.50727.4927
Version 3.0.30729.4926
Version 3.0.30729.8763
Version 3.0.4506.4926
Version 3.0.6920.4902
Version 3.5.30729.4926
Version 4.0.0.0
Version 4.6.01586
Release 4.6.2 installed on Windows 10 Anniversary Update
```

# おわりに

.NET Framework は、レジストリにバージョン情報を持ち、且つバージョン情報の格納されるキーの規則が複雑でした。しかし PowerShell の特性を利用して、シンプルなスクリプトでバージョン情報を列挙することができました。

# 参考記事
[^ref]: [How to: Determine Which .NET Framework Versions Are Installed](https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx)
[^ref2]: [方法 : インストールされている .NET Framework バージョンを確認する](https://msdn.microsoft.com/ja-jp/library/hh925568(v=vs.110).aspx)