元号が平成から令和になり、会社で使用しているとあるアプリに、令和対応アップデータが公開されていました。
当然、このアップデータをインストールしないと令和表示ができないので、インストールしなければいけないのですが…何十台ものPCに手動でアップデートするのは正直しんどい。
そこで、以前組んだ「ネットワーク越しにスタートアップファイルを入れ替える」処理を応用して、各クライアントPCの起動時にインストール処理を動かして、各自でインストールしてもらう方法にしてみました。
その手順をめもめも。
ちなみに、ネットワーク越しにスタートアップファイルを入れ替える処理は以下の記事で紹介しています。
まずは大前提
ネットワーク越しにスタートアップファイルを入れ替える処理のときと同様、ログオンスクリプト代わりのVBSが、既に各クライアントPCのスタートアップに置いてあり、サーバ上のバッチファイル「logon_scripts.bat」を実行できていることが前提です。
各クライアントPCが、起動時にサーバ上のバッチファイルを実行できる状態に無ければ、「VBSをログオンスクリプトの代用に」の記事のように設定・設置してください。
アップデータを実行するVBS
アップデータを各クライアントPCにコピーすれば、PC起動時に自動でアップデータが起動しますが、この方法だとPCを起動するたびに毎回インストールが始まってしまいますので、却下。
また、全てのPCにアプリがインストールされている訳ではないので、アプリがインストールされていたらアップデータを実行する、という処理が必要。
インストールされているか確認
ということで、まずはレジストリを参照して、アプリがインストールされているか確認。割と決め打ちです。
Set objShell = CreateObject( "WScript.Shell" )
strExePath = objShell.RegRead( "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\APPLICATION.exe\" )
インストーラからインストールしたアプリの実行ファイルは、ファイル名だけで実行されるように、レジストリに登録されるようです。それを応用した確認方法です。
アプリがインストールされていれば、strExePathにインストール先フルパスが返ってきます。インストールされていなければ空なので、IsEmpty()で判断できます。
アプリのバージョンを取得
アプリの製作者がきちんと実行ファイルのバージョン情報を更新してくれていれば、実行ファイルのバージョン情報を取得して最新かどうか判別できます。
Set objFS = CreateObject( "Scripting.FileSystemObject" )
strVersion = objFS.GetFileVersion( strExePath )
最新版のバージョンとstrVersionの値を文字列比較して、違っていたらインストーラを実行させればいいですね。
残念なことに、今回アップデートしようとしたアプリは「令和対応」させるだけのアップデートなので、実行ファイルのバージョンが更新されていなかったため、この方法は使えず。
仕方がないので、実行ファイルの更新日時で比較することにしました。
まず、1台のPCに手動でアップデートをインストールし、実行ファイル一式の更新日時を確認します。幸い、新旧実行ファイルで更新日時が違っていたので、決め打ちで判断できました。
strExeDate = Left( objFS.GetFile( strExePath ).DateLastModified, 4 )
If strExeDate = "2019" Then
MsgBox "すでに更新されています。", vbInformation + vbSystemModal, "お知らせ"
WScript.Quit(0)
End If
アップデート前の実行ファイルが2018年のものだったので、先頭4桁(西暦部分)だけで判断しています。
アプリをサーバからコピーし実行
ここまでくれば、あとはアップデータをコピー(ダウンロード)して実行するだけ。コピー先は、ローカルPCのテンポラリフォルダにしています。
strFilePathFrom = "サーバにおいてあるアップデータまでのフルパス"
strFilePathTo = objFS.GetSpecialFolder(2).Path & "\アップデータのファイル名"
Call objFS.CopyFile( strFilePathFrom, strFilePathTo )
iReturn = objShell.Run( strFilePathTo, 1, True )
CopyFile()でサーバからローカルにアップデータをコピーし、Run()でアップデータを実行します。Run()のパラメータは、1番目が実行ファイルフルパス、2番目がウィンドウスタイル(1はアクティブ表示)、3番目がアップデータの終了を待つ指示(Falseだと待たない)。
処理的にはこれでアップデータが一度だけ(もし途中で失敗していたら成功するまで)実行されます。
処理の一連の流れ
ということで、エラー処理も含めた一連の流れはこんな感じ。
Option Explicit
Dim objFS, objShell
Dim strFilePathFrom, strFilePathTo, strExePath, strExeDate
Dim iCount, iReturn
'エラー発生時にも処理を続行するよう設定
On Error Resume Next
'ファイルシステムを扱うオブジェクトを作成
Set objFS = CreateObject( "Scripting.FileSystemObject" )
Set objShell = CreateObject( "WScript.Shell" )
'アプリのインストール先を確認する
strExePath = objShell.RegRead( "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\アプリの実行ファイル名\" )
If IsEmpty( strExePath ) Then
'エラー処理
WScript.Quit(-1)
End If
'アップデート対象ファイルの更新日時を取得する
strExeDate = Left( objFS.GetFile( strExePath ).DateLastModified, 4 )
If strExeDate = "2019" Then
WScript.Quit(0)
End If
'アップデート処理を行うメッセージを出力する
MsgBox "[アプリ名]のアップデートを行います。", vbInformation + vbSystemModal, "お知らせ"
'コピーファイルのパスを指定
strFilePathFrom = "サーバに置いてあるアップデータの実行ファイルフルパス"
strFilePathTo = objFS.GetSpecialFolder(2).Path & "\アップデータの実行ファイル名"
'ファイルを上書きコピー
Call objFS.CopyFile( strFilePathFrom, strFilePathTo )
'元ファイルが無いなど、エラーになった場合の処理
If Err.Number <> 0 Then
'エラー処理
WScript.Quit(-1)
End If
'ファイルコピーを待つ
iCount = 0
Do While objFS.FileExists( strFilePathTo ) = False
iCount = iCount + 1
WScript.Sleep 500
'30秒待ってもコピーが終わらない場合はエラー終了する
If iCount >= 60 Then
'エラー処理
WScript.Quit(-1)
End If
Loop
'ファイルを実行する
iReturn = objShell.Run( strFilePathTo, 1, True )
'ファイル実行時、エラーになった場合の処理
If iReturn <> 0 Then
'エラー処理
WScript.Quit(-1)
End If
'「On Error Resume Next」を解除
On Error Goto 0
Set objShell = Nothing
Set objFS = Nothing
WScript.Quit(-1)
今回インストールするアップデータは、途中で処理を中断しても正常終了として戻ってきてしまうため、正常に終了した場合でもVBS側からは異常終了としています。
こうすることで、アップデータをインストールしないで終了した場合は、再度インストール処理を。きちんとインストール処理が完了していれば、ファイルの更新日時が変わっているので正常終了する、という動きになるからです。
そして、このVBSの呼び元で、正常終了で戻ってきたらインストール完了とするフラグを立てる、と。
決め打ちが多いのが難点
本来はもっと柔軟に対応できるような作りをすべきですが、今回は割と時間がない中で処理を作り、テストし、実行する必要があったので、決め打ちしているところがだいぶ多いです。
でも、こんな処理でも何かの参考になれば、ということで。
コメント