OSのバージョン・ビットに応じてレジストリを更新するバッチ

# 要件

 - とあるアプリケーションのレジストリをバッチで更新したい
    - `HKLM\SOFTWARE`以下なので、管理者権限ユーザのみ実行可能とする
 - 対象OSは、Windows8.1、10
    - 32bit版と64bit版両方を対象とする
 - アプリケーションがインストールされてない場合は、処理を実行しない
    - 不要なレジストリは登録しない

# 処理の流れ

 1. 管理者ユーザで、かつ、管理者権限でプロンプトを実行する
    - ローカルユーザの場合、処理中断
    - 管理者ユーザで、かつ通常プロンプトでバッチが実行された場合、管理者権限プロンプトに昇格し、以降の処理を実行する
 2. OSのバージョンをチェックする
    - Win8.1、10のみ、次処理に引き継ぐ
 3. bitをチェックする
    - レジストリが64bitと32bitで格納場所が異なるため、bitに応じて処理対象レジストリパスを判定する
 4. レジストリキーをチェックする
    - 更新対象レジストリキーが存在する事をチェックする
    - アプリケーションの存在有無は、レジストリチェックを持って代用する 
 5. レジストリキーを更新する

# レジストリ更新バッチ

```RegistoryUpdater.bat
@echo off

echo **** レジストリ更新処理: %date% %time%

SETLOCAL enabledelayedexpansion

rem -- 64bit版 レジストリのパス
set REG_64_ROOT=HKLM\SOFTWARE\Wow6432Node\Sample

rem -- 32bit版 レジストリのパス
set REG_32_ROOT=HKLM\SOFTWARE\Sample

rem -- カレントディレクトリを基準とする
cd /d %~dp0

rem ----------------------------------------------
rem --- 管理者実行チェック＆昇格処理
:checkMandatoryLevel
rem --- ▼管理者として実行されているか確認 START
for /f "tokens=1 delims=," %%i in ('whoami /groups /FO CSV /NH') do (
    if "%%~i"=="BUILTIN\Administrators" set ADMIN=yes
    if "%%~i"=="Mandatory Label\High Mandatory Level" set ELEVATED=yes
)

if "%ADMIN%" neq "yes" (
    rem -- Administratorsグループでない（ローカルユーザの場合）
    echo 管理者権限を持たない為、処理を中断します。
    
    rem --- 処理終了
    goto exit1
)
if "%ELEVATED%" neq "yes" (
    rem -- (プロセスが昇格されていない) Admin権限ありユーザが通常実行した場合
    echo このファイルは管理者権限での実行が必要です
    echo 昇格を行いますので、しばらくお待ちください
    
    goto runas
)
rem --- ▲管理者として実行されているか確認 END

:admins
    rem --- ▼管理者として実行したいコマンド START

    rem --- OSチェック処理
    CALL :checkOS

    rem --- ▲管理者として実行したいコマンド END
    goto exit1

:runas

    if "%1" == "" (
        rem --- 引数なしのため、★管理者として再実行
        @powershell -NoProfile -ExecutionPolicy unrestricted -Command "Start-Process %~f0 REPEATED -Verb runas"
    ) else (
        rem --- 引数ありのため、すでに自身を再実行している。
        rem --- 処理終了
        echo 管理者への昇格に失敗しました。処理を中断します。
    )

goto exit1

rem ----------------------------------------------
rem --- OSチェックサブルーチン
:checkOS

echo OS: 
call ver

rem --- OSのバージョン確認(Win7) → 処理中断
ver | find /i "Version 6.1." > nul
if %ERRORLEVEL% equ 0 goto :checkOS_WIN7
rem --- OSのバージョン確認(Win8.1) → bitチェック
ver | find /i "Version 6.3." > nul
if %ERRORLEVEL% equ 0 goto :checkBit
rem --- OSのバージョン確認(Win10) → bitチェック
ver | find /i "Version 10.0." > nul
if %ERRORLEVEL% equ 0 goto :checkBit
rem --- それ以外の場合、処理終了
goto :exit1

exit /B


rem ----------------------------------------------
rem -- OSチェック結果：Win7
:checkOS_WIN7
echo Windows7は処理対象外のため、終了します。

goto :exit1

exit /B


rem ----------------------------------------------
rem -- bitチェック
:checkBit

echo bit: %PROCESSOR_ARCHITECTURE%

rem --- OSのbit確認(64bit)
if %PROCESSOR_ARCHITECTURE% == AMD64 GOTO :checkBitResult64
rem --- OSのbit確認(32bit)
if %PROCESSOR_ARCHITECTURE% == x86 GOTO :checkBitResult32
rem --- それ以外の場合、処理終了
goto :exit1

exit /B


rem ----------------------------------------------
rem -- bitチェック結果(64bit)
:checkBitResult64

rem -- 64bit版のパスを保持する
set REG_ROOT=%REG_64_ROOT%

rem -- レジストリ確認処理実行
goto :checkpRegistory

exit /B


rem ----------------------------------------------
rem -- bitチェック結果(32bit)
:checkBitResult32

rem -- 32bit版のパスを保持する
set REG_ROOT=%REG_32_ROOT%

rem -- レジストリ確認処理実行
goto :checkpRegistory

exit /B



rem ----------------------------------------------
rem -- レジストリ確認処理
:checkpRegistory

echo レジストリ確認: %REG_ROOT%

reg query %REG_ROOT% /v EnableSample | find /i "EnableSample" > nul
rem -- レジストリが存在するため、レジストリ更新処理実行
if %ERRORLEVEL% equ 0 goto :updatepRegistory
rem --- それ以外の場合、処理終了

echo 更新対象レジストリが存在しないため、処理を中断します。

goto :exit1

exit /B


rem ----------------------------------------------
rem -- レジストリ更新処理
:updatepRegistory

echo レジストリを更新します。

rem -- レジストリ更新処理実行
reg add %REG_ROOT% /v EnableSample /t REG_DWORD /d 1 /f

rem -- 処理終了
goto :exit1

exit /B




rem ----------------------------------------------
rem -- 終了処理
:exit1

    echo **** レジストリ更新処理終了
    
    exit

```

参考)
 - [バッチファイル(*.bat) を管理者として実行するための バッチファイル](http://qiita.com/jTakasuRyuji/items/e7bd576ed57969b2d06e)
 - [Windows OS のバージョン情報を判定して条件分岐させるバッチファイル【共通編】](https://automationlabo.com/wat/enc/ext/w10-verfind/)
 - [コマンドプロンプトで64bitか32bitを調べる方法: 京都きもの屋IT系ブログ](http://hiroses.seesaa.net/article/247418901.html)

# おまけ

上記バッチには不採用になったが、色々なパターンを想定してたサンプルを作ったので、供養。

## アプリケーションのバージョンチェック

EXEやDLLのプロパティ＞詳細＞ファイルバージョンに記載されている値を取得するバッチコマンド
＃どっちかというと、Powershellの結果をバッチ側で取得するサンプル、かな…

```ExeVerCheck.bat
set EXE_PATH=C:\Program Files\Microsoft Office\Office14\EXCEL.EXE

echo EXEパス: %EXE_PATH%

FOR /F "usebackq" %%i IN (`Powershell -Command "return (Get-ItemProperty '%EXE_PATH%').VersionInfo.FileVersion"`) DO SET EXE_VER=%%i

echo EXEバージョン: %EXE_VER%
```

## レジストリの更新チェック

該当レジストリキーの項目だけ更新できているかチェック。
他のキーを更新している等、diff結果が該当キー以外にもヒットした場合、リストアする。

```RegDiff.bat
rem -- 管理者権限チェック・昇格処理は省略。

rem -- 更新対象レジストリパス
set REG_ROOT=HKLM\SOFTWARE\Sample\

rem -- ★比較用レジストリファイル
set REG_BEFORE=RegBefore.reg
set REG_AFTER=RegAfter.reg

rem -- カレントディレクトリを基準とする
cd /d %~dp0

rem ---------------------------------------------------
rem -- レジストリ確認処理
:checkRegistory

echo レジストリルート: %REG_ROOT%

rem -- レジストリ存在チェック
reg query %REG_ROOT% /v EnableSample | find /i "EnableSample" > nul
rem -- レジストリが存在するため、レジストリ更新処理実行
if %ERRORLEVEL% equ 0 goto :changeRegistory

rem --- それ以外の場合、処理終了
echo レジストリが存在しないため、処理を中断します。

goto :exit1

rem - サブルーチンの終了
exit /B



rem ---------------------------------------------------
rem -- レジストリ更新処理
:changeRegistory

rem -- ★変更前レジストリを保存(上書き許可)
reg export %REG_ROOT% %REG_BEFORE% /y

echo レジストリを更新します。
reg add %REG_ROOT% /v EnableSample /t REG_DWORD /d 1 /f

rem -- ★更新後のレジストリを保存(上書き許可)
reg export %REG_ROOT% %REG_AFTER% /y

rem -- ★レジストリファイルの比較
rem -- fc: Windows標準diffコマンド
rem -- 不一致行の前後の一致行も常に表示される
rem -- /uオプション: unicodeで比較する
fc /U %REG_AFTER% %REG_BEFORE%

rem -- レジストリ比較結果保持
set REG_DIFF=""

rem -- ★実際に相違のある行のみを表示する
rem -- F=0 → ***** に囲まれたファイル1表示の外側
rem -- F=1 → ファイル1表示の先頭行なので表示しない
rem -- F=2 → ファイル1表示の2行目。F=3の処理と合わせるため一時保管しておく
rem -- F=3 → 同3行目以降。最終行かもしれないのですぐに表示出来ないので一時保管する
rem --　　　　ただし、さっき一時保管した行があるはずなのでまずそれを表示する
rem -- ***** %1 と等しい行 → F=1にする
rem -- ***** %2 と等しい行 → 最終行が保管されているが表示せずF=0にする
set F=0
for /f "skip=1 delims=" %%A in ('fc /U %REG_AFTER% %REG_BEFORE%') do (
    if /i "%%A"=="***** %REG_BEFORE%" ( set F=0
    ) else if /i "%%A"=="***** %REG_AFTER%" ( set F=1
    ) else if !F!==1 ( set F=2
    ) else if !F!==2 ( set F=3&set SAVE=%%A&set REG_DIFF=%REG_DIFF%_%%A
    ) else if !F!==3 ( echo.!SAVE!&set SAVE=%%A)
)

rem -- 比較部分の文字列からダブルクォーテーションを除く
set REG_DIFF=%REG_DIFF:"=%

rem -- 正常に更新された場合
if "%REG_DIFF%" == "_EnableSample=dword:00000001" goto :updatedRegistory
rem -- 更新が行われなかった（既に更新済み）の場合
if "%REG_DIFF%" == "" goto :updatedRegistory
echo レジストリが不正に更新された可能性があります。restoreします。
goto :restoreRegistory

exit /B



rem ---------------------------------------------------
rem -- レジストリ更新正常終了
:updatedRegistory

echo レジストリが正常に更新されました。

goto exit1

exit /B



rem ---------------------------------------------------
rem -- レジストリ更新以上終了
:restoreRegistory

echo レジストリの更新に失敗したため、リストアします。

reg import %REG_BEFORE%

goto exit1

exit /B


:exit1

    exit

```

参考) [ファイル比較結果の相違点のみ取得したい (DOSプロンプト活用相談室LOG)](http://fpcu.on.coocan.jp/dosvcmd/bbs/log/fccomp/3-0732.html)