[PS]WMIの取り扱いについて

暫く更新が滞っていました。私事で忙しかったせいですが、今回はPowerShellとWMIで気がついた点を記載します。

Windows Vistaを使ってPowerShellでインストールされたソフトウェアの一覧を表示しようとして、WMIのWin32_Productクラスを使ってみました。

 PS (1) >Get-WmiObject Win32_Product

Get-WmiObject : エラーです
発生場所 行:1 文字:14
+ Get-WmiObject  <<<< Win32_Product

このようにエラーになってしまいました。一部のソフトウェアが表示される場合もありますが、必ず「Get-WmiObject : エラーです」となってしまいます。色々と調べていくと、Windows Vista のWMIのWin32_Productクラスのバグらしいということが判明しました。この情報はネットニュースのpowershellの中にありました。この内容を見ると既知のバグでVista SP1で修正される予定だと書かれています。じゃあ、他の方法を使わないとWindows Vistaでインストール済みのソフトウェアの一覧を取得できないことになります。で思いついたのが

  • レジストリを列挙する。
  • Windows Installer APIを使用する。

という方法です。今回は、Windows Installer APIを使用してみたいと思います。

 PS (2) >$wi = New-Object -ComObject WindowsInstaller.Installer
PS (3) >$wi | Get-Member


   TypeName: System.__ComObject

Name                      MemberType Definition
----                      ---------- ----------
CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(
Type requestedType)
Equals                    Method     System.Boolean Equals(Object obj)
GetHashCode               Method     System.Int32 GetHashCode()
GetLifetimeService        Method     System.Object GetLifetimeService()
GetType                   Method     System.Type GetType()
InitializeLifetimeService Method     System.Object InitializeLifetimeService()
ToString                  Method     System.String ToString()

このようにWindows Installer のCOMオブジェクトには、何故か実装されているはずのメンバーが見当たりません。何故かなぁと思って調べていくと、タイプライブラリにcoclassが定義されていないようです。このためにNew-Objectコマンドレットでは、プロパティやメソッドをマップできないようです。解決策はないのかなと思って調べていくと、Abhishek's PowerShell Blogが見つかりました。この内容を参考に以下のようなスクリプトを作成しました。

 # COMオブジェクトを作成する
Function Global:GetComObject($ProgID)
{
  New-Object -ComObject $ProgID
}

# プロパティを呼び出す
Function Global:GetPropFromCom($obj, $PropertyName)
{
  # $obj:COMオブジェクト
  # $PropertyName:プロパティ名
  # $Args:パラメータを必要とするプロパティ
  If ( -Not ($obj -is [System.__ComObject]))
 { Throw "__ComObjectではありません"; Return }
  # System.Typeを取得して、プロパティを呼び出す
  $type = $obj.GetType()
  $type.InvokeMember( $PropertyName, 
[System.Reflection.BindingFlags]::GetProperty ,
 $null, $obj, $args)
}

System.Typeのインスタンスを生成してプロパティをInvokeするというのがこのスクリプトです。これを使って以下のように実行すれば、問題なくインストール済みのソフトウェアの一覧を取得することができます。

 PS (10) >$wi = GetComObject WindowsInstaller.Installer
PS (11) >$ps = GetPropFromCom $wi Products
PS (12) >ForEach ($i in $ps)
>> {  GetPropFromCom $wi ProductInfo $i ProductName }
>>
Cardmod_x86 and MSITPintool
Microsoft ASP.NET Futures (May 2007)
Microsoft ASP.NET 2.0 AJAX Extensions 1.0
以下続く