Installerフォルダーの肥大化#3 インストーラーの列挙

前回の投稿までに、Installerフォルダーのファイルの列挙ができ、使用容量の確認までしました。今回は、実際に使われているファイルの分別をしたいと思います。

インストーラーの列挙方法

インストール済みのインストーラを列挙するにはどうすればよいでしょうか?

Uninstallレジストリ

ユーザーがWindows上で確認できるところでは、

  • 「設定」アプリの「ホーム→アプリ→アプリと機能」(Windows 10のみ)
  • コントロールパネルの「プログラム→プログラムと機能→プログラムのアンインストールまたは変更」(Windows Vista/7/8.0/8.1/10)
  • コントロールパネルの「プログラムの追加と削除→プログラムの変更と削除」(Windows XP)

があります。

この情報は、64ビットWindowsの場合、レジストリの以下の場所にあります。

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
  • HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall

なお、32ビットWindowsの場合は、前者の場所(WOW6432Nodeが無い方)のみです。

しかしながら、ここに列挙されているインストール済みのインストーラーは、Windows Installer技術を使ったインストーラーすべてが表示されているわけではありません。一部のインストーラーしか表示されていません。

Windows Installer技術を使ったインストーラーの列挙API

Windows Installer技術を使ったインストーラーは、Win32 APIを使うと列挙できます。具体的には、Windows Installer関数(Windows Installer Function(英語))の中のシステム状態関数(System Status Functions(英語))を使います。この中のMsiEnumProductsEx()などを利用して、インストーラーの列挙をします。

ただし、これらは、Win32 Native APIのため、C#などの.NET Frameworkアプリから使うときは、オートメーション インターフェース(Automation Interface(英語))を使ってアクセスした方が容易です。

この中の、Installerオブジェクト(Installer Object(英語))を使い、Installer.ProductsExプロパティ(Installer.ProductsEx Property(英語))で列挙できます。

アプリでインストーラーの列挙

オートメーション インターフェース(Automation Interface(英語))を使い、Installer Adjustment App(インストーラ調整アプリ)にインストーラーの列挙機能を追加しました。列挙機能が追加されたアプリはバージョン0.2.0以降です。

アプリを起動しただけでは、インストーラーの一覧は表示されません。上部の「Installerフォルダーを解析する」ボタンをクリックするとインストーラーの列挙を開始します。インストーラーの列挙には、長い時間がかかります。列挙中は、プログレスバーが表示されるとともに、インストーラー一覧の上にある数字がカウントアップされていきます。

インストーラーの製品一覧

この例では、二つのインストーラーがインストール済みであることがわかります。

この一覧には、インストーラー名、インストーラーのサイズ(全体のサイズ、単体のサイズ、更新ファイルのサイズ)、インストーラーファイル(msiファイル)の場所、インストーラーのプロダクトコードなどが表示されます。

インストーラーの一覧は、上部のヘッダ部をクリックすることにより、昇順または、降順に並べ替えができます。

未使用ファイル・フォルダーの判別

インストーラーの列挙をすることはできました。次はこの情報を利用して、Installerフォルダー内のファイルの中で使用されていないファイルを判別します。

インストーラーファイル

インストーラー情報からは、インストーラーごとに、インストーラー本体(1個のmsiファイル)とインストーラー更新ファイル(0個以上のmspファイル)、インストーラーのIDであるプロダクトコードの情報などが得られます。プロダクトコードは、システム内でインストーラーを区別するためにインストーラーごとに割り当てられているIDとなります。これらの情報を使って、使用中のファイルおよび使用中のフォルダーを判別します。

具体的には、インストーラー情報から参照されている、以下のファイルを使用中として判断します。

  • インストーラー本体(msiファイル, C:\Windows\Installer\xxxxxx.msi)
  • インストーラー更新ファイル(mspファイル, C:\Windows\Installer\xxxxxx.msp)

これらのファイル名はインストーラーごとに固定のファイル名ではなく、ランダムに作成されたファイル名です。これらの情報は、インストーラー情報からフルパスで取得できます。取得できたパスのインストーラーファイルは使用中として判断します。

プロダクトコード関連のファイルとフォルダー

また、プロダクトコードをファイル名の一部とする以下のファイルとフォルダーを使用中として判断します。

  • C:\Windows\Installer\SourceHash{GUID} ファイル
  • C:\Windows\Installer\{GUID} フォルダー
  • C:\Windows\Installer\wix{GUID}.SchedService.Config.rmi ファイル

これらは、インストーラーが上記のファイル名やフォルダー名が使用されていることがわかったからです。そのため、該当するファイルやフォルダーは使用中として判断します。

$PatchCache$ フォルダー

最後に特殊なフォルダーである C:\Windows\Installer\$PatchCache$ フォルダー内のファイルが使用中であるかを判断する方法です。このフォルダーの配下には、インストールするファイルのキャッシュが保存されているようです。フォルダー名にはプロダクトコード(GUID)を変形したパックGUID(Packed GUID)形式の名前が使用されています。

パックGUID (Packed GUID)

パックGUID(Packed GUID) とは、どんなものなのでしょうか?

パックGUID(Packed GUID)は、人によっては、圧縮GUID(Compressed GUID)やSQUID(squished GUID)といっている人がいます。

このパックGUIDは、GUIDの値の順番を入れ替えることにより生成できます。GUIDは、C/C++では以下の構造体で表現できます。

typedef struct _GUID {
  DWORD Data1;      // 12345678-
  WORD Data2;       // 1234-
  WORD Data3;       // 1234-
  BYTE Data4[8];    // 1212-121212121212
} GUID;

このように、GUIDはDWORD, WORD, WORD, 8個のBYTEデータで構成されます。パックGUIDは、それぞれのデータごとに4ビット(ニブル)単位で左右を入れ替えた形になります。

例えば、GUIDが {12345678-ABCD-EFGH-1234-567890ABCDEF} のとき、以下の手順で変換します。

手順GUIDをPacked GUIDに変換
1. GUID{12345678-ABCD-EFGH-1234-567890ABCDEF}
2. DWORD内の順番の入れ替え{12345678-ABCD-EFGH-1234-567890ABCDEF}
3. 2個のWORD内の順番の入れ替え{87654321-ABCD-EFGH-1234-567890ABCDEF}
4. 8個のBYTE内の順番の入れ替え{87654321-DCBA-HGFE-1234-567890ABCDEF}
5. 括弧とハイフンを削除{87654321-DCBA-HGFE-2143-658709BADCFE}
6. パックGUID(Packed GUID) 87654321DCBAHGFE2143658709BADCFE

変換したパックGUIDは、 87654321DCBAHGFE2143658709BADCFE となります。

インストーラーが使用する$PatchCache$フォルダー

インストーラーが使用する$PatchCache$フォルダーは、以下の形式のフォルダーです。

  • C:\Windows\Installer\$PatchCache$\Managed\PackedGUID\ フォルダー
  • C:\Windows\Installer\$PatchCache$\Unmanaged\SID\PackedGUID\ フォルダー

PackedGUIDは、プロダクトコードをパックGUID形式に変形した値です。SIDは、ユーザー単位でインストールしたインストーラーのユーザーSIDです。

こららのファイルは調査によりインストーラーによっては上記のフォルダー名が使用されていることがわかりました。そのため、該当するフォルダーは使用中として判断します。

アプリ上の未使用ファイル・フォルダーの一覧

これらのアルゴリズムで、使用中ファイル・使用中フォルダーを判断します。Installerフォルダー内にあるファイル・フォルダーから上記のファイル・フォルダーを除外したものを未使用ファイル・フォルダーとして判断します。アプリ上では、下記のように「未使用のファイルとフォルダー」として表示します。

未使用ファイルとフォルダー

この例では、未使用のファイルとフォルダーは、「0バイト、0ファイル」となっているので、インストール済みのインストーラーから参照されていない未使用ファイルは存在しないことになります。

使用中のインストーラーファイル

使用中のインストーラーファイルも簡単に確認できるように表示します。インストーラーファイルとは、インストーラー本体ファイル(msiファイル)とインストーラーの更新ファイル(mspファイル)です。

アプリ上では、下記のように「使用中のインストーラーファイル(msi/msp)」として表示します。

使用中のインストーラーファイル(msi/msp)

この例では、二つのmsiファイルがあり、合計が2.22MBであることがわかります。

Installer Adjustment App バージョン0.2.0

Installer Adjustment Appバージョン0.2.0では、インストール済みのインストーラーから参照されていないファイルを判別できるようになりました。ただし、まだ、不要ファイルなどを削除して、空き容量を増やすなどの機能はありません。また、システムから参照されているが、削除可能なファイルの検出もしていません。これらは順次検討していきたいと思います。


インターネットを検索すると、このアプリが最終的に目指す機能に似た機能を持つアプリがあることがわかりました。たとえば、PatchCleanerです。

次回は、このアプリの解析結果とPatchCleanerの解析結果を比較してみたいと思います。

One Reply to “Installerフォルダーの肥大化#3 インストーラーの列挙”

コメントを残す