スクリプト作成_ファイル・フォルダ情報の確認

<h1>はじめに</h1>
<b>※あくまで個人的備忘録です※</b>
運用チームのお手伝いで、エンジニア人生5年目で初めて実用的なスクリプト作成にトライしました。
内容は「バックアップされたファイル、フォルダを目視確認している。この手間を省くため、確認作業の自動化をしてほしい。」というお話からでした。
当時、構築案件が落ち着いていたこともあり、私が対応することになりました。
要件は明確ですが、スクリプトなんてまともなものを作ったことがないため、1からググることを始めました。

<h1>スクリプトの仕様について</h1>
始める前に、以下の流れで取り組み、イメージを可視化しました。
①フローチャート図を作成し、大まかな処理の流れを書き出す（実際の確認処理は処理A,処理Bとaboutに表現）
②処理A、Bと表現した処理について、要件から必要な処理ごとに分ける
③処理に必要と思われるコマンドを調べ、イメージと合致するものをピックアップしていく


<b>◆フローチャート図◆</b>
概要
![概要.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639874/faa3ad52-0a69-fb31-deaa-11e2d1c715d8.png)

詳細
![詳細.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639874/b41d232a-eb50-c699-9847-1f5f54c0f05c.png)

<b>◆要件の整理◆</b>

<table>
<tr><th>パターン</th><th>確認方法</th><th>補足</th></tr>
<tr> <th>A</th> <th>YYYY-MM-DD hh.mm.ss表記のフォルダが作成されている</th> <th></th> </tr>
<tr> <th>B</th> <th>更新日時が前日日付のファイルがある</th> <th></th> </tr>
<tr> <th>C</th> <th>UDPコンソールを起動しイベントログからステータス確認</th> <th>バックアップサーバにRDP接続する</th> </tr>
<tr> <th>D</th> <th>.binファイルの更新日付が確認日の2:00になっている</th> <th></th> </tr>
<tr> <th>E</th> <th>YYYY.MM.DD,YYYY.MM.DD-1,YYYY.MM.DD-2のフォルダが存在すること</th> <th></th> </tr>
</table>

<b>◆コマンドのピックアップ◆</b>

```java:forコマンド
for /f "skip=1 tokens=1-3 delims=," %%a in ( ****.csv ) do ( )
rem カンマ(,)区切りのCSVを変数に読み込む
```
```java:dirコマンド
dir /b /ad %FILEPATH%
rem FILEPATHに存在するフォルダ一覧のみ表示

dir /a-d %FILEPATH%
rem FILEPATHに存在するファイルを一覧表示（更新日付含む）
```
```java:findstrコマンド
dir /b /ad %FILEPATH% | findstr "test"

rem dirコマンドで取得した値から、文字列「test」を含むものだけ抽出
```
<h1>実際に作ってみた</h1>

以下のファイル構成で準備しました。
分割したのは汎用性を高めるためです。（改修や別スクリプトへの流用）
![構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639874/998259ed-c30f-5d39-8f6a-949c458da206.png)
</br>

情報ファイル(hostlist.csv)を事前に準備します。
内容例は以下になります。

<table>
<tr><th>ホスト名</th><th>パターン情報</th><th>確認先フォルダ</th></tr>
<tr> <th>HOST-A</th> <th>A</th> <th>H:\Backup\HOST-A</th> </tr>
<tr> <th>HOST-B</th> <th>B</th> <th>H:\Backup\HOST-B</th> </tr>
<tr> <th>HOST-C</th> <th>C</th> <th>H:\Backup\HOST-C</th> </tr>
<tr> <th>・・・</th> <th>・・・</th> <th>・・・</th> </tr>
</table>


```java:main.bat
@echo off
setlocal EnableDelayedExpansion

rem *-------------------------------*
rem 
rem 	バックアップ確認 自動化
rem 
rem *-------------------------------*
rem 
rem YYYY.MM.DD	:新規作成

rem サブスクリプト一覧(subscript配下)
rem today.bat		:当日日付情報取得
rem yesterday.bat	:昨日日付情報取得
rem 2days_ago.bat	:一昨日日付情報を取得
rem PatternA.bat	:パターンAの処理用
rem PatternB.bat	:パターンBの処理用
rem PatternC.bat	:パターンCの処理用
rem PatternD.bat	:パターンDの処理用
rem PatternE.bat	:パターンEの処理用

rem 変数一覧
rem TODAY1	        :yyyy-mm-dd表記の当日日付
rem TODAY2	        :yyyy/mm/dd表記の当日日付
rem TODAY3	        :yyyymmdd表記の当日日付
rem YESTERDAY1	    :yyyy-mm-dd表記の昨日日付
rem YESTERDAY2	    :yyyy/mm/dd表記の昨日日付
rem YESTERDAY3	    :yyyymmdd表記の昨日日付
rem TWODAYS_AGO     :yyyymmdd表記の一昨日日付
rem CSVHOSTNAME     :CSV一覧に記載されている確認対象ホスト名
rem CSVPATH	        :CSV一覧に記載されている確認先パス情報
rem HANTEI	        :分岐処理の判定結果(○/△)
rem LOGFILE	        :検査結果の出力先


rem 日付情報の取得
call subscript\today.bat
call subscript\yesterday.bat
call subscript\2days_ago.bat

set LOGFILE=C:\TEMP\Script\%TODAY1%_backup-autocheck.csv

rem 対象ホスト,パターン,確認先フォルダ情報元の指定
set LISTFILE = hostlist.csv

for /f "skip=1 tokens=1-3 delims=," %%a in ( %LISTFILE% ) do (
	rem ホスト名,パターン情報,確認先を変数に代入
	set CSVHOSTNAME=%%a
	set CSVPATH=%%c
	set HANTEI=N/A
	
	rem パターンごとに処理を分岐
	if %%b == A (
	   call subscript\PaternA.bat %%c 
    ) else if %%b == B (
	   call subscript\PaternB.bat %%c
    ) else if %%b == C (
	   call subscript\PaternC.bat %%c
    ) else if %%b == D (
	   call subscript\PaternD.bat %%c
    ) else if %%b == E (
	   call subscript\PaternE.bat %%c
    ) else (
	   set HANTEI=Error:該当パターン無
    )
	rem ホスト名と判定結果をCSV出力
	echo !CSVHOSTNAME!,!HANTEI! >> %LOGFILE%
)

endlocal
```
```java:today.bat
@echo off

rem 時刻表記がYYYY-MM-DD
set TODAY1=%DATE:~0,4%-%DATE:~5,2%-%DATE:~8,2%

rem 時刻表記がYYYY/MM/DD
set TODAY2=%DATE:~0,4%/%DATE:~5,2%/%DATE:~8,2%

rem 時刻表記がYYYY.MM.DD
set TODAY3=%DATE:~0,4%.%DATE:~5,2%.%DATE:~8,2%
```
```java:yesterday.bat
@echo off

rem 時刻表記がYYYY-MM-DD
rem 前日日付
FOR /F "usebackq" %%a IN (`powershell -command [DateTime]::Today.AddDays"("-1")".ToString"("'yyyy-MM-dd'")"`) DO SET yesterday1=%%a

rem 時刻表記がYYYY/MM/DD
rem 前日日付
FOR /F "usebackq" %%a IN (`powershell -command [DateTime]::Today.AddDays"("-1")".ToString"("'yyyy/MM/dd'")"`) DO SET yesterday2=%%a

rem 時刻表記がYYYY.MM.DD
rem 前日日付
FOR /F "usebackq" %%a IN (`powershell -command [DateTime]::Today.AddDays"("-1")".ToString"("'yyyy.MM.dd'")"`) DO SET yesterday3=%%a
```
```java:2days_ago.bat
@echo off

rem 時刻表記がYYYY.MM.DD

rem 前々日日付
FOR /F "usebackq" %%a IN (`powershell [DateTime]::Today.AddDays"("-2")".ToString"("'yyyy.MM.dd'")"`) DO SET TWODAYS_AGO=%%a
```
```java:PatternA.bat
@echo off

set CSVPATH=%1

rem 取得した日付と同じ日付のフォルダ名を検索
dir /b /ad %CSVPATH% | findstr "%YESTERDAY1%" >nul

if %errorlevel% == 0 (
 set HANTEI=○
) else (
 set HANTEI=△
)
```
```java:PatternB.bat
@echo off

set CSVPATH=%1

rem 取得した日付と同じ更新日付のファイルを検索
dir /a-d %CSVPATH% | findstr "%YESTERDAY2%" > nul

if %errorlevel% == 0 (
 set HANTEI=○
) else (
 set HANTEI=△
)
```
```java:Patternc.bat
@echo off

set HANTEI=自動化対象外
```
```java:PatternD.bat
@echo off

set CSVPATH=%1

rem 更新時刻情報を取得
set UPDATE-TIME=02:00

rem 対象ファイル1を指定
set FILE1=test1.bin

rem 指定された日付,時刻のファイル名を検索
dir /a-d %CSVPATH% | findstr "%TODAY2%" |  findstr "%UPDATE-TIME%" | findstr "%FILE1%" > nul

if %errorlevel% == 0 (
 goto :GOOD-END
)

rem 対象ファイル2を指定
set FILE2=test2.bin

rem 指定された日付,時刻のファイル名を検索
dir /a-d %CSVPATH% | findstr "%TODAY2%" |  findstr "%UPDATE-TIME%" | findstr "%FILE2%" > nul

if %errorlevel% == 0 (
 goto :GOOD-END
) 

set HANTEI=△

exit /b

:GOOD-END
set HANTEI=○
```
```java:PatternE.bat
@echo off

set CSVPATH=%1
rem 2日前の日付フォルダ名を検索
dir /b /ad %CSVPATH% | findstr "%TWODAYS_AGO%" >nul

if %errorlevel% neq 0 (
 goto :NG-END
)

rem 昨日の日付フォルダ名を検索
dir /b /ad %CSVPATH% | findstr "%YESTERDAY3%" >nul

if %errorlevel% neq 0 (
 goto :NG-END
)

rem 当日の日付フォルダ名を検索
dir /b /ad %CSVPATH% | findstr "%TODAY3%" >nul

if %errorlevel% neq 0 (
 goto :NG-END
)

set HANTEI=○

exit /b

:NG-END
set HANTEI=△
```

<h1>おわりに</h1>
完璧なものを手今日することができなかったのは悔しいですが、最低限必要な機能を実装はできました。
「PatternC」についてもイメージはあったんですが、下記の理由で断念しました。
①バックアップシステム本体は直接触れない
②自動化はしてほしいがあまり時間をかけないでほしい（ベストエフォート）
※「確認対象は1つ2つ程度だったこともあり、自動化するほどではない。」と無理矢理納得してもらいました。。。。


ただ、個人的には「自分の力でスクリプトを作成することができる」ことがわかったので、これからちょくちょくやっていこうと思います。