VBScriptでMS Accessのdecompile,compile,repair

#### 概要
某所では、ファイルサイズの肥大化を避けるため、accdbに手を入れる度にデコンパイル、コンパイル、および[データベースの最適化と修復]をすることになっている（慣わし・仕来りの類）
毎回手作業でやりたくないので作った。

```vb:accdb_optimize.vbs
Dim Excel
Set Excel = WScript.CreateObject("Excel.Application")

Const SHIFT_KEY = &H10
Const CMD = "C:\Windows\System32\cmd.exe"
Const MSACCESS = """C:\Program Files {(}x86{)}\Microsoft Office\Office16\MSACCESS.EXE"" "
Const AAA_DB_PATH     = "C:\aaa.accdb"
Const BBB_DB_PATH     = "C:\bbb.accdb"
Const CCC_DB_PATH     = "C:\ccc.accdb"
Const DDD_DB_PATH     = "C:\ddd.accdb"

Sub API_keybd_event(bVk, bScan, dwFlags, dwExtraInfo)
    Dim strFunction
    Const API_STRING = "CALL(""user32"",""keybd_event"",""JJJJJ"", $1, $2, $3, $4)"
    strFunction = Replace(Replace(Replace(Replace(API_STRING, "$1", bVk), "$2", bScan), "$3", dwFlags), "$4", dwExtraInfo)
    Call Excel.ExecuteExcel4Macro(strFunction)
End Sub

Sub optimize(dbPath)
    Dim WshShell,acApp,ctrl,acForm,i,objExecCmd
    Set WshShell = WScript.CreateObject("WScript.Shell")
    
    WshShell.Run(CMD)
    WScript.Sleep(1000)
    WshShell.SendKeys(MSACCESS & dbPath & " /decompile")

    'Shift on
    Call API_keybd_event(SHIFT_KEY, 0, 1, 0)
    
    'Decompile
    WshShell.SendKeys("{enter}")
    WScript.Sleep(2000)

    'Shift off
    Call API_keybd_event(SHIFT_KEY, 0, 3, 0)
    
    'Compile
    Set acApp = GetObject(dbPath)
    Set ctrl = acApp.VBE.CommandBars.FindControl(,578)
    ctrl.Execute()
    WScript.Sleep(1000)
    
    'Close shutter bar
    Call acApp.DoCmd.SelectObject(acForm, "", True)
    acApp.DoCmd.Minimize()
    WScript.Sleep(1000)
    
    'Close ACCDB
    WshShell.SendKeys("%{F4}")
    WScript.Sleep(3000)

    'Just in case(shift off)
    Call API_keybd_event(SHIFT_KEY, 0, 3, 0)

    'Compact and repair database
    WshShell.AppActivate(CMD)
    WshShell.SendKeys(MSACCESS & dbPath & " /compact")
    WshShell.SendKeys("{enter}")
    WScript.Sleep(2000)

    'Close CMD
    WshShell.AppActivate(CMD)
    WshShell.SendKeys("exit{enter}")
End Sub

Sub main
    Dim input_no
    input_no = CStr(InputBox("Decompile, compile, compress and repair ACCDB." & vbCrLf & _
                             "Please input the number for target App." & vbCrLf & _
                             vbCrLf & _
                             "1:AAA" & vbCrLf & _
                             "2:BBB" & vbCrLf & _
                             "3:CCC" & vbCrLf & _
                             "4:DDD", _
                             "ACCDB optimization tool"))

    If input_no = "" Then
        exit sub
    Elseif input_no = "1" Then
        optimize(AAA_DB_PATH)
    Elseif input_no = "2" Then
        optimize(BBB_DB_PATH)
    Elseif input_no = "3" Then
        optimize(CCC_DB_PATH)
    Elseif input_no = "4" Then
        optimize(DDD_DB_PATH)
    Else
        Call MsgBox("The menu does not have that number. " & input_no)
        Exit Sub
    End if
    Call MsgBox("Optimization complete.", vbInformation)
End Sub

'execute main procedure
main()
```

####解説
- 処理の完了検知ができないので、所々で適当な秒数sleepしてる。
- Shift押しながらdecompileしないと、スタートアップフォームやマクロが起動してしまうので、Excel経由でWindows APIを使って、Shiftキーを押しっぱなしたことにしている。

####所感
- mission-criticalなところでMS Accessをアプリとして使うのはやめたほうがいい気がします...
- Accessでimport/exportを6,000回くらい繰り返すと、謎のエラーで動かなくなる...