'******************************************
'*  Filename >>>  deviceguard_disable.vbs *
'*                                        *
'*  ・Device Guard 機能の無効化           *
'******************************************
'******************************************
' 概要：メイン処理
' 引数：なし / SILENT
' 戻値：0      … 正常終了
'       0 以外 … 異常終了
'******************************************
'---------------------------------
' DebugMode
'---------------------------------
Dim DebugMode   : DebugMode = 0

'---------------------------------
' 引数設定
'---------------------------------
Dim objArgs     : Set objArgs = WScript.Arguments
Dim ExecMode    : ExecMode    = "MANUAL"

'---------------------------------
' 初期設定
'---------------------------------
' 定数
Const JPNLANG       = 1041       ' 言語設定用
Const SUCCESS       = 0          ' 正常終了
Const CANCEL        = 1          ' キャンセル押下
Const ERR_OS        = 2          ' 対象外 OS エラー
Const ERR_REGDELETE = 3          ' レジストリ削除エラー
Const ERR_REGADD    = 4          ' レジストリ追加エラー
Const ERR_OTHER     = 255        ' 初期値

Dim objShell        : Set objShell = WScript.CreateObject("Wscript.Shell")
Dim WINDIR          : WINDIR = objShell.ExpandEnvironmentStrings("%windir%")

Dim RetValue        : RetValue   = ERR_OTHER
Dim ReturnCode      : ReturnCode = ERR_OTHER
Dim strCmdline      : strCmdline = ""

' WMI用
Dim strComputer     : strComputer = "."
Dim objOSItems      : objOSItems  = ""
Dim LangNum         : LangNum     = 0
Dim OSLang          : OSLang      = "ENG"
Dim OSEdition       : OSEdition   = ""

Dim objWMIService   : Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Dim ColOSItems      : Set ColOSItems    = objWMIService.ExecQuery("Select * From Win32_OperatingSystem",,48)

' レジストリ設定用
Dim RegChangeFlg    : RegChangeFlg = False
Dim Count           : Count        = 0


'---------------------------------
' 引数確認
'---------------------------------
If objArgs.Count > 0 Then
   If objArgs(0) = "SILENT" Then
      ExecMode = "SILENT"
   End If
End If

If DebugMode = 1 Then
   WScript.echo "ExecMode = " & ExecMode
End If

'---------------------------------
' OS 判別 と 言語の設定
'---------------------------------
For Each objOSItems In ColOSItems
   LangNum   = int(objOSItems.OSLanguage)
   OSEdition = objOSItems.Caption
   Exit For
Next

' 言語判別
If LangNum = JPNLANG Then
   ' 日本語に設定
   OSLang = "JPN"
End If

If DebugMode = 1 Then
   WScript.echo "OSEdition = " & OSEdition & vbCrLf & _
                "OSLang    = " & OSLang
End If

' OS 判別
If InStr(1, OSEdition, "Server 2016", vbTextCompare) = 0 Then
   ' 対象外 OS
   Call ErrFunction("B101", ERR_OS)
End If

'---------------------------------
' 開始メッセージ
'---------------------------------
If ExecMode = "MANUAL" Then
   RetValue = Disp_Message("A001", OSLang)

   If RetValue <> 1 Then
       ' キャンセルボタン(OKボタン以外)
      Call ErrFunction("A002", CANCEL)
   End If
End If

'---------------------------------
' レジストリの削除 (EnableVirtualizationBasedSecurity / RequirePlatformSecurityFeatures)
'---------------------------------
' レジストリ削除関数の呼び出し
RetValue = ERR_OTHER
RetValue = Reg_Delete()

' 戻り値確認
If RetValue <> 0 Then
   ' レジストリの作成に失敗
   Call ErrFunction("C201", ERR_REGDELETE)
End If

'---------------------------------
' レジストリの追加 (EnableVirtualizationBasedSecurity / HyperVVirtualizationBasedSecurityOptout)
'---------------------------------
' レジストリ追加関数の呼び出し
RetValue = ERR_OTHER
RetValue = Reg_Add()

' 戻り値確認
If RetValue <> 0 Then
   ' レジストリの作成に失敗
   Call ErrFunction("C202", ERR_REGADD)
End If

'---------------------------------
' 終了処理
'---------------------------------
' オブジェクトの解放
Set objWMIService = Nothing
Set ColOSItems    = Nothing


If ExecMode = "MANUAL" Then
   ' 終了メッセージ表示
   If RegChangeFlg = False Then
      ' レジストリを変更していないため Device Guard 無効化済と判断
      RetValue = Disp_Message("A003", OSLang)
      ' オブジェクトの解放
      Set objShell = Nothing
      ' 再起動しない
      WScript.Quit(SUCCESS)
   Else
      RetValue = Disp_Message("A004", OSLang)

      ' メッセージ表示後再起動を実施
      strCmdline = WINDIR & "\system32\shutdown.exe /r /t 0"
      objShell.Run strCmdline
   End If
Else
   ' オブジェクトの解放
   Set objShell = Nothing
   ' 実行モードが SLIENT の場合は再起動しない
   WScript.Quit(SUCCESS)
End If


'****************************************
' 概要    ：メッセージ表示関数
' 第一引数：メッセージID
' 第二引数：表示言語
' 戻値    ：押されたボタンに対応する数値
'****************************************
Function Disp_Message(MESID, MESLANG)
    Dim MESTITLE   : MESTITLE   = "Device Guard disable tool"
    Dim strMsg     : strMsg     = ""
    Dim strIcon    : strIcon    = 0
    Dim msgButtons : msgButtons = 0

    Select Case MESID
        Case "A001"
            If MESLANG = "JPN" Then
               strMsg = "Device Guard 機能を無効化します。" & vbCrLf & _
                        "" & vbCrLf & _
                        "本ツールは管理者権限で起動したコマンドプロンプトから" & vbCrLf & _
                        "実行してください。" & vbCrLf & _
                        "本ツール実行後、再起動を行います。" & vbCrLf & _
                        "継続するときは OK ボタンをクリックしてください。"
            Else
               strMsg = "Disabling Device Guard function." & vbCrLf & _
                        "" & vbCrLf & _
                        "Please run from the command prompt" & vbCrLf & _
                        "with an administrator privileges." & vbCrLf & _
                        "Restarting the system after this tool completed." & vbCrLf & _
                        "When continuing this tool, please click OK."
            End If
            strIcon = vbInformation
            msgButtons = 1
        Case "A002"
            If MESLANG = "JPN" Then
               strMsg = "ツールを終了します。"
            Else
               strMsg = "This tool is ended."
            End If
            strIcon = vbInformation
        Case "A003"
            If MESLANG = "JPN" Then
               strMsg = "Device Guard は既に無効化されています。" & vbCrLf & _
                        "ツールを終了します。"
            Else
               strMsg = "Device Guard already has been disabled." & vbCrLf & _
                        "This tool is ended."
            End If
            strIcon = vbInformation
        Case "A004"
            If MESLANG = "JPN" Then
               strMsg = "本ツールは正常に完了しました。" & vbCrLf & _
                        "OK ボタンをクリックすると、再起動します。"
            Else
               strMsg = "This tool has been completed." & vbCrLf & _
                        "Restarting the system, when OK button clicked."
            End If
            strIcon = vbInformation
        Case "B101"
            If MESLANG = "JPN" Then
               strMsg = "本ツールの対象 OS ではありません。" & vbCrLf & _
                        "ツールを終了します。"
            Else
               strMsg = "This tool is not available on this OS." & vbCrLf & _
                        "This tool is ended."
            End If
            strIcon = vbExclamation
        Case "C201", "C202"
            If MESLANG = "JPN" Then
               strMsg = "ツールの実行に失敗しました。" & vbCrLf & _
                        "管理者権限で起動したコマンドプロンプトから" & vbCrLf & _
                        "再度実行してください。"
            Else
               strMsg = "This tool failed to execute." & vbCrLf & _
                        "Please execute again from the command prompt " & vbCrLf & _
                        "with an administrator privileges."
            End If
            strIcon = vbCritical
        Case Else

    End Select

    ' メッセージ ID を追加
    strMsg = strMsg & vbCrLf & "(ID:" & MESID & ")"
    ' ボタンとアイコンの設定
    strIcon = strIcon + msgButtons

    ' メッセージボックスを表示する
    ReturnCode   = ERR_OTHER
    ReturnCode   = objShell.Popup(strMsg, 0, MESTITLE, strIcon)
    Disp_Message = ReturnCode

End Function

'****************************************
' 概要    ：エラー処理関数
' 第一引数：メッセージID
' 第二引数：スクリプト終了時に返却する数値
' 戻値    ：なし
'****************************************
Sub ErrFunction(ErrMsgID, ErrRetValue)

   ' メッセージ表示あり
   If ExecMode = "MANUAL" Then
      RetValue = Disp_Message(ErrMsgID, OSLang)
   End If

   ' オブジェクトの解放
   Set objShell      = Nothing
   Set objWMIService = Nothing
   Set ColOSItems    = Nothing

   WScript.Quit(ErrRetValue)

End Sub

'****************************************
' 概要    ：レジストリ削除関数
' 引数    ：なし
' 戻値    ：SUCCESS       (0)
'           ERR_REGDELETE (3) 初期値
'****************************************
Function Reg_Delete()

   ' 初期値設定
   Reg_Delete = ERR_REGDELETE
   Dim DelRegPath   : DelRegPath  = "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\DeviceGuard"
   Dim DelRegNames  : DelRegNames = Array("EnableVirtualizationBasedSecurity","RequirePlatformSecurityFeatures")

   For Count = 0 to UBound(DelRegNames)
      ' レジストリの確認
      strCmdline = "REG QUERY " & DelRegPath & " /v " & DelRegNames(Count)
      ReturnCode = ERR_OTHER
      ReturnCode = objShell.Run(strCmdline, 0, TRUE)

      If DebugMode = 1 Then
         WScript.echo "strCmdline = " & strCmdline & vbCrLf & _
                      "ReturnCode = " & ReturnCode
      End If

      ' 戻り値確認
      If ReturnCode = 0 Then
         ' レジストリが存在するため削除実施
         strCmdline = "REG DELETE " & DelRegPath & " /v " & DelRegNames(Count) & " /f"
         ReturnCode = ERR_OTHER
         ReturnCode = objShell.Run(strCmdline, 0, TRUE)

         If DebugMode = 1 Then
            WScript.echo "strCmdline = " & strCmdline & vbCrLf & _
                         "ReturnCode = " & ReturnCode
         End If

         ' 戻り値確認
         If ReturnCode = 0 Then
            ' コマンド実行成功
            Reg_Delete = SUCCESS
            ' レジストリ変更フラグオン
            RegChangeFlg = True
         Else
            ' レジストリ削除に失敗
            Reg_Delete = ERR_REGDELETE
            Exit Function
         End If
      Else
         ' レジストリ値が存在しないため SUCCESS を設定
         Reg_Delete = SUCCESS
      End If
   Next

   If DebugMode = 1 Then
      WScript.echo "Reg_Delete = " & Reg_Delete & vbCrLf & _
                   "RegChangeFlg = " & RegChangeFlg
   End If

End Function


'****************************************
' 概要    ：レジストリ追加関数
' 引数    ：なし
' 戻値    ：SUCCESS    (0)
'           ERR_REGADD (4) 初期値
'****************************************
Function Reg_Add()

   ' 初期値設定
   Reg_Add = ERR_REGADD
   Dim objReg         : Set objReg    = WScript.CreateObject("Wscript.Shell")
   Dim AddRegPath     : AddRegPath    = "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\DeviceGuard"
   Dim AddValueNames  : AddValueNames = Array("EnableVirtualizationBasedSecurity","HyperVVirtualizationBasedSecurityOptout")
   Dim RegSetValues   : RegSetValues  = Array(0, 1) ' EnableVirtualizationBasedSecurity 0 / HyperVVirtualizationBasedSecurityOptout 1
   Dim GetValue       : GetValue      = ERR_OTHER
   Dim RegExist       : RegExist      = False

   For Count = 0 to UBound(AddValueNames)
      ' レジストリの確認
      strCmdline = "REG QUERY " & AddRegPath & " /v " & AddValueNames(Count)
      ReturnCode = ERR_OTHER
      ReturnCode = objShell.Run(strCmdline, 0, TRUE)

      If DebugMode = 1 Then
         WScript.echo "strCmdline = " & strCmdline & vbCrLf & _
                      "ReturnCode = " & ReturnCode
      End If

      ' レジストリ書き込み要否判定フラグ
      RegExist = False

      ' 戻り値確認
      If ReturnCode = 0 Then
         ' レジストリが存在するため値を確認
         GetValue = ERR_OTHER
         GetValue = objReg.RegRead(AddRegPath & "\" & AddValueNames(Count))

         If DebugMode = 1 Then
            WScript.echo "GetValue = " & GetValue
         End If

         If GetValue = RegSetValues(Count) Then
            ' 既に正解値がセットされているため変更する必要なし。
            Reg_Add  = SUCCESS
            RegExist = True
         End If
      End If

      If RegExist = False Then
         ' レジストリの追加
         strCmdline = "REG ADD " & AddRegPath & " /v " & AddValueNames(Count) & " /t REG_DWORD /d " & RegSetValues(Count) & " /f"
         ReturnCode = ERR_OTHER
         ReturnCode = objShell.Run(strCmdline, 0, TRUE)

         If DebugMode = 1 Then
            WScript.echo "strCmdline = " & strCmdline & vbCrLf & _
                         "ReturnCode = " & ReturnCode
         End If

         ' 戻り値確認
         If ReturnCode = 0 Then
            ' コマンド実行成功
            Reg_Add = SUCCESS
            ' レジストリ変更フラグオン
            RegChangeFlg = True
         Else
            ' レジストリ追加に失敗
            Reg_Add = ERR_REGADD
            Exit Function
         End If
      End If
   Next

   If DebugMode = 1 Then
      WScript.echo "Reg_Add = " & Reg_Add & vbCrLf & _
                   "RegChangeFlg = " & RegChangeFlg
   End If

   ' オブジェクトの解放
   Set objReg = Nothing
End Function