ファイルをダウンロードするスクリプトを VBScript で書く

ある案件で, 「エンドユーザーがスクリプトファイルを実行したら, HKCU 配下のレジストリツリーへの書き込みと, クライアントソフトウェアのインストーラーのダウンロードと, インストールの実行がひととおりおこなわれるようにしてほしい」 という要件がありました. 本当は, ウェブページ上のリンクを 1 回クリックするだけで, それら一連の作業がすべて自動的に実行されることを期待されていたのですが, ブラウザーのセキュリティ設定を大幅に緩めることでもしないかぎり難しそうなので, エンドユーザーさんにはせめてスクリプトファイルのダウンロードと実行をおこなうという労力を負担していただくことで妥協することになりつつあります.

ちなみに, そういう顧客企業の個別の要望に応じたきめ細かなカスタマイズは日本企業の得意とするところなのかと思いきや, どうも弊社のようなパッケージベンダーの責務らしいということになりまして, これまで油断しっぱなしだったわたしとしては, 今般 VBScript をにわか勉強することになりました. ひょんなきっかけで知識や経験が増えるのは, 実にありがたいことです.

で, 本日は, レジストリへの書き込みに関することとファイルの実行に関することは捨象しまして, ファイルのダウンロードに関することだけ備忘録として書いておきたいと思います.

あるウェブサイトから HTTP を使ってファイルを取得する (ダウンロードする) のを VBScript で書くとした場合, どんな方法があるのでしょうか. ググってみましたところ, いくつかの記事がヒットするのですが, Windows XP 以降のクライアント OS を前提とするなら, たとえば次のようになりましょうか. (ちなみに, 現時点における Git の最新版の Windowsインストーラーをダウンロードし, カレントディレクトリに保存するという事例で考えてみました.)

Const cReqPath = "http://msysgit.googlecode.com/files/"
Const cFileName = "Git-1.7.9-preview20120201.exe"

Set objShell = WScript.CreateObject("WScript.Shell")

Set objXmlHttp = WScript.CreateObject("MSXML2.XmlHttp")

objXmlHttp.Open "GET", cReqPath & cFileName, False
objXmlHttp.Send
intStatus = objXmlHttp.status
If (intStatus <> 200) Then
  WScript.Echo "FAILED" & vbCrLf & vbCrLf & "HTTP status code is " & intStatus
  WScript.Quit
End If

Set objStream = WScript.CreateObject("ADODB.Stream")
objStream.Open
objStream.Type = 1
objStream.Write objXmlHttp.responseBody
objStream.SaveToFile objShell.CurrentDirectory & "\" & cFileName, 2
objStream.Close
Set objStream = Nothing

Set objXmlHttp = Nothing

WScript.Echo "Successfully done."
WScript.Quit

変数名などは, VB 界隈におけるコーディングルールの鉄板をよく知りませんので, とりあえず見よう見まねで書いてみました. また, 冒頭の WScript.CreateObject("MSXML2.XmlHttp") の部分は, ほかにも環境によって? 好みによって? いくつかほかにも選択肢があるようですが, それらの違いがよくわからなかったので, とりあえず Windows XP でも Windows 7 でも動作しそうなものを選んでみました.

さて, このスクリプトには, ひとつ困った点があります. それは, 一度ダウンロードしたファイルがローカルキャッシュに保存されますと, 次に再びこのスクリプトを実行しても, もはやウェブサイトにはアクセスせず, ローカルキャッシュに保存されているファイルを取得してしまうということです. ウェブサイトにアクセスしようともせずに XmlHttp オブジェクトの status プロパティが 200 を返すというのも, なんとなく釈然としないものが残ります.

この点に関しては, XmlHttp オブジェクトの Send メソッドを実行する前に, 次のようにキャッシュを無視するような設定を挿入しておけば, 毎回ウェブサイトからダウンロードしようとするようになるようです.

objXmlHttp.SetRequestHeader "Pragma", "no-cache"
objXmlHttp.SetRequestHeader "Cache-Control", "no-cache"
objXmlHttp.SetRequestHeader "If-Modified-Since", "Thu, 01 Jan 1970 00:00:00 GMT"

これについては XMLHttpRequest() という記事を参考にさせていただきました.

今夜は, 以上です.