Help us understand the problem. What is going on with this article?

Windows Management Instrumentation を簡単に得られるツール wmi2struct

WMI とは

Windows PC やサーバから色々な情報を得る方法として Microsoft は WMI(Windows Management Instrumentation) を提供しています。

これらの情報は WMI クラスという構造で格納された形式で提供され、数多くのクラスが用意されています。

https://docs.microsoft.com/en-us/windows/desktop/wmisdk/wmi-system-classes

wmic コマンド

コマンドラインからは wmic というツールを使いこれらの情報に簡単にアクセス出来る様になっています。

WMIC

ちょっと確認するには wmic コマンドは便利です。wmic コマンドには一応、CSV もしくは XML 形式で出力するオプションが付いているのですが、プログラムからは非常に扱い辛い物になっています。また型もないので出力内容を WMI クラスの定義に従って変換しないといけない訳です。そこで便利なのが StackExchange/wmi です。

StackExchange/wmi パッケージ

https://github.com/StackExchange/wmi

StackExchangeStackOverflow と同じ会社が運営している FAQ サイトです。StackOverflow は Web サービスの多くを Windows サーバで運用している珍しい会社として有名ですが、内部のリソース管理に Go 言語で書かれたシステムを使っています。そのシステムで使われているのが StackExchange/wmi です。StackExchange/wmi は内部で COM を使っています。ちなみに Go から COM を扱う方法として go-ole という筆者が開発しているパッケージがあるのですが、wmi はこの go-ole を使ったパッケージになっています。

使い方はとても簡単で、SQL の様な WMI クエリを発行して WMI クラスのレコードを取り出します。

package main

import (
    "fmt"
    "log"

    "github.com/StackExchange/wmi"
)

type Win32ComputerSystemProduct struct {
    Caption           string
    Description       string
    IdentifyingNumber string
    Name              string
    SKUNumber         *string
    UUID              string
    Vendor            string
    Version           string
}

func main() {
    var records []Win32ComputerSystemProduct
    err := wmi.Query("SELECT * FROM Win32_ComputerSystemProduct", &records)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(records[0].Vendor)
}

Win32_ComputerSystemProduct はコンピュータの製品情報を得られるクラスです。この例であれば僕のノート PC は HP 製なので Hewlett-Packard と表示されます。

さて、この Win32_ComputerSystemProduct というクラスはブラウザを起動してググって Microsoft のページに辿り着ければ誰でも構造を得られます。

https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-computersystemproduct

[Dynamic, Provider("CIMWin32"), UUID("{FAF76B96-798C-11D2-AAD1-006008C78BC7}"), AMENDMENT]
class Win32_ComputerSystemProduct : CIM_Product
{
  string Caption;
  string Description;
  string IdentifyingNumber;
  string Name;
  string SKUNumber;
  string Vendor;
  string Version;
  string UUID;
};

なるほど C# で書かれていています。これをチマチマと上記の様に Go に置き換える必要があります。なかなか面倒そうですね。

wmi2struct

そこで登場するのがこの記事の主役、wmi2struct です。

https://github.com/mattn/wmi2struct

wmi2struct はコマンドラインアプリケーションです。使い方は以下の通り。

Usage of wmi2struct:
  -l    list all classes
  -n    output number fields
  -o string
        output filename
  -p string
        package (default "main")

-l オプションを付けて起動すると、その PC で取得可能な WMI クラスの一覧が表示されます。

略
Win32_SystemTrace
Win32_ProcessTrace
Win32_ProcessStartTrace
Win32_ProcessStopTrace
Win32_ThreadTrace
Win32_ThreadStartTrace
Win32_ThreadStopTrace
Win32_ModuleTrace
Win32_ModuleLoadTrace
Win32_PowerManagementEvent
Win32_ComputerSystemEvent
Win32_ComputerShutdownEvent
略

では例えば上記で使った Win32_ComputerSystemProduct を引数に渡してみます。

C:\>wmi2struct Win32_ComputerSystemProduct
package main

// Win32_ComputerSystemProduct is struct for WMI
type Win32_ComputerSystemProduct struct {
    Caption           string
    Description       string
    IdentifyingNumber string
    Name              string
    SKUNumber         string
    UUID              string
    Vendor            string
    Version           string
}

なんと C# のソースだった Win32_ComputerSystemProduct が Go の形式で出力されているではないですか!便利!

あとはこれを Go のソースとして保存し、上記の様に wmi.Query を実行するだけなのです。超便利!

一応、1点だけ注意点があり、Go の string は C# の string の様に nil(null) が格納出来ません。もし WMI クラスの値として nil が格納される可能性があるのであれば、そのフィールドを *string として宣言して下さい。wmi パッケージがよろしく変換して実行してくれます。今回の例であれば、SKUNumber が nil を持ち得るフィールドになります。

type Win32_ComputerSystemProduct struct {
    Caption           string
    Description       string
    IdentifyingNumber string
    Name              string
    SKUNumber         *string
    UUID              string
    Vendor            string
    Version           string
}

まとめ

今回は WMI クラスを扱えるパッケージ StackExchange/wmi と、それに渡すべき struct を簡単に生成できるツール wmi2struct を紹介しました。PC に格納されている色々な情報を簡単に得られるのでぜひお使い下さい。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away