ファイルサーバ上でExcel操作を自動化



# 目的
大量のエクセルファイルから，条件に該当する行だけをコピーしてくる処理をつくる
自分だけじゃなくて他のプロジェクトメンバにもつかってもらう．

# VBScript選択の理由
メンバがwindowsOS使用で，プログラミングスキルも高くないので
環境構築不要　＆　クリックだけで実行　ってレベルの簡単さじゃないと定着しないと判断した

下記サイトの最適解をパクる
https://qiita.com/onegear0o/items/2363394e5ba23170d878

※会社だと，ネットワークアクセスの制限で，パッケージファイルがインターネットから取ってこれなかったりするけど，VBSならwindowsOSが入っていればまあ使えるってのが選択の最大の理由．
※機能性とデバッグ性を優先するならpythonとかjavaとかdartとか別の選択肢もある
※普及の容易性＋理解しやすさでVBScriptを選択している




# VBScriptについて
linuxのシェル ≒ windowsバッチ・powershell・VBS　な認識

今回はExcel操作なのでVBSを使う．
※下記の通り，VB(Visual Basic)には色々ある．
※例えばVBとVBSは記法が似ているが，別物なのでコピーしても動かないことが多々あるため注意

* VBA  
Microsoft社のOfficeシリーズ（ExcelやWord、Access等）で実行できるプログラミング言語
* VB  
～.exeや～.dllなどの実行形式ファイルが作成できソフト開発で使われているプログラミング言語
* VB.NET  
VBを.NET Framework（Windowsアプリケーションの開発環境）で使う時に用いるプログラミング言語
* VBScript  
VBの簡易版で手軽にWindows上で動作するプログラムが作れるプログラミング言語

# VBSを呼び出す batch処理
大量のエクセルファイルから，条件に該当する行を見つけ，
指定ファイルの末尾にコピーしてくる処理

様々なファイルで同じ処理をかけたいので，バッチを挟む
※　batchでのコメントアウトは　@rem  です

```bat:test.bat
@rem コピー先ファイルを作成
copy Excelcopy.xlsx Excel\make.xlsx

@rem test_1,2のファイルの内容で，makeの末尾に行を追加していく
test.vbs  Excel\test_1.xlsx Excel\make.xlsx
test.vbs  Excel\test_2.xlsx Excel\make.xlsx
```

# Excel操作するVBS

batchからvbsが呼び出される

下記2種類のExcelシートを同時に開き
①コピーされる元データ
②コピー先データ

①の各行について，C列に"検索文字列"が含まれるか確認して，含まれる場合は
②に該当行をコピーをする
※　vbsでのコメントアウトは　'   です

```vbs:test.vbs
Option Explicit

Dim excel_obj
Dim fso
Dim pass1,pass2
Dim workbook,workbook2
Dim worksheet,worksheet2
Dim message
Dim MaxRow1, MaxRow2
Dim ans
Dim i

' WScript.Arguments(0)は，スクリプト呼び出し時の引数が入る
set fso = createObject("Scripting.FileSystemObject")
pass1 = fso.getParentFolderName(WScript.ScriptFullName) & "\" & WScript.Arguments(0)
pass2 = fso.getParentFolderName(WScript.ScriptFullName) & "\" & WScript.Arguments(1)

'Excelの機能を利用するために必要
Set excel_obj = CreateObject("Excel.Application")

'Excelを可視化
excel_obj.Visible = True

'開きたいExcelファイルを指定(絶対パス)
Set workbook = excel_obj.Workbooks.Open(pass1)
Set workbook2 = excel_obj.Workbooks.Open(pass2)

'シートを指定(名前Or番号で指定)
Set worksheet = workbook.Sheets(1)
Set worksheet2 = workbook2.Sheets(1)

'開いたExcelシートの"C列"の行数を確認
MaxRow1 = worksheet.Cells(worksheet.Rows.Count, "C").End(-4162).Row
MaxRow2 = worksheet2.Cells(worksheet2.Rows.Count, "C").End(-4162).Row

'messageを表示し，yes/Noの選択ボタンを表示して選ばせる．Noを押したら処理終了．
message = "can you start program " & pass1 & "  start process   " & MaxRow1 & "  :   " & MaxRow2
ans = MsgBox(message, vbYesNo)
If ans = vbNo Then WScript.Quit


'worksheetを上から1行ずつ確認していく
For i = 1 To MaxRow1
'１つめのシートの"C列"に「検索文字列」が含まれているか判定、もう一つのシートに列ごとコピー
If worksheet.Cells(i, "C") = "グループ" Then
If Not worksheet.Cells(i, "D") = "グループ課題に移動済み" Then
'２つめのシートの最後尾＋1行のところに
MaxRow2=MaxRow2 + 1
'該当行を行ごとコピー
worksheet.Cells(i, "C").EntireRow.Copy worksheet2.Rows(MaxRow2)
worksheet.Cells(i, "D").Value = "グループ課題に移動済み"
worksheet.Cells(1, "D").NumberFormatLocal = "G/標準"
End If
End If
Next

'上書き保存
workbook.Save
workbook2.Save

'上書き保存
workbook2.Save

'ワークブックを閉じる
workbook.Close
workbook2.Close

'Excelを閉じる
excel_obj.Quit
```



# batchを呼び出す(管理する) HTA
htaからバッチを処理できるようにして
バッチに関する説明はここに書いてしまう．

```hta:test.hta
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=Shift_JIS" http-equiv="Content-Type">
<title>ファイル操作スクリプト</title>
</head>
<body>
<form name="form1">
<input type="button" name="btn_do_bat01" value="test.batの実行" onClick="do_bat01()" /><br />
<input type="button" name="btn_do_bat02" value="test2.batの実行" onClick="do_bat02()" /><br />
<br />
<input type="button" name="btn_reset" value="カラーリセット" onClick="do_reset()" /><br />
</form>

<SCRIPT FOR=window EVENT=onload LANGUAGE="VbScript">
resizeTo 320,240
moveTo 100,75

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set SaveFile = objFSO.OpenTextFile("save.txt" , 1 , False, 0)

Do Until SaveFile.AtEndOfStream
strLine = SaveFile.ReadLine
Select Case strLine
Case "do_bat01"
document.form1.btn_do_bat01.style.backgroundColor = "RED"
Case "do_bat02"
document.form1.btn_do_bat02.style.backgroundColor = "RED"
' ...
End Select
Loop
SaveFile.Close
</SCRIPT>

<script language="VBScript">
Dim WshShell, oExec
Set WshShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")

Sub do_bat01()
If objFso.FileExists("test.bat") Then
    Set oExec = WshShell.Exec("test.bat")
    MsgBox "処理終了"
    document.form1.btn_do_bat01.style.backgroundColor = "RED"
    Set SaveFile = objFSO.OpenTextFile("save.txt" , 8 , True, 0)
    SaveFile.WriteLine("do_bat01")
Else
    MsgBox "test.batが見つかりません"
End If
End Sub

Sub do_bat02()
If objFso.FileExists("test2.bat") Then
    Set oExec = WshShell.Exec("test2.bat")
    MsgBox "終わりましたか？"
    document.form1.btn_do_bat02.style.backgroundColor = "RED"
    Set SaveFile = objFSO.OpenTextFile("save.txt" , 8 , True, 0)
    SaveFile.WriteLine("do_bat02")
Else
    MsgBox "test2.batが見つかりません"
End If
End Sub

Sub do_reset()
Set SaveFile = objFSO.OpenTextFile("save.txt" , 2 , True, 0)
SaveFile.Write("")
document.form1.btn_do_bat01.style.backgroundColor = ""
document.form1.btn_do_bat02.style.backgroundColor = ""
End Sub
</script>
</body></html>
```