[WMI] C++ で 2 つ以上の引数を与えてメソッドを実行するには? 1 / (2)

みなさん、大変ご無沙汰しておりました。ういこです。
しばらく心身ともに調子が悪く、ブログもやめようかな…と悩んでおりました。
しかし、会計年度も変わり、そろそろ年末も見えてきたあたりで復活しようかなと思いつつあります。またひとつよろしくお願いいたします。

なぜか前会計年度では Windows Media テクノロジーのサポートチームと同じチームでしたが (※ US も同じ構成ですが、いまだになぜ一緒なのか謎) 今期から Windows SDK のチームとさらにくっつき、最近は普通に API 案件などもやっていたりします。なぜ Windows Media と ILM / ADSI、Windows SDK が一緒なのか、それはきっと足が飾りだと思う必要がないレベルのえらい人にしかわからない何か事情があるんでしょう。というわけで、今後は SDK 案件も書いていくことになると思いますがよろしくお願いします。

…相変わらず前置き長くてすみません。本題に入らせていただきますです。
さて復活第一弾は、ILM ねたでいこうかなと思いましたが、現在稼働中の案件もいくつかあるので、あえて WMI を。…今回も文章、長いですよ…。というか、一回にしようと思いましたが、コード長すぎなんですみません。

続きはこちら。タイトル変えました。
[WMI] C++ で 2 つ以上の引数を与えてメソッドを実行するには? 2 / (2)
https://blogs.technet.com/jpilmblg/archive/2009/10/06/wmi-c-2-2-2.aspx

【お題 : C++ で WMI - メソッドに二つ以上引数を渡したいの】
WMI。それはシステム管理者様にとって、一見いいことずくめな感じなもの。スクリプトを気合で組めば、何だって自動化できちゃうぞ!人のマシンだってシャットダウンできちゃうぞ(※注 : それ相応のシステムの管理権限必要)!と、野望や夢も膨らむってもんですが、問題はえっらい遅いこと。
そんな「WMI 遅い」問題に果敢に挑み C++ で実装いただいている漢(おとこ)たちもいらっしゃいます。(あるいはこれまでの既存 C 資産に WMI を組み込む必要がある方々など…。)しかし、いかんせんコード量が多い。多いのです。スクリプトや、.NET Framework アプリとして C# や VB.net などで組んだ場合と比較してコード量が半端じゃありません。

何気に WMI はドキュメントが多いほうです。C++ も例外ではありません。英語ばっかりではあるものの拳でわかりあうように、コードをとりあえずコピペして動きに思いを馳せるってやりかたができるので割と敷居は低いほうのプロダクトです。
ただ、C++ の場合、メソッドを実行したいと思っても、複数個引数を与えるメソッド実行、どうやったらいいかって思ったことありませんか?今回は、C++ で WMI、複数引数でメソッド実行について、Msvm_shutdownComponent の InitiateShutdown() メソッドを例にとり、二回に分けてお話させていただきます。
例を挙げましょう。Windows Server 2008 の Hyper-V 上の OS をシャットダウンするというものです。 それぞれ、wmic コマンドを使った場合、VBScript の場合、C# の場合から見ていきます。C++ は次回のお楽しみです。

[1] WMIC コマンドの場合
WMIC コマンドを使った例です。まず、仮想マシンの名前が "Windows 7" のものをシャットダウンします。

1. GUID をゲットする
仮想マシン名から、仮想マシンの GUID をとってきます。このとき、Msvm_ComputerSystem を使います。

※注意 : 必ずコマンドプロンプトは権限を昇格させ、管理者で実行してください。

wmic /namespace:"\\root\virtualization" path Msvm_ComputerSystem where ElementName='Windows 7' get name

image

2. Msvm_shutdownComponent を使って、上記 1. を使いシャットダウンさせます。

メソッドは InitiateShutdown です。一つ目の引数 true は強制終了の意味、二つめはあのよくサーバを落とす際にかかされる「終了の理由」です。下記の引数に与えているオレンジ色の GUID は、上記 1. でとってきた GUID をコマンド プロンプトからコピペしてきたものです。

wmic /namespace:\\root\virtualization path Msvm_shutdownComponent where systemname='5EDE3587-0CF3-4C0A-913F-9BEAB8E84C83' call InitiateShutdown true,"てすと"

image

↑ただしく実行されると、ReturnValue = 0 で返されてきます。

↓シャットダウンされます

image

[2] VBScript の場合
wmic だと二行ですが、ちょいと増えます。ただ、systemname にあたるところも変数を使えるので、いちいち人間が name を取得してコピペしないですむので、作成の工数はかかりつつ、その後は格段に楽です。

' <==== ここから
Option Explicit
Dim vmshut
Dim VMName
Dim WMIObject
Dim VM
Dim VMList
Dim vmReturn

VMName = "Windows 7"

Set WMIObject = GetObject("winmgmts:\\.\root\virtualization")
Set VMList = WMIObject.ExecQuery("SELECT * FROM Msvm_ComputerSystem WHERE ElementName='" & VMName & "'")
VM = VMList.ItemIndex(0).Name
Set vmshut = WMIObject.ExecQuery("SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='" & VM & "'")
vmReturn = vmshut.ItemIndex(0).InitiateShutdown(True,"てすと")
' <==== ここまで

[3] C# の場合
うわ、ながっ!って思うかも知れません。自分でも今見て、ながっ!と思いましたが、まだまだこれからです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Management;

namespace ShutDownVM
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

        private void button1_Click(object sender, EventArgs e)
{
// root\virtualization クラスにスコープをあわせる
ConnectionOptions options = new ConnectionOptions();
ManagementScope scope = new ManagementScope(@"\\localhost\root\virtualization");
scope.Connect();

           // Msvm_computersystem クラスを用いて、name を取得
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope,
new ObjectQuery("SELECT * FROM Msvm_ComputerSystem WHERE ElementName = 'Windows 7'"));
IEnumerator enumr = searcher.Get().GetEnumerator();
enumr.MoveNext();
ManagementObject msvm_computersystem = (ManagementObject)(enumr.Current);
ManagementObjectCollection collection = msvm_computersystem.GetRelated("Msvm_ShutdownComponent");
ManagementObjectCollection.ManagementObjectEnumerator enumerator =
collection.GetEnumerator();
enumerator.MoveNext();
ManagementObject msvm_shutdowncomponent = (ManagementObject)enumerator.Current;

            // InitiateShutdown() メソッドの引数を指定
ManagementBaseObject inParams =
msvm_shutdowncomponent.GetMethodParameters("InitiateShutdown");
inParams["Force"] = true;
inParams["Reason"] = "てすと";

            // InitiateShutdown() メソッドの実行
ManagementBaseObject outParams =
msvm_shutdowncomponent.InvokeMethod("InitiateShutdown", inParams, null);
uint returnValue = (uint)outParams["ReturnValue"];

           // 処理失敗した場合は 0 以外が返ります
if (returnValue != 0)
Console.WriteLine("失敗したよ");

            }
}
}

これを見ると、メソッドをただ実行するのではなく、以下の段階を踏んでいることがわかるかと思います。

1. メソッドの引数 (上記例だと、inParams) を指定する
2. メソッドを実行する

次回は、これを C++ でやるとどんな風かというのを、C++ 固有の処理も含めてご紹介させていただきます。

さて、このブログを初めてごらんいただく皆様もいらっしゃるかと思います。また、気がついたらブログ開設から一年とっくに過ぎておりました。
当初、ILM / MIIS という率直に言って決して今のところ、裾野が広いとは言い切れない分野に情報が提供できれば、またサポート契約でどうしても対応できない範囲やわかっていればお問い合わせいただく手間も必要ないような FAQ な事例などをご紹介しようと思い始めたブログですが、気がついたら WMI やら PowerShell やら担当製品が微妙に増加してしまい、今となっては何でもありというかそもそも、technet である必要があるのかもさっぱりわからないカオスな状態になっています。文章もカオスで、マイクロソフトのサポートチームなのか胡散臭いかもしれませんが、お役立ち度数は文章の胡散臭さの絶対値以上のものを目指しております。
今後ともよろしくお願いいたします!

ういこう@某国民的 GF な恋愛ゲームを誕生日プレゼントにだんなからもらいました