すがブロ

sugamasaoのhatenablogだよ

Windows のバッチスクリプトから脱却し、WSHを用いて JavaScript でWindows用スクリプトを書く

Windows のバッチスクリプトは結構難しい

ちゃんと調べればそこそこ使えるのだけど、Linux のシェルに慣れた身としてはパワー不足が否めない。
かといって、Ruby やらで実装しようにも、対象のクライアントPCに入っているか気にしなくてはいけないので、できれば Windows ネイティブな言語で実装したい。
ただ、VBScript ってほとんどやった事無いからもっと手軽に実装したい><

そんな時は WSH だ!

WSHWindows98 から実装されているし、VBScriptJScript をサポートしているから、普段 VB に慣れてないような人でも JS だったらまだ取っ付きやすいよ! って人も多いと思う*1

使い方

cscript JScript ファイル

とやると WSH が起動してスクリプトを実行する。ファイルをダブルクリックでも実行できるけど、出力がメッセージボックスになってしまうのでコマンドラインから、 cscript コマンド経由で実行してね。
JScript と言っても特別なことはなくて、普通に JavaScript を記載する感覚で良い。ただ、Windows にアクセスするための専用オブジェクトを生成して使用する部分があるので、そこを追々覚えていけば良い。ーーつまり、バッチファイルで悩みの種になりやすかった if 文や for 文で悩む事は無い訳ですね。

サンプルプログラム

よく使いそうな所を適当に実装してみた。

  • cscript ファイル実行時に引数を渡すやり方
  • ファイルシステムへのアクセス
  • system 関数的な使い方
  • popen 関数的な使い方(子プロセスで実行したプログラムの標準出力を受け取る)
function print(message) {
	WScript.Echo(message)
}

// 参考  http://www.atmarkit.co.jp/fwin2k/operation/wsh05/wsh05_02.html
// system 関数的なヤツ標準出力結果は受け取れない
function SystemCallRun() {
	var  objShell = WScript.CreateObject("WScript.Shell")
	// 第二引数でウィンドウの大きさを制御する
	objShell.Run("notepad.exe", 1, false) // false は notepad の終了を待たないでプログラムを続ける
}

// 参考  http://www.atmarkit.co.jp/fwin2k/operation/wsh05/wsh05_03.html
// system 関数的なヤツ標準出力結果を受けとる
function SystemCallExec() {
	var objShell = WScript.CreateObject("WScript.Shell")
	// cmd /c はコマンドを実行した後に cmd を終了させるオプション
	var objExec = objShell.Exec("cmd /c dir c:\\") 
	
	while(!objExec.StdOut.AtEndOfStream) {
		print(objExec.StdOut.ReadLine())
	}
}


// 参考  http://msdn.microsoft.com/ja-jp/library/cc428041.aspx
// ファイル操作は FileSystemObject を使うよ
function ReportFileStatus(filespec)
{
	var fso, s = filespec;
	fso = new ActiveXObject("Scripting.FileSystemObject");
	if (fso.FileExists(filespec)) {
		s += " は、存在します。";
	} else {
		s += " は、存在しません。";
	}
	
	print(s);
}

// 参考  http://msdn.microsoft.com/ja-jp/library/cc428069.aspx
// ファイル情報を取得するよ
function ShowFileInfo(filespec) {
	var fso, f, s;
	fso = new ActiveXObject("Scripting.FileSystemObject");
	f = fso.GetFile(filespec);
	print("Attributes:" + f.Attributes)
	print("DateCreated:" + f.DateCreated)
	print("DateLastAccessed:" + f.DateLastAccessed)
	print("DateLastModified:" + f.DateLastModified)
	print("Drive:" + f.Drive)
	print("Name:" + f.Name)
	print("ParentFolder:" + f.ParentFolder)
	print("Path:" + f.Path)
	print("ShortName:" + f.ShortName)
	print("ShortPath:" + f.ShortPath)
	print("size:" + f.size)
	print("Type:" + f.Type)
}

// 引数の取り扱い
for (var i = 0; i < WScript.Arguments.length; i++) {
	print("引数[" + i + "]=" + WScript.Arguments(i))
}

// ファイル情報を出力するオブジェクト
ShowFileInfo("test.js")

// ファイル操作系オブジェクト
ReportFileStatus("test.js")

// system 関数的に使う実行のみ
SystemCallRun()

// system 関数的に使う。結果の標準出力を取得できる
SystemCallExec()

実行結果

コマンド引数は以下のように、後続の引数に渡せば使える。

cscript test.js 1 aiueo "引数"

上記のスクリプトを実行した結果。
わかりにくいと思ったので適宜コメントを入れてます。

Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

// 引数の取り扱い
引数[0]=1
引数[1]=aiueo
引数[2]=引数

//ShowFileInfo("test.js")
Attributes:32
DateCreated:Mon Dec 1 02:14:19 UTC+0900 2008
DateLastAccessed:Mon Dec 1 02:14:19 UTC+0900 2008
DateLastModified:Mon Dec 1 02:14:00 UTC+0900 2008
Drive:C:
Name:test.js
ParentFolder:C:\tmp
Path:C:\tmp\test.js
ShortName:test.js
ShortPath:C:\tmp\test.js
size:2219
Type:JScript Script File

//ReportFileStatus("test.js")
test.js は、存在します。

//SystemCallRun()
//実行すると、 notepad が起動しているはず

//SystemCallExec()
ドライブ C のボリューム ラベルがありません。
ボリューム シリアル番号は 9C10-B841 です

c:\ のディレクトリ

2007/01/14 02:49 0 AUTOEXEC.BAT
2007/01/14 02:49 0 CONFIG.SYS
2007/01/14 02:53

Documents and Settings
2007/01/14 03:19 ppwork
2008/08/24 17:50 Program Files
2007/06/10 15:40 ruby
2008/12/01 02:14 tmp
2008/11/26 23:36 WINDOWS
2 個のファイル 0 バイト
6 個のディレクトリ 21,319,520,256 バイトの空き領域

ね、簡単でしょう?

*1:っていうかおれの事だよ!