DOBON.NET DOBON.NETプログラミング掲示板過去ログ

WMIを介してWindowsシャットダウン

分類:[.NET]

現在、System.Management名前空間を介して、Win32Shutdownメソッドを実行して
Windowsシャットダウンを行う関数を作成中なのですが、
ローカルシャットダウンの特権をどのように与えるのか分からなくて困っています。

vb6では出来たのですが、VB.NETではどうすればいいのでしょうか?
参考url等でも教えていただければありがたいです。
よろしくお願いします。
> ローカルシャットダウンの特権をどのように与えるのか分からなくて困っています。

.Scope.Options.EnablePrivileges = True

としても、

'System.Management.ManagementException' のハンドルされていない例外が system.management.dll で発生しました。

追加情報 : 特権を保有していません。

というエラーになるのは何故かという件でしょうか?
(何故なんでしょうね。私も分かっていません)
>というエラーになるのは何故かという件でしょうか?
そうなんです。

当方で、試した内容は、次の通りです。

参照設定で「System.Management」追加する。
フォームにボタンを貼り付けて、ボタンクリックでシャットダウンする。
クリックイベント内のコードは次の通り。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim PrcSrc As ManagementObjectCollection
Dim Prc As ManagementObject
Dim ms As New ManagementScope()

'ms.Options.EnablePrivileges = True

Dim Searcher As New ManagementObjectSearcher()
Searcher.Query.QueryString = "SELECT * FROM Win32_OperatingSystem"
Searcher.Scope = ms
PrcSrc = Searcher.Get

For Each Prc In PrcSrc
Dim ss(1) As String
ss(0) = "2"
ss(1) = "0"
Prc.Scope.Options.EnablePrivileges = True
Debug.WriteLine(Prc.ToString)
Prc.InvokeMethod("Win32Shutdown", ss)

Next

End Sub
> >というエラーになるのは何故かという件でしょうか?
> そうなんです。

.Scope.Options.EnablePrivilegesはなんのためにあるのかは
私もよく分かりませんが、1つの代替策はWin32APIで特権を獲得
することでしょう。

これ↓で私のW2kProでリブートできました。
(※動作したものの私もよくわからず組んだので信用しないこと(^^;)

    'Imports System.Management
    'Imports System.Security.Principal

    '**************************************************************************
    'ローカルマシンのログオフorリブートorシャットダウンを行う
    '@param iMode 0=ログオフ 2=リブート 8=電源断 (各々の数字に4を足せば強制モード)
    '**************************************************************************
    Private Sub doShutdown(ByVal iMode As Integer)
        Dim hasPrivilege As Boolean '特権獲得成功識別Flag

        '*** Win32APIで特権獲得 (9X系なら飛ばすようにすべき) ***
        Const SE_SHUTDOWN_NAME = "SeShutdownPrivilege"
        Const SE_PRIVILEGE_ENABLED As Int32 = &H2
        Dim tknPrivilege As TOKEN_PRIVILEGES
        If LookupPrivilegeValue(vbNullString, SE_SHUTDOWN_NAME, _
                                tknPrivilege.Privileges.pLuid) Then
            tknPrivilege.PrivilegeCount = 1
            tknPrivilege.Privileges.Attributes = SE_PRIVILEGE_ENABLED
            If AdjustTokenPrivileges(WindowsIdentity.GetCurrent.Token(), _
                                     0, tknPrivilege, Len(tknPrivilege), _
                                     Nothing, 0) Then
                hasPrivilege = True
            End If
        End If
        If Not hasPrivilege Then
            '<特権獲得に失敗した場合>
            '実行しているアカウントが本当に権限を持っていないとか...
            '(ドメインの権限設定やローカル セキュリティ ポリシーで要確認)
            Return
        End If

        '*** System.ManagementでShutdown ***
        Const WQL_SELECT_OS = "select name from Win32_OperatingSystem where primary=true"
        Dim moOS As ManagementObject
        For Each moOS In New ManagementObjectSearcher(WQL_SELECT_OS).Get()
            'moOS.Scope.Options.EnablePrivileges = True これが効かないので上のAPIで取っている
            moOS.InvokeMethod("Win32Shutdown", New String() {CStr(iMode), "0"})
        Next
    End Sub

#Region "doShutdownで特権獲得に使用するAPI"

    Structure LUID_AND_ATTRIBUTES
        Dim pLuid As LARGE_INTEGER
        Dim Attributes As Int32
    End Structure

    Structure LUID
        Dim LowPart As Int32
        Dim HighPart As Int32
    End Structure

    Structure LARGE_INTEGER
        Dim lowpart As Int32
        Dim highpart As Int32
    End Structure

    Structure TOKEN_PRIVILEGES
        Dim PrivilegeCount As Int32
        Dim Privileges As LUID_AND_ATTRIBUTES
    End Structure

    Declare Auto Function AdjustTokenPrivileges Lib "advapi32.dll" ( _
        ByVal TokenHandle As IntPtr, _
        ByVal DisableAllPrivileges As Int32, _
        ByRef NewState As TOKEN_PRIVILEGES, _
        ByVal BufferLength As Int32, _
        ByRef PreviousState As TOKEN_PRIVILEGES, _
        ByRef ReturnLength As Int32) As Int32

    Declare Auto Function LookupPrivilegeValue Lib "advapi32.dll" ( _
            ByVal lpSystemName As String, _
            ByVal lpName As String, _
            ByRef lpLuid As LARGE_INTEGER) As Int32
#End Region
ピラルクさん代替策ありがとうございます。参考にさせて頂きます。
また、よろしくお願いします。

DOBON.NET | プログラミング道 | プログラミング掲示板