もくじ
https://tera1707.com/entry/2022/02/06/144447
やりたいこと
WMIでなにか値をとりたいなと思ったときに、どのクラスからどんな値が取れるのかがわからないので、いつも出だしで困る。
あまり良いやり方ではないかもしれないが、とりあえずもう全部のWMIで取れる値を全部取ってしまってから、その中になんか目的のあたいっぽいのがないかなー?という調べ方をしたい。
で、そのために、全部のクラス(のインスタンス?)から、全部のプロパティの値をとって全部表示するようなことがしたい。
※WMIのクラス、とか、インスタンス、とか、プロパティ、とか言っているが、それが用語として正しいのかはっきりわかってないのが今の現状。ゆえにそんな変な調べ方しかできないのだが、知識を付けるのは追々やるとして、いったんそういう変なことができるのかどうか調べてみる。。。
※以前も、似たようなことを言っていて、そのときはWbemTestというツールを使ってみた。(が、以前目的のモノにすぐたどり着けない。。。)
https://zenn.dev/tera1707/articles/87bf99621770e1
やったこと
ObjectQuery()をnewするときに、
var query = new ObjectQuery("SELECT * FROM meta_class");
というクエリにする(FROMにmeta_class
を指定する)と、WMIのクラスを全部取ってこれる様子。
下のコードのようにすれば、全部のインスタンスの値が取れてるっぽい。
つまり、Wim32_BIOS
とかWin32_ComputerSystem
とか、もろもろいつも使うようなクラスの値が全部とれてるっぽい。
ぽい、というのは、下記のコードを実行すると、途中でクォータ違反です
というエラーが出てしまい、途中で終わってしまい、全部みれないため。
※どうも、連続して大量にWMIでデータをとると、そういうエラーになるらしい。
public void GetInfo() { var scope = new ManagementScope("\\\\.\\ROOT\\cimv2"); //var query = new ObjectQuery("SELECT * FROM Win32_ComputerSystem"); var query = new ObjectQuery("SELECT * FROM meta_class"); var searcher = new ManagementObjectSearcher(scope, query); using (ManagementObjectCollection queryCollection = searcher.Get()) { try { foreach (ManagementObject mo in queryCollection) { Console.WriteLine($"■{mo.ClassPath}"); if (mo.ClassPath.ToString().Contains("Win32_LocalTime") || mo.ClassPath.ToString().Contains("Win32_NTLogEvent") || mo.ClassPath.ToString().Contains("Win32_SoftwareElement")) continue; ManagementClass mc = new ManagementClass(mo.ClassPath); foreach (ManagementObject c in mc.GetInstances()) { Console.WriteLine($" ▼{c.ClassPath}"); PropertyDataCollection props = c.Properties; // WMIのオブジェクトのプロパティを列挙する foreach (PropertyData p in props) { Console.WriteLine($" {p.Name,-30} : {p.Value}"); } c.Dispose(); } mo.Dispose(); } } catch (Exception ex) { Console.WriteLine(ex); } } searcher.Dispose(); Console.WriteLine("finished......."); }
で、途中で落ちるのでは困る。
なので、上記コードでコメントアウトしている
//var query = new ObjectQuery("SELECT * FROM Win32_ComputerSystem"); var query = new ObjectQuery("SELECT * FROM meta_class");
の部分を反対にして、Win32_ComputerSystem
の情報を取るようにしてやると、まぁWin32_ComputerSystem
に含まれる値はうまいこと取れる。
本番でWMIでデータをとるときは、全部とってくるようなことはしないので、結局大体使えそうなクラスを見定めておいて、SELECT * FROM 使えそうなクラス名
にするしかなさそう。
※ちなみに、私のPCで上記コードを実行すると、400万行以上のテキストになった。 本番で使いそうなクラスの値は、たまたま含まれていたが、途中では終わっている様子。
使えそうなクラス名を探すとき
上のコードの、プロパティを全部とる部分を消して、
public void GetInfo() { var scope = new ManagementScope("\\\\.\\ROOT\\cimv2"); var query = new ObjectQuery("SELECT * FROM meta_class"); var searcher = new ManagementObjectSearcher(scope, query); using (ManagementObjectCollection queryCollection = searcher.Get()) { foreach (ManagementObject mo in queryCollection) { Console.WriteLine($"■{mo.ClassPath}"); mo.Dispose(); } } searcher.Dispose(); Console.WriteLine("finished......."); }
としてやると、クラス名は全部取れる様子。
wbemtestのツールと、上記で吐いたクラス一覧を合わせてみるしかないか。。。。
※上記で吐いたクラスだけの一覧は、私のPCでは1300行程度だった。
ManagementClassを使わないと中身がnullになる ← 追記:間違いだった ←追記:やっぱり間違いじゃなかった(nullになる)
以前調べた、WMIでCPU時間を取る方法のコードと今回のコードだと、foreach (ManagementObject mo in queryCollection)
の中で、
今回は
ManagementClass mc = new ManagementClass(mo.ClassPath); foreach (ManagementObject c in mc.GetInstances()) {・・・
という感じで、ManagementClassをnewして、そいつでGetInstanceをしている部分がことなる。 (CPU時間のときは、それがなかった)
今回は、Win32_ComputerSystem
クラスのプロパティの値を取りたかったのだが、ManagementClass
を使わないと(前回のように、searcher.Get()でとったManagementObjectCollection の中身を直接見る感じだと)、Win32_ComputerSystem
のプロパティの値は全部nullだった。
ManagementObjectCollection queryCollection = searcher.Get(); foreach (ManagementObject m in queryCollection) { // WMIオブジェクトのプロパティを取得して表示 Console.WriteLine("{0}, {1}, {2}, {3}, {4}", m["Name"], m["IDProcess"], m["PercentProcessorTime"], m["PrivateBytes"], (uint.Parse(m["IOWriteBytesPerSec"].ToString()))); }
クラス(ガワ)には中身の値がないけど、とインスタンス(中身)にはある、みたいな違いがあるのかもしれない。
※現状、勉強不足でよくわかっていない。(CPU時間はそれでとれてたのに、なぜ今回はnullなのか、等)
ManagementClassを使わなくても値が取れた
ManagementClassを使わないと中身がnullになる、は間違いだった。 WMIでCPU時間を取る方法のコードと似たやり方で、値もとれた。
実験していたときに、なにか変なことをしていたっぽい。
下記で、うまく取れた。
public void GetInfo() { var scope = new ManagementScope("\\\\.\\ROOT\\cimv2"); var query = new ObjectQuery("SELECT * FROM Win32_ComputerSystem"); //var query = new ObjectQuery("SELECT * FROM meta_class"); var searcher = new ManagementObjectSearcher(scope, query); using (ManagementObjectCollection queryCollection = searcher.Get()) { try { foreach (ManagementObject mo in queryCollection) { Console.WriteLine($"■{mo.ClassPath}"); PropertyDataCollection props = mo.Properties; foreach (PropertyData p in props) { Console.WriteLine($" {p.Name,-30} : {p.Value}"); } mo.Dispose(); } } catch (Exception ex) { Console.WriteLine(ex); } } searcher.Dispose(); Console.WriteLine("finished......."); }
※やっぱり、その後もう一度試したらまた値が空になっていた。 なにか条件がある??一度インスタンス取得したら、そのあとはインスタンス取らなくても値が入ってる、とか?
備考
WMIについての知識がたりないせいで、なにか無理やり感、頓珍漢なことしてる感を感じる。
おいおい勉強必要。
参考
全部のWMIのクラス?を取ってくる https://mycsharp.de/forum/threads/69845/lan-adapter-auslesen?page=1
PropertyData クラス https://learn.microsoft.com/ja-jp/dotnet/api/system.management.propertydata?view=dotnet-plat-ext-7.0
WMI クラスの取得
https://learn.microsoft.com/ja-jp/windows/win32/wmisdk/retrieving-a-class
WMI インスタンスの取得
https://learn.microsoft.com/ja-jp/windows/win32/wmisdk/retrieving-an-instance