著作一覧 |
.NETでManagementObjectを使ってシャットダウンをしようとすると、「できない」という悲鳴がいっぱい聞こえてくる。
さらに、3.5の頃はできたのに4.0になったらできなくなったというような頓珍漢な見解とかもあったりする(どこだか忘れた)。
たとえば以下のような例がある。
A required privilege is not held by the client 2006年 System.Management.ManagementException: “Privilege not held.” When trying to Shutdown Windows 7 in C# 4.0 using WMI" 2013年 WMI "Privilege not held" error when attempting to remote shutdown a machine 2008年 Reboot computer in C# / .NET 2010年で、shutdown.exeをProcess.Startすれば良いとか、Interop使えば良いとかサジェストを受けて、PrivilegeTokenをいじったりしているのだが、そんな必要はない。
まあ、かくいうこちらも、そういう情報を見てInteropで実行していたのだが、ふと、そんな使いみちがないままでManagementObjectを出し続けているわけないだろうと考えた。
で、試しにやってみたら、確かにManagementExceptionを喰らう。
でも、待て、何かおかしい。
で、検索してみたら唯一、正解に近いのがPrivilege not held on InvokeMethod(2005年)見つかった。だが、この方法は少なくとも現在は使えない。
答は単純で、インパーソネートしてEnablePrivileges=trueにして接続したスレッドでWMIを動かすというのはその通り。ただ、(おれの予想だが)普通に作るとMTA内のアパートに作られるために呼び出しが失敗する(というのは、computer-programming-forum.comのMVPの人の説明と同じ)で、しかしMTAで動くのではない点にある。
つまり、
[STAThread]
を付けたプログラムで実行すれば良い。
とはいえ、そんなプログラムでなければ、シャットダウンの実行をSTAにすれば良い。
using System; using System.Linq; using System.Management; using System.Threading; class Shutdown { enum ShutdownFlags { LogOff = 0, Shutdown = 1, Reboot = 2, PowerOff = 8, Forced = 4, } static void Main() { var t = new Thread(() => { var management = new ManagementClass("Win32_OperatingSystem"); management.Get(); management.Scope.Options.EnablePrivileges = true; foreach (var win32 in management.GetInstances().OfType<ManagementObject>()) { win32.InvokeMethod("Win32Shutdown", new object[] {ShutdownFlags.LogOff | ShutdownFlags.Forced, 0}); } }); t.SetApartmentState(ApartmentState.STA); t.Start(); t.Join(); } }
ジェズイットを見習え |