i-Vinci TechBlog
株式会社i-Vinciの技術ブログ

バッチファイルで作業を自動化してみた

こんにちは。昨年の4月に入社した川西です。
最近、パフォーマンステストに参加した際に新しい学びが得られました。
それはリモートサーバーからログファイルをローカルPCに直接コピーするツールを作成する方法です。
この学びを活かし、パフォーマンスモニターのログ取得を効率化するツールを作成しました。今回、その成果について記事にまとめました。

ログファイルの取得

1. 既存のツールについて

下記は、過去のテストで使っていたツールで、ログファイルをリモートサーバーからローカルPCに直接コピーするものです。

@echo off
setlocal enabledelayedexpansion

rem サーバー接続情報
set username={username}
set password={password}

rem サーバーに接続
net use {drive name} /delete
net use {drive name} /user:!username! !password!

rem ログファイルをコピー
copy {file path}

rem ネットワーク接続の切断
net use {drive name} /delete

2. フォルダ構成について

今回私が担当するテストでも、既存ツールのファイルパスを変更するだけで対応できると考えていたのですが、今回はフォルダの構成が既存のツールで対応していたものと異なっておりました。

既存のツールで対応できたフォルダ構成

  • 最新のログファイルがフォルダ1配下に生成される。
- Aサーバ
  - フォルダ1
    - ○○○○○○.log
    - ○○○○○○_20230202.log
    - ○○○○○○_20230203.log
- Bサーバ
  - フォルダ1
    - ○○○○○○.log
    - ○○○○○○_20230202.log
    - ○○○○○○_20230203.log

今回のフォルダ構成

最新のログファイルがフォルダ毎に生成され、フォルダ末尾のカウント数が他のサーバーと異なる。

- Aサーバ
  - フォルダ1
    - ○○○○○○.blg
  - フォルダ2
    - ○○○○○○.blg
- Bサーバ
  - フォルダ1
    - ○○○○○○.blg
  - フォルダ2
    - ○○○○○○.blg
  - フォルダ3
    - ○○○○○○.blg

3. 最新のログファイルを取得

パスを直接指定しファイルをコピーする方法は、今回のフォルダ構成(カウント数がサーバーによって異なる)では困難であることがわかりました。
そのため、最新のログファイルを探してコピーする処理に修正してみました。

rem サーバー接続情報
set username={username}
set password={password}

rem サーバーに接続
net use {drive name} /delete
net use {drive name} /user:!username! !password!

rem 各サーバーのリスト定義
set SaverName1=SaverName1
set SaverName2=SaverName2
set SaverName3=SaverName3

rem 配列に格納
set "Servers[0]=!SaverName1!"
set "Servers[1]=!SaverName2!"
set "Servers[2]=!SaverName3!"

rem 配列の要素にアクセス
for /L %%i in (0, 1, 2) do (
    set "ServerName=!Servers[%%i]!"
    set "targetFolder=\\!ServerName!\○\○○○\○○○○○○"
    set "latestSubfolder="
    set "latestDate=0"

    rem 指定されたフォルダ内のサブフォルダを、最終更新日が最新の日付順に取得します。
    for /F "delims=" %%I in ('DIR /AD /B /O-D "!targetFolder!"') do (
        set "subfolderDate="

        rem 各サブフォルダ内のファイルの中で最新更新日付のものを"subfolderDate"変数に代入します。
        for /F %%A in ('DIR /TW /OD /A-D "!targetFolder!\%%I" 2^>nul ^| find "."') do set "subfolderDate=%%A"

        rem "latestDate"よりも大きい場合(最新の日付である場合)に処理を実行します。
        if !subfolderDate! gtr !latestDate! (

            rem latestDateに最新の日付を設定します。
            set "latestDate=!subfolderDate!"

            rem latestSubfolderに最新のサブフォルダパスを指定します。
            set "latestSubfolder=!targetFolder!\%%I"
            mkdir "!ServerName!"
            copy "!latestSubfolder!\*" "!ServerName!"
        )
    )
)

rem ネットワーク接続の切断
net use {drive name} /delete

今回修正したBatchは、次のログが生成されるまでの間に起動して、ログ取得をする必要があります。
例えば、下記のように3/1以降の毎日9:00~21:00までパフォーマンスモニターを起動させるように設定した場合、
3/1のパフォーマンスモニターのログをコピーするには、3/2の9:00までにBatchを起動する必要があります。

  • 開始時間を設定
    開始時間の設定

  • 停止時間を設定
    停止時間の設定

当日にログを取得できなかった場合

もし当日にBatchを起動し忘れた場合や、例外的に前日のログが必要になった場合、新たにフォルダが生成されるためログが取得できません。

対策としての追加機能

対策として2番目に新しいログファイルを取得できるBatchを作成しました。
これで3. 最新のログファイルを取得で紹介したBatchで最新ログを、以下追加で作成したBatchで2番目に新しいログをそれぞれ取得できるようになります。
本来であれば、1つにまとめてしまいたかったのですが、私の理解が浅い部分もあり期日内には難しかったため、これで妥協することになりました。
ただ、テストのログを取り損ねることを回避するという目的は達成できました。

rem 配列の要素にアクセス
for /L %%i in (0, 1, 2) do (
    set "ServerName=!Servers[%%i]!"
    set "targetFolder=\\!ServerName!\○\○○○\○○○○○○"
    set "latestSubfolder="
    set "latestDate=0"
    set "secondLatestSubfolder="
    set "secondLatestDate=0"

    rem 指定されたフォルダ内のサブフォルダを、最終更新日が最新の日付順に取得します。
    for /F "delims=" %%I in ('DIR /AD /B /O-D "!targetFolder!"') do (
        set "subfolderDate="

        rem 各サブフォルダ内のファイルの中で最新更新日付のものを"subfolderDate"変数に代入します。
        for /F %%A in ('DIR /TW /OD /A-D "!targetFolder!\%%I" 2^>nul ^| find "."') do set "subfolderDate=%%A"

        rem "latestDate"よりも大きい場合(最新の日付である場合)に処理を実行します。
        if !subfolderDate! gtr !latestDate! (
            rem "latestDate"に最新の日付を設定します。
            set "latestDate=!subfolderDate!"

            rem "latestSubfolder"に最新のサブフォルダパスを指定します。
            set "latestSubfolder=!targetFolder!\%%I"

        )else if !subfolderDate! gtr !secondLatestDate! (
            rem "secondLatestDate"に2番目に最新の日付を設定します。
            set "secondLatestDate=!subfolderDate!"

            rem "latestSubfolder"に最新のサブフォルダパスを指定します。
            set "secondLatestSubfolder=!targetFolder!\%%I"
        )
    )

    rem "secondLatestSubfolder"に値がある場合処理を実行。
    if defined secondLatestSubfolder (
        mkdir "!ServerName!"
        copy "!latestSubfolder!\*" "!ServerName!"
    )
)

rem ネットワーク接続の切断
net use {drive name} /delete

さいごに

最初は10以上のサーバーからログファイルを手動で取得していましたが、ログファイルを自動で取得するバッチを作成したことで、課題であった作業時間を大幅に短縮できました。
また、対象のログファイルを指定する処理には少し悩みましたが、プロジェクトメンバーと相談した結果、更新日付から最新のファイルを取得するというアプローチにたどり着きました。
この経験は非常に勉強になりました。

最後まで読んでいただきありがとうございました。