VBScript でインストーラを作成する

クラウドプログラミング

Windows 環境で動作するインストーラを作成する場合、VBScript がおすすめです。
VBScript は Windows に標準で搭載されており、様々な環境の違いが想定されるクライアント PC 上で、おおむね問題なく動作することが可能であり、特別な前準備も必要としません。
また同じく実装の候補としてあがるバッチファイルよりも高機能であり、インストールに必要な機能を色々と実装することができます。

本記事では VBScript でインストーラを作成する際に必要になりそうなポイントについて、いくつか実装例をご紹介したいと思います。


前提条件
本記事で紹介するスクリプトは、CScriptでの動作を前提としています。
コマンドプロンプト上にインストールの実行ログを出力することを想定しているからです。
なお、ダイアログ型のメッセージ出力は、Msgboxを利用して実装します。

コマンドプロンプト上に実行ログを表示する


管理者権限で実行する
例えばProgram Filesフォルダ内の変更やレジストリの編集には管理者権限が必要になります。
したがってスクリプトを管理者権限で実行する必要があるのですが、ダブルクリックの実行では通常管理者権限にはなりませんし、スクリプトファイルを右クリックしても「管理者として実行」のメニューが出てきません。
この問題を解決するには、以下のようにスクリプトの最初で管理者に昇格して再実行する仕組みを組み込みます。

' 管理者権限で実行させる

Dim shApp
Set shApp = WScript.CreateObject("Shell.Application")
Dim args
Set args = WScript.Arguments

If args.Count > 0 And args.item(0) = "startAdmin" Then
	' 管理者権限モードで再実行中なら何もしない
Else
	' 管理者権限モードで再実行する
	Dim strArgs, i
	Set strArgs = ""
	For i = 0 To args.Count - 1
		strArgs = strArgs&" "&args.item(i) ' 配列に格納された引数を文字列に展開
	Next
	shApp.ShellExecute "CScript.exe", WScript.ScriptFullName&" startAdmin"&strArgs, "", "runas", 1
	WScript.Quit
End If

なお、このサンプルプログラムでは、管理者権限で実行の際にコマンドの第1引数に必ず “startAdmin” が入る仕様になりますので、コマンド引数を利用する場合は第2引数から参照するようにしてください。

右クリックの「管理者として実行」を有効にするため、スクリプトを実行するバッチファイルを作成したり、スクリプトファイルを .exe の実行ファイルに変換するなどの方法もありますが、いずれもインストールする側に右クリックを強要することになりますので、VBScript 側で対処する上記の方法が最善かと思います。

参考: VBScript / JScript を素早く・簡単に Exe ファイルにするツール MakeExe


レジストリの読み書き
RegReadRegWriteRegDeleteを使用してレジストリに読み書きします。

WshShell.RegRead
引数に参照するキー名もしくはキー名+エントリー名を指定します。
キー名を指定する場合は最後にバックスラッシュをつけます。
キー名+エントリー名を指定した場合は、エントリーの値が返ります(Function 呼び出し)。

WshShell.RegWrite
引数にキー名+エントリー名設定する値値の種類を指定します。
キーが存在しない場合はキーの作成も行われます。

WshShell.RegDelete
引数に削除するキー名もしくはキー名+エントリー名を指定します。
キー名を指定する場合は最後にバックスラッシュをつけます。
キー名を指定するとキーの削除、キー名+エントリー名を指定するとエントリーのみの削除となります。

ルートキーは以下のように省略が可能です。

HKEY_CURRENT_USER → HKCU
HKEY_LOCAL_MACHINE → HKLM

' レジストリの読み書き

Dim shell
Set shell = WScript.CreateObject("WScript.Shell")

' キーの存在を確認
Err.Clear
shell.RegRead "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5\"
If Err.Number = 0 Then
	WScript.Echo "キーは存在します。"
Else ' -2147024894
	WScript.Echo "キーは存在しません。"
End If

' 値の取得
Dim version
version = shell.RegRead("HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5\Version")
WScript.Echo ".NET Framework 3.5 version="&version

' 値の設定(キーの作成)
shell.RegWrite "HKLM\SOFTWARE\Test\Version", "1.00", "REG_SZ"

' 値の削除、キーの削除
shell.RegDelete "HKLM\SOFTWARE\Test\Version" ' 値の削除
shell.RegDelete "HKLM\SOFTWARE\Test\" ' キーの削除

Windows OS および OS 上で動作するアプリケーションには、32bit 版と 64bit 版の2種類が存在します。
32bit のアプリケーションを 64bit 版 Windows と 32bit 版 Windows にインストールした場合では、レジストリの参照・更新場所が変わります。

32bit 版アプリを 32bit 版 Windows へインストールした場合
\HKEY_LOCAL_MACHINE\SOFTWARE\・・・

32bit 版アプリを 64bit 版 Windows へインストールした場合
\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\・・・

32bit 版のアプリケーションを扱う場合は、以下のように Windows がどちらの版なのかあらかじめ判断しておくと便利でしょう。
Wos6432Nodeのキーの有無で判定します。

' 64bit / 32bit 判定

Dim os
Err.Clear
shell.RegRead("HKLM\SOFTWARE\WOW6432Node\")
If Err.Number = 0 Then
	os = 64 ' 64bit
Else
	os = 32 ' 32bit
End If


プログラム・コマンドの実行
Runを使用して外部プログラムや内部コマンドを実行します。

WshShell.Run
引数に起動するコマンドウィンドウスタイルコマンドの終了待ちをするか否かを指定します。
ウィンドウスタイルの設定値は以下の通りです。

実行コマンドのウィンドウ ウィンドウフォーカス
0非表示変わらない
1表示実行コマンドのウィンドウ
4表示変わらない
7最小化変わらない

 

' プログラム・コマンドの実行

Dim cmd

' プログラムの実行
cmd = ".\Setup.exe"
shell.Run cmd, 0, True

' 内部コマンドの実行
cmd = "cmd.exe /c copy /Y src dest"
shell.Run cmd, 0, True

基本的にRunは外部プログラムの実行を行うものなので、copyコマンドやdirコマンドなど Windows の内部コマンドは、サンプルのように、cmd.exeから実行します


作業ディレクトリを変更する
デフォルトでは VBScript の作業ディレクトリはシステムディレクトリ(Windows\system32)になっています。
作業ディレクトリを変更する場合は、WshShell.CurrentDirectoryに当該 ディレクトリ を設定します。

' 作業ディレクトリの取得
Dim crrtDir
crrtDir = shell.CurrentDirectory
WScript.Echo crrtDir

' 自身の場所を取得
Dim fso
Set fso = WScript.CreateObject("Scripting.FileSystemObject")

Dim myDir
myDir = fso.getParentFolderName(WScript.ScriptFullName)
WScript.Echo myDir

' 作業ディレクトリの変更
shell.CurrentDirectory = myDir


ファイルの読み書き
OpenTextFileを使用してファイルをオープンします。

FileSystemObject.OpenTextFile
引数にファイル名I/O モードファイル作成の有無ファイル形式を指定します。
第2引数の I/O モードの設定値は以下の通りです (省略可能、デフォルト:1) 。

I/O モード
1参照モード
2新規書き込みモード
8追加書き込みモード



第3引数にTrueを指定すると、ファイルが存在しない場合にはファイルを作成します (省略可能、デフォルト:False) 。
第4引数の ファイル形式の設定値は以下の通りです(省略可能)。

ファイル形式
0ASCII
-1Unicode
-2システムの規定値

 

' ファイルの読み書き

Dim fso
Set fso = WScript.CreateObject("Scripting.FileSystemObject")

' 書き込み
Dim fp
set fp = fso.OpenTextFile("test.txt", 8, True)
fp.WriteLine("test" & vbCrLf & "test2")
fp.Close

' 読み込み
Dim line
set fp = fso.OpenTextFile("test.txt", 1, True)
Do While fp.AtEndOfStream <> True
	line = fp.ReadLine
	WScript.Echo line
Loop
fp.Close


インストールログ出力
インストーラが動作するクライアント PC には様々な環境の違いがあり、テストでうまくいったからといって、必ずしも他の PC でうまく動作するとは限りません。
インストーラの実行ログを出力するようにしておきましょう。
このとき、メッセージの出力とログの出力を両方行う共通の Function を作成しておくと便利です。

' インストールログ

Dim fso
Set fso = WScript.CreateObject("Scripting.FileSystemObject")

' ログファイル名の日付文字列生成
Dim dateStr
dateStr = Replace(Replace(Replace(Now(), "/", ""), ":", ""), " ", "")

' ログファイルオープン
Dim logfp
Err.Clear
set logfp = fso.OpenTextFile("install_"&dateStr&".log", 8, True)
If Err.Number <> 0 Then
	WScript.Echo "->errno=" & Err.Number & ":" & Err.Description
End If

' テキストメッセージ出力+ログ出力
echoLog "テストメッセージ 1"
echoLog "テストメッセージ 2"

' ポップアップメッセージ出力+ログ出力
popLog "title", "テストメッセージ 3"
popLog "title", "テストメッセージ 4"

logfp.Close
WScript.Quit 0


' テキストメッセージ出力+ログ出力関数
Function echoLog(msg)
	WScript.Echo msg
	logfp.WriteLine(msg)
End Function

' ポップアップメッセージ出力+ログ出力関数
Function popLog(title, msg)
	MsgBox msg,,title
	logfp.WriteLine(msg)
End Function


プログラム・コマンド実行共通関数
プログラムの実行やコマンドの実行の際、エラー判定やエラー発生時のメッセージやログの出力などを毎回やるのは大変ですので、これら諸々の処理を行う共通関数を作成しておくと便利です。

' プログラム・コマンド実行

Dim rc
rc = cmdExec("cmd.exe /c dir", "dir コマンドでエラーが発生しました。")
If rc <> 0 Then
	WScript.Quit rc
End If

WScript.Quit 0


' プログラム・コマンド実行関数
Function cmdExec(cmd, errMsg)
	echoLog cmd
	Err.Clear
	shell.Run cmd, 0, True
	If Err.Number <> 0 Then
		echoLog "->errno=" & Err.Number & ":" & Err.Description
		popLog errMsg
		cmdExec = Err.Number
		Exit Function
	End If
	cmdExec = 0
End Function


サンプルプログラムのダウンロード
本記事で紹介したサンプルのプログラムを下記からダウンロードできます。

コメント