treedown’s Report

システム管理者に巻き起こる様々な事象を読者の貴方へ報告するブログです。会社でも家庭でも"システム"に携わるすべての方の共感を目指しています。

※https化しました。その影響でしばらくリンク切れなどがあるかもしれませんが徐々に修正していきます。 リンク切れなどのお気づきの点がございましたらコメントなどでご指摘いただけますと助かります。

バッチファイルでアプリケーションのバージョンを比較して実行

前回でCubePDFのバージョン情報が収集できたので、ファイル名に記載されたバージョン情報と比較して、インストール有無を判断するバッチファイルに仕上げていきます。
難航した比較処理のための文字列操作、何とか完成しました。

比較処理を追加してみる

PCにインストール済CubePDFのバージョン情報を格納した変数%CPver%と、インストールファイルに記載された(ファイル名内の)バージョンの変数%InstFileNum%を比較してみます。

--------------------------------------------------------------
バッチファイルの比較部分を前回に追加
--------------------------------------------------------------
@echo off
set CPver=

rem 一時ファイル生成
reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{4DB5CF1C-F10E-4C4D-84D7-2525CFAB8F6C}_is1" | findstr "DisplayVersion">CubePVerCHK.txt
set /P CPver=<%CD%\CubePVerCHK.txt
set CPver=%CPver:~-8%
set CPver=%CPver: =%
del %CD%\CubePVerCHK.txt

rem インストール済みバージョンとインストールファイルバージョンを比較する
echo .
echo ここから比較処理に入ります。
rem メジャーバージョンの比較
echo 比較 %CPver% と %InstFileNum%

    if %CPver% GTR %InstFileNum% (
        echo インストールされているバージョンが新しい
    ) else (
        if %CPver% EQU %InstFileNum% (
            echo インストールバージョンと同じ
        ) else (
            if %CPver% LSS %InstFileNum% (
                echo 新バージョンをインストールします。
            )
        )
    )

set CPver=
--------------------------------------------------------------

それぞれ対象となるファイル名を書き換えてバッチファイルを実行してみた結果、(左がインストール済のバージョンで、右がインストールファイル名から取得したバージョンでの比較)

--------------------------------------------------------------
>CubePVerCHK.bat 実行結果
--------------------------------------------------------------
ここから比較処理に入ります。
比較 1.5.2 と 1.15.2
インストールされているバージョンが新しい
--------------------------------------------------------------
.
ここから比較処理に入ります。
比較 1.5.2 と 1.60.2
新バージョンをインストールします。
--------------------------------------------------------------
.
ここから比較処理に入ります。
比較 1.5.2 と 1.00.2
インストールされているバージョンが新しい
--------------------------------------------------------------
.
ここから比較処理に入ります。
比較 1.5.2 と 1.5.21
新バージョンをインストールします。
--------------------------------------------------------------
.
ここから比較処理に入ります。
比較 1.5.2 と 1.10.21
インストールされているバージョンが新しい
--------------------------------------------------------------

単純にsetで代入したバージョン情報は文字列として扱われるにしても不思議な結果。
上記以外でもいろいろと数字を入れて確認してみた結論として、
「1.5.2」は「1.52」として計算されており、比較対象がそれぞれ、「1.15.2」は「1.152」、「1.60.2」は「1.602」、「1.00.2」は「1.002」、「1.5.21」は「1.521」、「1.10.21」は「1.1021」と計算されているのではないかと考えました。これだと、上記のように比較結果が出ているのは納得がいきます。

そうだとすると、バージョン情報の二つ目の数字が二桁になると意図しない動作となってしまうことから、この方法でバージョンを比較するのは誤動作の元になってしまう、という結論になり、別の方法でバージョンを比較する必要が出てきました。

もう一つの方法:forで数字を取得する

そこで、他の方法はないかを探したとき、「tokens=」が使えそうということで調べてみることにしました。
バージョンは「.」で区切られた三種類の個別の数字を比較しないと正確にバージョンが上下と判断出来ないためです。

例えば前述の変数%CPver%に以下のfor文を追加してみると
--------------------------------------------------------------
FOR /F "delims=. tokens=1,2,3" %%i in ("%CPver%") DO echo %%i %%j %%k
--------------------------------------------------------------
実行結果として画面には
--------------------------------------------------------------
1 5 2
--------------------------------------------------------------
こんな風に表示されます。「.」区切りのデータを個別に取得できています。これ使えるんじゃないかなとおもいはじめました。
忘れる前に備忘録。

「delims=」で、区切り文字を指定します。
今回は「1.5.2」と「.」ピリオドが区切り文字となっていますので、上述のように「delims=.」という具合に指定します。
他にも「:」コロンとか「;」セミコロンとか、「,」カンマとかを指定してデータの区切りを指定できます。

「tokens=」で、収集するデータをいくつ収集するかを指定します。
今回「1.5.2」と「.」ピリオド区切りの三つの数字を変数に保管したいため、上述では「tokens=1,2,3」と指定しています。その次に「%%i」と指定して%%i %%j %%kにそれぞれ数字が格納されます。

これらを条件に分解するデータを指定した後、do以降の命令を実行してくれます。

これをそれぞれ変数に入れて比較すれば、やりたいことができそうと考えました。

やってみる

試しに、前述のfor文を以下のようにしてみました。
--------------------------------------------------------------
FOR /F "delims=. tokens=1,2,3" %%i in ("%CPver%") DO (
    set MgVerL=%%i
    set MiVerL=%%j
    set SubVerL=%%k
    )
echo %MgVerL%-%MiVerL%-%SubVerL%
--------------------------------------------------------------

do以降でfor文内だけで有効な変数から変数に値を保管して、for文終了後、保管した数字をechoの画面出力で確認。
実行結果は、
--------------------------------------------------------------
1-5-2
--------------------------------------------------------------
と画面表示されました。好感触です。

あとは、両方のバージョンの数字を(前述のように)if文で比較すれば達成可能です。注意深く判定を作ってバッチファイルを完成させました。

完成版

完成版のバッチファイルです。もっと汎用的にしようと思っていたのですが、けっきょくCubePDFのインストール.exeの専用のようになってしまいました。

インストールの.exe実行は予め取得してあるファイルパス(%InstFileDir%)とファイル名(%InstFileName%)を使って、サイレントオプションを付けてインストールを実行しています。
※サイレントオプション「/VERYSILENT」を使っていますが、「/SILENT」でも良いかもしれません。どちらにしろ、UACは動作しますし、DOS窓が表示されるのを抑制することもできませんし。

追記:
64ビット版のCubePDFインストーラ「cubepdf-0.0.0-x64.exe」を想定しています。そのため、バッチファイルの最初にOSビット数の判定で32ビット環境では何もせず終了するようにしました。
インストールファイルを保管したフォルダ名は、予め変数名「InstFileDir」に入力しておく必要があります。

インストールファイルだけが保管された状態のフォルダを「InstFileDir」のパスとして指定します。(余計なファイルが入っていると、予期しない動きが出るかも。)

f:id:treedown:20211122185040p:plain

インストール済CubePDFのバージョン取得コマンドが、実際にバージョンアップされた後だとUUIDが変わることが分かったので、急遽、前回記事のようにレジストリから取得するのを止めて、PowerShell経由でインストール済CubePDFの.exeファイルから製品バージョンを取得するように変更しました。(※既存の部分で不要な行はremでコメントアウトしました。おいおい整理していきたい。)

--------------------------------------------------------------
ファイル名:CubePVerup.bat
--------------------------------------------------------------
@echo off
set CPver=
set InstFileDir=.\InstFile-Test
set InstFileName=
set InstFileNum=

set MgVerL=
set MiVerL=
set SubVerL=
set MgVer=
set MiVer=
set SubVer=

echo .
echo CubePDFのインストールとバージョンアップを実行します。
echo .

rem OSビット数判定※64ビット環境限定
if "%PROCESSOR_ARCHITECTURE%" EQU "AMD64" goto CHKVer
if "%PROCESSOR_ARCHITECTURE%" EQU "x86" goto end
echo ERR:32bitOSは未対応環境です。このまま終了します。
goto end

:CHKVer
rem 一時ファイル生成しそこから変数に代入
rem reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{4DB5CF1C-F10E-4C4D-84D7-2525CFAB8F6C}_is1" | findstr "DisplayVersion">%CD%\CubePVerCHK.txt
Powershell -Command  (Get-ItemProperty 'C:\Program Files\CubePDF\cubepdf.exe').VersionInfo.ProductVersion>%CD%\CubePVerCHK.txt
set /P CPver=<%CD%\CubePVerCHK.txt
rem set CPver=%CPver:~-8%
rem set CPver=%CPver: =%
del %CD%\CubePVerCHK.txt
rem echo 現在のバージョン=%CPver%

rem インストール場所からファイル名を取得
pushd %InstFileDir%
FOR /F %%i in ('dir /b') DO @SET InstFileName=%%i
rem 拡張子を除いてファイル名だけ取得
FOR /F %%i in ('echo %InstFileName%') DO set InstFileNum=%%~ni
rem バージョンだけ抜き出す[cubepdf-0.0.0-x64.exeの「cubepdf-」と「-x64」を取り払う。
rem 例:置き換える場合の書式[set InstFileNum=%InstFileNum:x64=x86%]
set InstFileNum=%InstFileNum:cubepdf-=%
set InstFileNum=%InstFileNum:-x64=%
rem echo %InstFileNum%
popd

rem インストール済みバージョンとインストールファイルバージョンを比較する

rem インストール済のバージョン情報を取得
FOR /F "delims=. tokens=1,2,3" %%i in ("%CPver%") DO (
    set MgVerL=%%i
    set MiVerL=%%j
    set SubVerL=%%k
    )
rem インストールファイルのバージョン情報を取得
FOR /F "delims=. tokens=1,2,3" %%a in ("%InstFileNum%") DO (
    set MgVer=%%a
    set MiVer=%%b
    set SubVer=%%c
    )

rem メジャーバージョンの比較
rem echo %MgVerL% EQU %MgVer%の比較
    if %MgVerL% EQU %MgVer% (
rem        echo インストールされたメジャーバージョンと同じ⇒次の判定へ
        goto minorVerComp
    ) else (
        if %MgVerL% GTR %MgVer% (
rem            echo インストールされているメジャーバージョンが新しい⇒何もせず終了
            goto end
        ) else (
            if %MgVerL% LSS %MgVer% (
rem                echo 旧バージョン⇒新バージョンをインストールします。
                goto InstNewVer
            )
        )
    )

:minorVerComp
rem マイナーバージョン(二番目の数値)の比較
rem echo %MiVerL% EQU %MiVer% の比較
    if %MiVerL% EQU %MiVer% (
rem        echo インストールマイナーバージョンと同じ⇒次の判定へ
        goto RevNoComp
    ) else (
        if %MiVerL% GTR %MiVer% (
rem            echo インストールされているマイナーバージョンが新しい⇒何もせず終了
            goto end
        ) else (
            if %MiVerL% LSS %MiVer% (
rem                echo 旧バージョン⇒新バージョンをインストールします。
                goto InstNewVer
            )
        )
    )

:RevNoComp
rem Revバージョン(三番目の数値)の比較
rem echo %SubVerL% EQU %SubVer% の比較
    if %SubVerL% EQU %SubVer% (
rem         echo インストールRevバージョンと同じ⇒全て同じなので何もせず終了
        goto end
    ) else (
        if %SubVerL% GTR %SubVer% (
rem             echo インストールされているRevバージョンが新しい⇒何もせず終了
            goto end
        ) else (
            if %SubVerL% LSS %SubVer% (
rem                 echo 旧バージョン⇒新バージョンをインストールします。
                goto InstNewVer
            )
        )
    )

:InstNewVer
rem インストールファイルを実行
rem echo %InstFileDir%\%InstFileName% を実行します。
echo 新しいバージョン%InstFileName% をインストールしています。
"%InstFileDir%\%InstFileName%" /lang=japanese /verysilent /sp- /nocancel /norestart /suppressmsgboxes /nolaunch
goto end

:end
set CPver=
set InstFileDir=
set InstFileName=
set InstFileNum=
set MgrVer=
set MgrVerL=

set MgVerL=
set MiVerL=
set SubVerL=
set MgVer=
set MiVer=
set SubVer=
--------------------------------------------------------------

結局PowerShellコマンドレットを使っているあたり…、なんかイマイチです。