ノウハウいっぱいのiniファイルも扱える、Windows用バッチのテンプレート作りました。

## かなり大げさなバッチテンプレートです。

バッチ作ってますか？
もともと、ちょっとした小さなツールを作るのに向いてますよね。

でも、Windowsバッチの大きなメリットって、「動作させるために環境を整える必要がない。」
ってところですね。
それを生かして、結構なことでもバッチで作ることがあります。

特にサーバサイドで動かしたり、様々な環境のPCで動かしたり。

そんな時、このバッチテンプレートを参考にすると、結構面倒なiniファイル処理も出来るし、日付の処理なんかのノウハウもぶっこんでますので、活用ください。

## ちょっと、いや、かなりオーバースペックです(^^)/

テンプレートと書きましたが、かなり過剰になってます。
とはいえ、バッチなので重いとかではないです。

とりあえず、しょうもないサンプルですが、修正の仕方も中に書いてあります。
ちょっと面白いと思うので、必要なところだけ、かじってもらえれば幸甚です。

バッチのソースは、以下の通りです。
ご自由にお使いください。

```bat:bat_template.bat
@echo off
rem ※このファイルを拡張子.txtで入手した場合は、拡張子を.batに変更してから利用ください。

rem このバッチは、様々なノウハウが詰まった、バッチプログラムのテンプレートになります。
rem サンプルのメインプログラム内のサンプルにもヒントがあるので参照ください。
rem テンプレートの機能としては、以下の機能があります。
rem １．iniファイルの読み込み
rem     iniファイルの読み込みを行います。
rem ２．iniファイルの生成
rem     iniファイルを配布しなくても、動くよう、iniファイルを生成する機能があります。
rem     その際、画面からの入力を促すこともでき、選択肢にあるかどうかチェックすることもできます。
rem ３．その他、キャラコードやバージョン表示など

rem ちょっと機能を盛り込みすぎた感はありますが、iniファイルも使える使うテンプレートです。

rem このテンプレート使うときは、変更箇所が、5か所あります。
rem このバッチをコピーして、以下の5か所を変更してください。
rem 1 (システム環境)、2 (初期設定ファイル環境)、3 (メインプログラム)、4 (バッチの説明)、5 （自動生成する、初期設定ファイル）

rem それぞれの変更箇所は、
rem ===== START-n ====================================================================================
rem ===== END-n ====================================================================================
rem のようにremで囲んでますので、その中を変更してください。
rem もちろん、それ以外のこの文みたいなremは不要ですので、ご自由に削除ください。

rem 初回実行時にカレントディレクトリに説明付きの「iniファイル」のサンプルを作成することが出来ますので、
rem 「iniファイル」が必要だが、ほとんどの人が同じ設定で、一部の人だけiniファイルを変更する場合などは、
rem バッチの配布が簡単になります。

rem ===== START-1 (システム環境)====================================================================================
rem 下記コマンドは、必要に応じてコメントにしてください。
rem 意味が分からない場合は、このままでも問題ないと思います。
rem setlocal enabledelayedexpansionは、メリットデメリットなどあるので、興味がある方はネットで調べてください。
rem なお、作者名を書いておくと、分からないときの質問が出来るので便利です。
rem また、バージョンを書いておくと、HELP画面で表示するので、質問を受けるときに便利です。
rem created by XX 2023/4/14
set bat_ver=1.1
setlocal enabledelayedexpansion
rem 日本語windowsではshift-jis指定が無難なんですよね。
chcp 932
rem ===== END-1 ====================================================================================

rem ===== START-2 (初期設定ファイル環境)====================================================================================
rem ★iniファイルが不要な場合は、次の行をコメントにしてください。
rem iniファイルの生成や読み込みの機能が動かなくなります。
set ini_file=%~n0.ini
rem ★iniファイルは必要だが、自動生成するのでなく、どこかから入手してほしい場合は、下記変数に入手方法を書き込んでください。
rem ★初期値をこのバッチ内の値で自動生成したい場合は、自動生成にしておいてください。
rem 同じ変数に異なる値をセットすると、上書きされますので、今は、自動生成になっています。
set get_ini=初期設定ファイルは、ポータルで配布していますので、ポータルから自拠点の初期設定ファイルを入手してください。
set get_ini=自動生成
rem ===== END-2 ====================================================================================

rem パラメータ分析
rem /iは大文字と小文字を区別しません。残念ながら全角は別物になってしまいます。
if '%1'=='/?' ( goto :usage )
if /i '%1'=='/h' ( goto :usage )
if /i '%1'=='/help' ( goto :usage )
if /i '%1'=='/delete' ( goto :delete_ini_file )
if /i '%1'=='/type' ( goto :type_ini_file )

rem 初期設定ファイル読み込み
if not "%ini_file%"=="" ( 
    rem iniファイルを読み込みます。
    if not exist %ini_file% ( goto :usage )
    echo %ini_file%からパラメータを読み込みます。
    for /f "tokens=1,* delims==" %%a in (%ini_file%) do (
        if not "%%b"=="" set %%a=%%b
        )
    )

rem ===== START-3 (メインプログラム)====================================================================================
rem ここから、メインのバッチをコーディングします。
rem 以下はサンプルコードなので削除してください。

rem 今日の日付など、時々必要になります。
set today=%DATE%
rem ファイル名に使う場合はこんな感じ。
set today_file=%HOMEDRIVE%%HOMEPATH%\%today:/=%_LOG.txt

rem 昨日の日付のサンプルです。バッチで機能や明日を求めるのは難しいのでPowerShellを利用します。
rem PowerShellはデフォルトでインストールされているので、ほぼ動きますが、セキュリティー上禁止している場合もあります。
rem その場合は、このサンプルもエラーになります。
rem なお、adddaysの部分を+1に変えれば明日もできます。
for /F %%i in ('powershell (Get-Date '%today%'^).Adddays(-1^).ToString('yyyy/MM/dd'^)') do (set yesterday=%%i)

rem ファイルの更新日も便利です。
for %%i in (%~nx0) do set "UPDATE=%%~ti"

rem バッチには数字を返す機能があります。
rem 外部からの呼び出しでも内部のサブルーチンでもリターンコードは利用できます。
rem exit /b %ret_code%で戻すと、コール側は%ERRORLEVEL%という変数で参照できます。
rem 数字だけですが、値を返すことができます。
rem 特に外部からの呼び出し時は、0が正常で、それ以外はエラーとするケースが多いです。
rem なお、注意点として、ERRORLEVELという変数には直接値をセットしないでください。
rem 特殊変数らしく、「set ERRORLEVEL=値」でセットすると、リターン値として使えなくなるそうです。
set ret_code=100

echo today=%today%
echo today_file=%today_file%
echo yesterday=%yesterday%
echo update=%update%
echo ret_code=%ret_code%

rem iniファイルの値が読み込めていることが分かります。
if defined WORK_FILE ( echo WORK_FILE=%WORK_FILE% )
if defined debug_mode ( echo debug_mode=%debug_mode% )
if defined syain_id ( echo syain_id=%syain_id% )
if defined busyo_id ( echo busyo_id=%busyo_id% )

rem ===== END-3 ====================================================================================

exit /b %ret_code%

rem -----------------------------------------------------------------------------------------
rem 以下、サブルーチン群
rem -----------------------------------------------------------------------------------------

:usage
echo 【概要説明】   [%~f0 : ver %bat_ver%]

rem ===== START-4 (バッチの説明)====================================================================================
echo このバッチの説明を書きます。
echo.
echo 【使い方】
echo 使用法: %~n0 [/type , /delete]
echo.
echo /typeを指定すると、iniファイルを表示できます。
echo /deleteを指定すると、iniファイルを削除できます。
echo.
echo など、使い方を書きます。
echo.
rem ===== END-4 ====================================================================================

if "%ini_file%"=="" ( exit /b )

rem 以下は、iniファイルの生成部分です。
rem 「%ini_file%を定義している」＋「iniファイルが無い」＋「%get_ini%が「自動生成」になっている」の3つの条件がそろった場合、
rem 画面で確認して、生成します。

if exist %~n0.ini ( 
	echo ※ iniファイルは作成済みです。
	echo 表示する場合は /typeを 削除する場合は /deleteを付けてください。
	exit /b )

echo ★ 環境に合わせた「%~n0.ini」が必要です。
if "%get_ini%"=="自動生成" (
  echo このまま、「%~n0.ini」をカレントディレクトリに作成することも可能です。
  set /p ans="「%~n0.ini」を作成しますか (y/n)"
  IF /i "!ans!"=="Y" ( 
		goto :make_ini_file
	) else ( 
		echo "y"以外が押されました。)
) ELSE (
	echo ==================================
	echo %get_ini%
	echo ==================================
	echo.
)
echo 初期設定ファイル（%~n0.ini）を作成せずに、終了します。
exit /b

:make_ini_file
rem この行だけ、iniファイルへの書き込みがリダイレクトは追加でなく、新規書き込みになってます。（＞の数が1つです。）
rem 修正する場合は注意ください。
echo [環境に合わせて設定してください。]>%~n0.ini

rem ===== START-5 （自動生成する、初期設定ファイル）=============================================================================
rem 以下、STARTからENDは、iniファイルの自動生成サンプルです。初期値をセットしたい変数を設定ください。
rem echo ;で始まっているものは、iniファイルのコメントになります。
rem A=Bという書き方が、変数Aに初期値Bを入れるという意味になります。
rem echo.で空行が入れられます。
rem 初期値を「1桁の数字」とする場合は、スペースを追加しないと、ハンドルと勘違いされてファイル出力しなくなるので、注意ください。
rem 一方、文字列をセットする場合に、スペースを入れてしまうと変数にスペースまで入ってしまいますので、その場合はスペースは入れないでください。
rem また、サンプルの最後にあるdebug_modeのように2回出てくる場合は、後で出てきた方が上書きすることになります。

rem 大体こんな感じで、初期値をセットしていきます。
rem ; でコメントを追加することを推奨します。
echo ; OUT_FOLDERは、出力用フォルダーです。>>%~n0.ini
echo OUT_FOLDER=%HOMEPATH%>>%~n0.ini
echo ; WORK_FILEは、作業用ファイルです。>>%~n0.ini
echo ; 書き込み可能なフォルダーを指定ください。>>%~n0.ini
echo WORK_FILE=%TEMP%\$$$work.$$$>>%~n0.ini
echo.>>%~n0.ini

rem リダイレクトをハンドルリダイレクトと誤認されないように、初期値を1桁の数字とする場合、スペースを追加しないといけないので、要注意です。
echo repeat_count=3 >>%~n0.ini
echo.>>%~n0.ini

rem iniファイル作成時にユーザに入力させたい場合は、以下のサブルーチンを使います。
rem デフォルト値がある場合は、2番目のパラメータで指定します。
call :set_input 社員番号 %USERNAME%
echo syain_id=%ans%>>%~n0.ini

rem 上記に似ていますが、部署のように入力出来る項目を制限したい場合に使います。
rem 選択肢にはスペースを含めないでください。
set ans_list=総務部,人事部,経理部,営業部,システム部
call :set_list_input 部署 システム部
echo busyo_id=%ans%>>%~n0.ini


rem 同じ変数を2回入れておくと、iniファイルには両方書き出しますが、読み込み時に後の値が有効になります。
echo [Debug情報]>>%~n0.ini
echo ; debug modeを指定してください。>>%~n0.ini
echo debug_mode=on>>%~n0.ini
echo debug_mode=off>>%~n0.ini
rem ===== END-5 =============================================================================

echo.>>%~n0.ini
echo ★「%~n0.ini」をカレントディレクトリに保存しました。
exit /b

:delete_ini_file
if "%ini_file%"=="" ( exit /b )
if not exist %ini_file% ( 
	echo 既に%ini_file%は、削除されています。
	exit /b )
set /p ans="「%~n0.ini」を削除しますか (y/n)"
IF /i "%ans%"=="Y" ( 
  del %~n0.ini
  echo %ini_file%を削除しました。
  exit /b )
echo "y"以外が押されました。
echo 削除せず、終了します。
exit /b


:type_ini_file
if "%ini_file%"=="" ( exit /b )
if not exist %ini_file% ( 
	echo 既に%ini_file%は、削除されています。
	exit /b )
type %ini_file%
exit /b

:set_input
rem %1=入力項目の表記名（日本語が分かりやすい。）
rem %2=デフォルト値があれば指定
rem 出力は文字なので、リターンコードでは返せないため、変数ansに入れて戻します。
set question=%1を入力してください。
if not "%2"=="" set question=%question%（デフォルトは%2です。）
set ans=%2
set /p ans=%question%
IF "%ans%"=="" ( 
	echo %1は必須入力です。
	goto :set_input )
exit /b

:set_list_input
rem %1=入力項目の表記名（日本語が分かりやすい。）
rem %2=デフォルト値があれば指定
rem 出力は文字なので、リターンコードでは返せないため、変数ansに入れて戻します。
set question=%1を入力してください。
if not "%2"=="" set question=%question%（デフォルトは%2です。）
set ans=%2
set /p ans=%question%
if "%ans%"=="" (
  echo %1は必須入力です。
  goto :set_list_input )
rem 以下で、%ans_list%に登録されている値と比較します。
rem 見つかったら、ERRORLEVELが１で戻ってきます。
call :list_check "%ans_list%" %ans%
IF "%ERRORLEVEL%"=="0" ( 
  echo %ans%という%1は登録されていません。
	echo 登録された%1は以下の通りです。
	echo %ans_list%
  goto :set_list_input )
exit /b

:list_check
rem %1の文字リストに%2があったら、１を返す。
rem 見つからなかったら、0を返す。
rem 今のところ、選択できる数の最大は40にしています。
rem あまり大きくすると、エラーの場合に時間がかかります。
set check_max=40
for /l %%n in (1,1,%check_max%) do (
  call :check_from_list %1 %%n %2
  if "!ERRORLEVEL!"=="1" exit /b 1
  )
exit /b 0

:check_from_list
rem %1の文字リストの%2番目の要素が、探している%3だったら、１を返す。
rem 見つからなかったら、0を返す。
rem この位、サブルーチンにしなくてもよさそうだが、tokensの所に!!変数や%%変数を書くとエラーになる。
rem また、tokensで候補リストの1番目から順に照合するが、要素がないn番目を指定を指定しても""とかが帰ってこないから、途中でやめられない。
for /f "usebackq tokens=%2" %%a in (`echo %~1`) do (
  if "%%a"=="%3" ( exit /b 1)
  )
exit /b 0
```