First Step

firststep


WSHとは

WSHとは 正式名称 Windows Scripting Hostを 略した名称で、Microsoft Windowsにおいてテキストファイルに記述したスクリプトを実行するスクリプト実行環境です。標準では、MicrosoftのVBScriptとJScript言語を利用できます。また、WSHは内部でActiveXを使っているためにWindowsが持つたくさんのサービスが呼び出せ、かなり強力な機能を持ってます。

以下のページを見る前に、MicrosoftのWindows ScriptWindows Script Host Laboratoryのサイトを一読することをお勧めします。また、ここからWSHのオンラインヘルプをダウンロードしておくと便利です

OgOが装備するJavaScript言語では、スクリプトの最初に

 var {WScript} = require("wsh");

を実行すれば、強力な機能を持つ WSHが使えるようになります。

さらにActiveXの機能を使いたい場合、

 var {ActiveX} = require("ole");

も実行してください。

以下に、サンプルをとうしてWSHの使い方を説明します。


スクリプト作成と実行

まず次のようなテキストファイルを作ります。
start.js

var {WScript} = require("wsh");
WScript.Echo("こんにちは");

拡張子は .js とします。このスクリプトを実行するには、2つの方法があります。

echo.js

var {WScript} = require("wsh");

var v = new vector(0, 1, 2);
WScript.Echo(v);        //(0, 1, 2)

//vectorオブジェクト
function vector(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
    this.toString = function () {
        return "(" + this.x + ", " + this.y + ", " + this.z + ")";
    };
}

echo2.js

var {WScript} = require("wsh");

//Numberオブジェクト
var a = 1e-7
WScript.Echo(a);                            //1e-7

//VBのDate型オブジェクト
var fs = WScript.CreateObject("Scripting.FileSystemObject");
var WShell = WScript.CreateObject("Wscript.Shell");
var dsktop = fs.GetFolder(WShell.SpecialFolders("Desktop"));
WScript.Echo(dsktop.DateLastModified);      //Thu Mar 03 2011 09:05:55 GMT+0900

//Booleanオブジェクト
var b = true;
WScript.Echo(b);                            //true


OgOx の引数

OgOx では次のように引数をとることができます。

     OgOx    mtable.js   6   7   >   mtable.html   [Enter]

ここでは、6 と 7 が引数になっています。 リダイレクトで標準出力がmtable.htmlに書き出されます。

mtable.js

var {WScript} = require("wsh");

//かけ算の表を作るプログラム
var r, c, i, j;
var args = WScript.Arguments;

//引数の処理(かなり甘い)
if(args.length != 2)     //引数の数が2でないなら
    QuitForError();
if((r = parseInt(args[0])) <= 0)
    QuitForError();
if((c = parseInt(args[1])) <= 0)
    QuitForError();

//表を作る
WScript.Echo("<HTML>\n<BODY STYLE=\"text-align:center;\">");
WScript.Echo("<TABLE BORDER>");
for(i = 1; i <= r; i++) {
    WScript.Echo("<TR>");
    for(j = 1; j <= c; j++)
        WScript.Echo("<TD>" + i * j + "</TD>");
    WScript.Echo("</TR>");
}
WScript.Echo("</TABLE>\n</BODY>\n</HTML>");

function QuitForError() {
    WScript.Echo(
        "usage : OgOx  mtable.js  nrows  ncolumns");
    WScript.Quit();     //プログラムを終了する
}

このプログラムを実行すると、次のようなHTMLファイルが生成されます。

mtable.html

プログラムは、1番目の引数がrに入り、2番目の引数がcに入って、 r行×c列のかけ算の表を作ります。

WScript.Arguments配列を返します。args.lengthで引数の個数を返します。 上の例では2を返します。args[0]で最初の引数を返します。 args[1]で2番目の引数を返します。

このようにWSHで、使えるプログラムを組むことができます。

以下では、本当のWSHの価値を発見できるサンプルを掲載しています。
これらを参考にして普段のデータ処理を自動化してみてはいかがでしょうか。



Text File

Text_File


FileSystemObjectとその定数

FileSystemObjectを使うと、ファイルシステムを操作することができます。
FileSystemObjectを得るにはつぎのようにします。

   var fs = WScript.CreateObject("Scripting.FileSystemObject");

FileSystemObjectを使う際に必要な定数はつぎのようにして取得できます。

   var FS = WScript.loadConsts(fs);
   // FS.Normal==0, FS.ReadOnly==1, ...


テキストファイルの読み取り

テキストファイルの読み書きをするにはまず、 TextStreamを得る必要があります。
ファイルを読み取りまたは追加書き込みする場合は、

   var stream = fs.OpenTextFile(filename, iomode);

とします。追加書き込みの場合、iomodeFs.ForAppending (8)とします。読み取りの場合省略できます。

読み取りは典型的に次のように行います。

score.csv

名前,性,国語:Int,算数:Int,理科:Int,社会:Int
さくら,女,75,71,8,66
知世,女,62,2,89,60
小狼,男,51,28,70,31
千春,女,68,61,46,12
奈緒子,女,89,55,69,24
利佳,女,79,30,79,81

このようなテキストファイルを読んで、各人の合計の点数を表示します。

sum.js

var {WScript} = require("wsh");

var str, arr, i, sum;
var fs = WScript.CreateObject("Scripting.FileSystemObject");
var stream = fs.OpenTextFile("score.csv");  //読み取り専用

stream.SkipLine();              //一行読み飛ばし
while(!stream.AtEndOfStream) {  //ファイルの終端に達するまで
    str = stream.ReadLine();    //一行読む
    arr = str.split(",");
    sum = 0;
    for(i = 2; i < arr.length; i++)
        sum += parseInt(arr[i]);        //得点を足していく
    WScript.Echo(arr[0] + " " + sum);   //名前と総得点を表示
}
stream.Close();                 //最後にファイルをクローズ

OpenTextFileメソッドでテキストファイルを開いた後、 ReadLineメソッドで一行ずつ読みこみます(改行文字は省略されて値が返されます)。 AtEndOfStreamプロパティがtrue になったらファイルの終端まで達したことになるので Closeメソッドでファイルを閉じます。

書きこむ方法はほかに、指定した文字数を読みこむRead メソッド、ファイルを丸ごと読みこむReadAll メソッドがあります。


テキストファイルの書きこみ

新規にテキストファイルを作成する場合は、

   var stream = fs.CreateTextFile(filename, isoverwrite);

とします。isoverwritetrueでなく falseの場合、 filenameで指定されるファイルが存在するとエラーが発生します。

前回と同じかけ算の表を作ってみましょう。

mtable2.js

var {WScript} = require("wsh");

//かけ算の表を作るプログラム 2
var r, c, i, j;

//今回は引数の処理は無し
r = 6; c = 7;

var fs = WScript.CreateObject("Scripting.FileSystemObject");
var stream = fs.CreateTextFile("mtable2.htm");

//表を作る
with(stream) {
    Write("<HTML>\n<BODY STYLE=\"text-align:center;\">\n");
    Write("<TABLE BORDER>\n");
    for(i = 1; i <= r; i++) {
        Write("<TR>");
        for(j = 1; j <= c; j++)
            Write("<TD>" + i * j + "</TD>");
        WriteLine("</TR>");
    }
    Write("</TABLE>\n</BODY>\n</HTML>\n");
    Close();
}

CreateTextFileで新規ファイルを開いた後、 WriteあるいはWriteLine メソッドでテキストを書きこみます。WriteLineメソッドは最後に改行文字を書きこみます。最後にCloseメソッドでファイルを閉じます。



File System(1)

File_System_1


ドライブ・フォルダ・ファイル

FileSystemObjectを使って、 ドライブ・フォルダ・ファイルのそれぞれのオブジェクトを得ることができます。

var {WScript} = require("wsh");

var fs = WScript.CreateObject("Scripting.FileSystemObject");
var dr = fs.GetDrive("c:");
var fo = fs.GetFolder("c:\\windows");
var fi = fs.GetFile("c:\\command.com");

GetDriveの引数は、"c"、"c:\\"でもOKです。 GetFolderの引数は、"c:\\windows\\"でもOKです。
ドライブなどが存在しない場合はエラーが発生します。

これらのオブジェクトのコレクションを それぞれの上位階層のオブジェクトなどから得ることもできます。

    drc = fs.Drives
    foc = fo.SubFolders
    fic = fo.Files

これらのコレクションの要素は 次のように Enumeratorを用いて順に取り出すことができます。

dir.js

var {WScript, Enumerator} = require("wsh");

var fs = WScript.CreateObject("Scripting.FileSystemObject");
var f = fs.GetFolder(".")

//すべてのサブフォルダを表示
for (var subfc = new Enumerator(f.SubFolders); !subfc.atEnd(); subfc.moveNext()) {
    WScript.Echo("[" + subfc.item().Name + "]");
}

//すべてのファイルを表示
for (var fc = new Enumerator(f.Files); !fc.atEnd(); fc.moveNext()) {
    WScript.Echo(fc.item().Name);
}

このスクリプトはDOSのコマンドDIRと同様に、 そのフォルダ内のフォルダとファイルを一覧表示します。

for (var fc = new Enumerator(f.Files); !fc.atEnd(); fc.moveNext()) {
    fc.item() ……;
}

で、f.Filesで得られるフォルダ内のすべてのファイルの集まり Filesコレクションの要素のFileオブジェクトが 次々にf1で参照されるようになり処理されます。 その上も同様でそのフォルダ内のすべてのサブフォルダについて処理されます。

サブルーチンを再帰的に呼び出すことにより、 フォルダの中をすべてスキャンするプログラムがよく使われます。

du.js

var {WScript, Enumerator} = require("wsh");

var fs = WScript.CreateObject("Scripting.FileSystemObject")

// 引数が無ければカレントディレクトリ、
// あれば第1引数からスキャンする
var objArgs = WScript.Arguments;

var str;
if (objArgs.length == 0) {
    str = ".";
}else{
    str = objArgs[0];
}
var f = fs.GetFolder(str);

ScanFolder(f);     // フォルダ内の全てのフォルダについて処理する

function ScanFolder(f) {
    for (var subf=new Enumerator(f.SubFolders); !subf.atEnd(); subf.moveNext()) {
        ScanFolder(subf.item());
    }
    
    WScript.Echo(f.Path);
}


コピー・移動・削除

フォルダとファイルのコピーは次のようにします。

var {WScript} = require("wsh");

var fs = WScript.CreateObject("Scripting.FileSystemObject");
var f = fs.GetFolder("scripts");
f.Copy("c:\\backup\\", true);
var f1 = fs.GetFile("aname.pl");
f1.Copy("c:\\backup\\", true);

Copyメソッドの1番目の引数はコピー先、 2番目は省略可能で、上書きするかどうかです。 デフォルトは true です。 false で上書きしようとするとエラーになります。
フォルダの場合は、下の階層のファイル・フォルダも全てコピーします。

フォルダとファイルの移動も同様です。

f.Move("c:\\backup\\");
f1.Move("c:\\backup\\");

フォルダとファイルの削除は次のように行います。

f.Delete(true);
f1.Delete(true);

引数は読取専用のファイル・フォルダも強制的に削除するかどうかです。 デフォルトは false です。 false で読取専用のファイル・フォルダを削除しようとするとエラーが出ます。

コピー・移動の操作はFileSystemObject を用いたほうが簡単かもしれません。

fs.CopyFolder("scripts", "c:\\backup\\", true);
fs.CopyFile("aname.pl", "c:\\backup\\", true);

1番目の引数はフォルダ・ファイルを表す文字列、2番目はコピー先、 3番目は上書きするかどうかです。
1番目の引数には次のようにワイルドカードを用いることも可能です。

fs.CopyFolder("???????", "c:\\backup\\", true);
fs.CopyFile("*.pl", "c:\\backup\\", true);

移動も同様です。

fs.MoveFolder("scripts", "c:\\backup\\");
fs.MoveFile("aname.pl", "c:\\backup\\");



File System(2)

File_System_2


Fileオブジェクトのプロパティ

Name ファイルの名前
ShortName 8.3形式のファイル名
Path ファイルのフルパス
ShortPath 8.3形式のフルパス
Size バイト単位のファイルサイズ
Type ファイルの種類 ex) "GIF イメージ"
Attributes ファイルの属性
DateCreated 作成日時
DateLastModified 更新日時
DateLastAccessed 最終アクセス日時
Drive ファイルが格納されているDriveオブジェクト
ParentFolder ファイルが格納されているFolderオブジェクト


Folderオブジェクトのプロパティ

Name フォルダの名前
ShortName 8.3形式のフォルダ名
Path フォルダのフルパス
ShortPath 8.3形式のフルパス
Size バイト単位のフォルダサイズ
Attributes フォルダの属性
DateCreated 作成日時
DateLastModified 更新日時
DateLastAccessed 最終アクセス日時
Drive フォルダが格納されているDriveオブジェクト
ParentFolder フォルダが格納されているFolderオブジェクト
IsRootFolder ルートフォルダかどうかを返す
Files フォルダ内のFileオブジェクトのコレクション
SubFolders フォルダ内のFolderオブジェクトのコレクション


Driveオブジェクトのプロパティ

TotalSize バイト単位の総ディスク容量
FreeSpace バイト単位の使用可能なディスク容量
AvailableSpace バイト単位のユーザが使用可能なディスク容量
DriveLetter ドライブ名 ex) "C"
Path パスを返す ex) "C:"
VolumeName ボリューム名
ShareName ドライブのネットワーク共有名
RootFolder ルートフォルダを表すFolderオブジェクト
DriveType ドライブの種類を示す値を整数で返す"
FileSystem ファイルシステムを表す文字列 ex) "FAT"
SerialNumber ディスクボリュームのシリアル番号
IsReady 準備できているかどうかを返す


ファイル・フォルダの属性

ファイル・フォルダの属性は次の値の加算によって表されます。

Normal 0 通常のファイル
ReadOnly 1 読み取り専用ファイル
Hidden 2 隠しファイル
System 4 システムファイル
Volume 8 ディスク ドライブ ボリューム ラベル
Directory 16 フォルダ
Archive 32 ファイルが前回のバックアップ以降に変更されているかどうか
Alias 1024 ショートカット
Compressed 2048 圧縮ファイル

例えば、読み取り専用で隠しファイルなら3が返ります。そのファイルが隠しファイルかどうかを判定するには次のようにします。

if(f1.Attributes & FS.Hidden)
    WScript.Echo(f1.Name + "は隠しファイル");
else
    WScript.Echo(f1.Name + "は隠しファイルでない");


ドライブの種類

DriveTypeプロパティは整数を返しますが、それぞれの値は次のドライブの値と対応しているようです。

UnknownType 0 不明
Removable 1 リムーバブル ディスク
Fixed 2 ハード ディスク
Remote 3 ネットワーク ドライブ
CDRom 4 CD-ROM
RamDisk 5 RAM ディスク


日時を返すプロパティ

各オブジェクトの日時を返すプロパティは、Yearは1900年からの差分年数となります。
正しい西暦年数は、getFullYearメソッドを使ってください。

var {WScript} = require("wsh");

var fs = WScript.CreateObject("Scripting.FileSystemObject");
var windir = fs.GetFolder("c:\\windows");
var d = windir.DateLastModified;
WScript.Echo(d.getYear());     //1900年からの差分年数
WScript.Echo(d.getFullYear()); //西暦年数



Excel

Excel

今回はExcelを操作する方法についてみていきます。これは、VBAをふだんから使っている人にとっては非常に簡単です。


Excelを操作する

最初に、ExcelのApplicationオブジェクトにあたるオブジェクトを得ます。

   var excel = WScript.CreateObject("Excel.Application");

それから、とりあえずExcelを見えるようにしておきます。

    excel.Visible = true;

そのあとは、VBAでApplicationとしているところ、またはそれが省略されているところでは Applicationオブジェクトを補っておきます。例えば、

    excel.Cells(1, 1).Value = 1;

だいたいこれくらい分かっておけば書けるでしょう。下の例は、モンテカルロ法で円周率を求めるプログラムです。座標値が0~1を取る正方形の中に疑似乱数で点を打ち、その点が中心が原点、半径1の円内に入るかどうかを調べます。 1、2列目がx、yの値、3列目が円の中に入っていれば1、入っていなければ0になります。この3列目の平均を取って4倍した値が概算の円周率です。

montecarlo.js

var {WScript} = require("wsh");

var i, rmax;
const pi = Math.PI;

var excel = WScript.CreateObject("Excel.Application");
const XL = WScript.loadConsts(excel);        // Excelの定数

excel.Visible = true;
excel.WorkBooks.Add();                  //新規ブック

// 1/4円を描くためのデータ 4列目がx、5列目がy
//本当はワークシート関数を使ったほうが速い
for(i = 0; i <= 50; i++) {
    excel.Cells(i + 1, 4).Value = Math.sin(pi * i / 100);
    excel.Cells(i + 1, 5).Value = Math.cos(pi * i / 100);
}

//座標値が0~1の値を取る2次元の点が
//半径1の円の中にいくつ入ったかで円周率を求める
rmax = 1000;
with(excel) {
    Range(Cells(1, 3), Cells(rmax, 3)).FormulaR1C1
                            = "=if(rc1*rc1+rc2*rc2<1,1,0)";
    Range(Cells(1, 1), Cells(rmax, 2)).FormulaR1C1
                            = "=rand()";
}
excel.Cells(1, 7).FormulaR1C1                   //結果
                = "=average(r1c3:r" + rmax + "c3)*4";
excel.Cells(1, 7).Borders.Weight = XL.xlMedium;

//疑似乱数によって生成された点と1/4円をグラフとして描く
with(excel) {
    ActiveSheet.ChartObjects().Add(60, 30, 330, 300).Select();
    //以下略
}

気をつけなければならないのは、Rangeメソッドです。

   //エラー
   excel.Range(Cells(1, 1), Cells(3, 1)).Value = 3;
   
   //正常動作
   excel.Range(excel.Cells(1, 1), excel.Cells(3, 1)).Value = 3;

   //正常動作 (with文で excel. を省略)
   with(excel) {
       Range(Cells(1, 1), Cells(3, 1)).Value = 3;
   }


名前付き引数は { 引数名 : 値, ... } で与えます。
transpose.js

var {WScript} = require("wsh");

var excel = WScript.CreateObject("Excel.Application");
excel.Visible = true;
excel.WorkBooks.Add();

with (excel) {
    Cells(1, 1).Value = 1;
    Cells(2, 1).Value = 2;
    Range("A1:A2").Copy();
    Range("C1").PasteSpecial( {Transpose:true} ); //Transpose:True 貼り付けるときにセル範囲の行と列を入れ替えます。
    Application.CutCopyMode = false;  //コピーした範囲が点線で点滅するのを止めます。
}


ファイルと連携する

下は1日の残業時間が書かれたテキストファイルを読み込んで、 Excelに書き出すスクリプトです。

D:\work\残業TXT の下に毎朝、前日の残業時間が書かれたテキストファイルがいつも置かれているとします。

残業110311.txt

さくら,知世,小狼,千春,奈緒子,利佳
     0,   0,   2, 0.5,     1, 0.5

D:\work\残業XLS の下に毎月の残業時間がまとめられたブックがあるとします。

          さくら  知世  小狼  千春  奈緒子  利佳
3/1/2011       1     1     0   1.5       1     2
3/2/2011     0.5   0.5     0   0.5       1     2

そして、タスクスケジューラで毎朝10時にスクリプトが動くなどと設定しておけば、自動的にテキストファイルを読み込んで、その月のブックのその日の行に各人の残業時間が書かれます。その月のブックがなければ前月分などから新しく作ります。Excelはウィンドウを見せないようにしていて、スクリプトが終わる前にExcelを終了するようにしているので、画面上には何も現れず、HDDが静かなマシンであれば動作していることに気づかないかもしれません。

zangyou.js

var {WScript, Enumerator} = require("wsh");

var fs, source_fld, excel_fld, stream, i, str;
fs = WScript.CreateObject("Scripting.FileSystemObject");
source_fld = fs.GetFolder("d:\\work\\残業TXT");

//テキストファイルから各人の残業時間を読み取る
var fc = new Enumerator(source_fld.Files);
var arrData = new Array();
var nData = 0;

for(; !fc.atEnd(); fc.moveNext()) {
  //ファイル名がパターンにマッチするテキストファイルを読む
  if(/残業[0-9]+\.txt/.test(fc.item().Name)) {
    arrData[nData] = new Data();
    //ファイル名から日付を得る
    arrData[nData].setDate(fc.item().Name);
    stream = fs.OpenTextFile(fc.item());
    //1行目は名前の配列
    str = stream.ReadLine();
    arrName = str.split(",");
    //2行目は残業時間の配列
    str = stream.ReadLine();
    arrHours = str.split(",");
    stream.Close();
    for(i = 0; i < arrName.length; i++)
      arrData[nData].setData(arrName[i].trim(), arrHours[i]);
    nData++;
  }
}

var r,c;

//データをブックに書きこむ
var excel = WScript.CreateObject("Excel.Application");
var XL = WScript.loadConsts(excel);
//objXL.Visible = true;             ウィンドウを見せない
excel_fld = fs.GetFolder("d:\\work\\残業XLS");
for(i = 0; i < nData; i++) {
  with(excel) {
    OpenMonthBook(arrData[i].d);
    r = arrData[i].d.getDate() + 1;         //書きこむ行
    str = arrData[i].d.toLocaleString();
    Cells(r, 1).Value = str.substring(0, 10);   //日付
    cmax = Cells(1, 2).SpecialCells(XL.xlLastCell).Column;
    for(c = 2; c <= cmax; c++) {
      str = Cells(1, c).Text.trim();        //名前
      if(arrData[i].IsExist(str))
        Cells(r, c).Value =
              arrData[i].getZangyou(str);
    }
    ActiveWorkbook.Save();
  }
}

excel.Quit();

//その月に対応するブックを開く
function OpenMonthBook(d) {
    //省略
}

//1日のデータを表すオブジェクトの定義
function Data() {
    this.d;
    this.dic = {};
    this.setDate = setDate;
    this.setData = setData;
    this.IsExist = IsExist;
    this.getZangyou = getZangyou;
}

//以下略


ウィンドウ系プロパティ

Excelだけ使っているとあまり使うことはないかもしれませんが、 WSHではウィンドウのサイズ、スタイルを変えるプロパティが有用です。

excelwnd.js

var {WScript} = require("wsh");

var excel = WScript.CreateObject("Excel.Application");
var XL = WScript.loadConsts(excel);  //定数

excel.Visible = true;

excel.Left = 0;                     //左端の座標
excel.Top = 0;                      //上端の座標
excel.Width = 600;                  //幅
excel.Height = 500;                 //高さ
excel.WindowState = XL.xlMaximized;    //最大化
excel.WindowState = XL.xlNormal;       //元の大きさに
excel.WindowState = XL.xlMinimized;    //最小化

excel.Workbooks.Add();



Internet Explorer(1)

Internet_Explorer

今回はInternet Explorerを操作する方法についてみていきます。 Internet Explorerを操作できると色々なオートパイロットができます。 オートパイロットのソフトには色々ありますが、 機能が充実していなかったり、シェアウェアだったりします。 一歩先を行くユーザは自由にカスタマイズできるようにWSHで書きましょう。

「Windows JavaScript」-「WebFormクラス」を使えば、Internet Explorerをよりカスタマイズした扱いができます。

Internet Explorerを開く

最初に、Internet Explorerオブジェクトを得ます。

    var IE = WScript.CreateObject("InternetExplorer.Application");

それから、IEを見えるようにしておきます。

    IE.Visible = true;

次のスクリプトは私がいつもデスクトップに置いて使っているものです。

ie.js

var {WScript} = require("wsh");

var IE = WScript.CreateObject("InternetExplorer.Application");
IE.Visible = true;
IE.Width = 680; IE.Height = 660;
IE.GoHome();

IEを立ち上げるとたぶん、ウィンドウが横長になってしまうと思います。 私はこれが気に入らないので、開いた後WidthHeightで横と縦の長さを変えています。 これ時点ではページが表示されていないので、最後にホームを表示します。私の作っているページは最近はたいていこの680という幅を前提にしています。 これより狭いと若干見にくくなるかもしれません。

documentオブジェクト

     IE.Document

とすると、ページ上のJavaScriptでいつも使っている documentオブジェクトを得ることができます。 これさえ得られれば、JavaScriptをふだんから使っている人なら あとは思いのままでしょう。例えば、下のボタンを押すスクリプトを考えましょう。

これは、

    <FORM NAME=frm1>
    <INPUT TYPE="button" NAME="button1" VALUE="押してね☆"
        ONCLICK='alert("幸せ絶頂!!ですわー!!")';
    </FORM>

となっており、ボタンを押すとメッセージが表示されます。これをスクリプトで実現するには、 Navigateメソッドで指定したURLに飛びます。

    IE.Navigate(URL);

このNavigateメソッドを働かせると、 指定したURLのページがロードされるまで待ってくれるわけではないようです。 仕方がないので次のように適当にページのロードが終わるまで待ちます。

    while(IE.busy) ;
    while(IE.Document.readyState != "complete") ;

ビジーの間待ち、さらにページのロードが完了するまで待ちます。 気持ちの悪い書き方ですが、これでもそんなにCPUを食うわけではないようです。実のところこれでちゃんとロードされるまでちゃんと待ってくれるのか分かりません。このあと、普通にページ上でJavaScriptを使うのと同じようにボタンをクリックします。

iebutton.js

var {WScript} = require("wsh");

var IE = WScript.CreateObject("InternetExplorer.Application");

//イベントを設定
WScript.addEventHandlers(IE,
  { 
    DocumentComplete: IE_DocumentComplete
  }
);

IE.Visible = true;
IE.Width = 680; IE.Height = 660;
IE.Navigate(
        "http://homepage3.nifty.com/aya_js/wsh/wsh07.htm");

WScript.waitEvents();

IE.Document.getElementsByName("frm1")(0).namedItem("button1").click();

WScript.unAdvise(IE);  //イベントを切断
IE = null;

function IE_DocumentComplete( pDisp, URL ) {
  WScript.cancelWaitEvents();  //イベントループを終了させる
}

このようにすれば、例えば独自の認証方法を取るサイトなど 普通のオートパイロットソフトでは巡回できないページも 自動的にロードすることができます。

ページの内容をすべて取り出せます。
以下は H2タグから連続したPタグの内容をリストアップするプログラムです。

asahicom.js

var {WScript} = require("wsh");

var IE = WScript.CreateObject("InternetExplorer.Application");

//イベントを設定
WScript.addEventHandlers(IE,
  {
    DocumentComplete: IE_DocumentComplete
  }
);

//IE.Visible = true;
IE.Navigate("http://www.asahi.com/paper/editorial.html");

WScript.waitEvents();

var str = IE.document.body.innerHTML;

//get H2タグの中身
var reg = /<H2[^>]*>/ig;
var a = reg.exec(str);
var str = str.slice(reg.lastIndex);

var reg = /<\/H2>/ig;
var a = reg.exec(str);

WScript.Echo( "タイトル : " + str.slice(0,a.index) );

str = str.slice(reg.lastIndex);

//get 連続 Pタグの中身
WScript.Echo( "内容 :" );
var findP;
for (; findP=getP(str); str=str.slice(findP[2])) {
  WScript.Echo( str.slice(findP[0],findP[1]) );
}

WScript.unAdvise(IE)
IE.Quit();

function getP(str) {

//以下略

ページがロードされたら、

    str = IE.document.body.innerHTML;

として、全文をstrに格納します。 そして、タグをたよりにタイトルと記事などを拾っていきます。

IEのコマンドを実行する

ExecWBメソッドを使うとIEのコマンドを実行することができます 。

   IE.ExecWB(cmdID, cmdexecopt [,pvaIn] [,pvaOut]) 

cmdIDはコマンドを指定します。 具体的には ここを見てください。

cmdexecoptは

   OLECMDEXECOPT_DODEFAULT
   OLECMDEXECOPT_DONTPROMPTUSER
   OLECMDEXECOPT_PROMPTUSER
   OLECMDEXECOPT_SHOWHELP

から選びます。pvaInは何か入力する変数、pvaOutは出力する変数です。

saveas.js

var {WScript} = require("wsh");

var IE = WScript.CreateObject("InternetExplorer.Application");
var IEC = WScript.loadConsts(IE);

IE.Visible = true;
IE.GoHome();
waitIE();

IE.ExecWB(IEC.OLECMDID_SAVEAS, IEC.OLECMDEXECOPT_DODEFAULT);

上のスクリプトはホームを表示して名前を付けて保存のコマンドを発行します。 ただダイアログを出すだけです。cmdIDを変えると色々なことができるので試してみましょう。



Internet Explorer(2)

IE4

今回は、おそらく Internet Explorer 4 から新たに参照・設定可能となったと思われるプロパティを紹介します。また、前回割愛したプロパティもあわせて紹介します。

ルックス

今までより見栄えを色々制御できるようになりました。

ielooks.js

var {WScript} = require("wsh");

var IE = WScript.CreateObject("InternetExplorer.Application");
IE.Visible = true;
IE.GoHome();

IE.TheaterMode = true;
IE.AddressBar = false;
IE.MenuBar = false;
IE.StatusBar = false;
IE.ToolBar = false;

AddressBarMenuBarStatusBarToolBar は読んで字のごとくのプロパティです。 TheaterMode は[表示]-[全画面](F11)に対応します。いずれもtruefalseで設定します。
MenuBarStatusBarToolBar は以前からありました。

これも前からありましたが、ウィンドウの左上のデスクトップの座標を、 Leftプロパティ、 Topプロパティで指定できます。

iemove.js

var {WScript} = require("wsh");

var x, y, w, h, w0, h0;
var IE = WScript.CreateObject("InternetExplorer.Application");

w = IE.Width;
h = IE.Height;
GetResolution();    //画面の大きさをw0、h0に格納

IE.Visible = true;
IE.Left = IE.Top = 0;   //左上隅に移動
IE.GoHome();

//Left、Topプロパティを変えて移動する
for(x = 0; x < w0 - w; x += 5) IE.Left = x;
for(y = 0; y < h0 - h; y += 5) IE.Top = y;
for(; x >= 0; x -= 5) IE.Left = x;
for(; y >= 0; y -= 5) IE.Top = y;

//ディスプレイの解像度をレジストリから得る
function GetResolution() {
//以下略

IEのウィンドウがデスクトップを一周します。

オフライン

IE4で何がよくなったかというと、やっぱりオフラインでオンラインと同じように見られるということだと思います。自分で自動巡回のスクリプトを書いたときに、あるところまではいつも同じだからオフライン、その先はオンラインで巡回したいというようなことがあるかもしれません。そんなときにOfflineプロパティを使います。

var {WScript} = require("wsh");

var IE = WScript.CreateObject("InternetExplorer.Application");
IE.Visible = true;
IE.Offline = true;

//どっかのページに飛ぶ

IE.Offline = false;

//フォームに入力してサブミットする

Offlineプロパティに truefalseを設定します。



DAO

DAO

DAO(Data Access Object)はデータベースの操作をパッケージ化して 使いやすくしたものです。

DAOの階層構造

ADOのと同じように操作できますが、 それよりも深い階層構造になっています。 DAOでは次のような階層構造になっています。

    DBEngine - Workspace - Database - Recordset

Microsoft Access Databaseからレコードセットオブジェクトを得るには 次のようにします。

    var {WScript} = require("wsh");

    var DBEngine = WScript.CreateObject("DAO.DBEngine");
    var ws = DBEngine.Workspaces(0);
    var dbase = ws.OpenDatabase("score.mdb");
    var rs = dbase.OpenRecordset("Score");

OpenDatabaseの引数はデータベース名を、 OpenRecordsetはテーブル名を指定します。私の環境では次のようにしなければいけませんでした。

    var DBEngine = WScript.CreateObject("DAO.DBEngine.35");

レジストリエディタでHKEY_CLASSES_ROOT\DAO.DBEngine辺りを見てください。適当にデータベースにアクセスしてみましょう。

score.lzh(score.mdbをLHAで圧縮したもの 8kB)

score.js

var {WScript} = require("wsh");

var DBEngine = WScript.CreateObject("DAO.DBEngine.35");
var dbase = DBEngine.Workspaces(0).OpenDatabase("score.mdb");
var rs = dbase.OpenRecordset("Score");

var allscore = 0;
while(!rs.EOF) {                //全てのレコードについて操作
    allscore += rs.Fields("算数").Value;
    rs.MoveNext();              //次のレコードへ
}

rs.Close();
dbase.Close();

WScript.Echo(allscore);

各人の算数の点数の合計を表示しています。
Fields("算数")として現在のレコードの算数フィールドの 値を得ます。 そして、MoveNextメソッドで次のレコードに移動します。 EOFプロパティで、 現在の位置が最後のレコードより後かどうかを判定します。

SQL

さきほどの例は次のようにしてSQL文を使うと簡単に書けます。

score2.js

var {WScript} = require("wsh");

var DBEngine = WScript.CreateObject("DAO.DBEngine.35");
var dbase = DBEngine.Workspaces(0).OpenDatabase("score.mdb");
var rs = dbase.OpenRecordset(
        "SELECT Sum(算数) AS 総得点 FROM Score");

WScript.Echo(rs.Fields("総得点").Value);

rs.Close();
dbase.Close();

OpenRecordsetメソッドで、 さきほどはテーブル名を引数にしていましたが、 SQL文を指定して実行することができます。

その他データベースへのアクセス

次のように例えばExcelのワークシートにアクセスすることができます。

score.xls(14kB)
score3.js

var {WScript} = require("wsh");

var DBEngine = WScript.CreateObject("DAO.DBEngine.35");
var dbase = DBEngine.Workspaces(0).OpenDatabase(
                "score.xls", false, false, "EXCEL 5.0;");
var rs = dbase.OpenRecordset("Score$");

WScript.Echo(rs.Fields("算数").Value);

rs.Close();
dbase.Close();

OpenRecordsetメソッドで、 ワークシート名を指定しています。

ExcelでSQLを使う

Excelのワークシートをテーブル名にする方法は、次のように指定します。

    [sheetname$]

先ほどのAccessでSQLを使ったのと同じことができます。

score4.js

var {WScript} = require("wsh");

var DBEngine = WScript.CreateObject("DAO.DBEngine.35");
var dbase = DBEngine.Workspaces(0).OpenDatabase(
                "score.xls", false, false, "EXCEL 5.0;");
var rs = dbase.OpenRecordset("SELECT Sum(算数) AS 総得点 FROM [Score$]");

WScript.Echo(rs.Fields("総得点").Value);

rs.Close();
dbase.Close();

シートの範囲に名前をつけておくとSQLのテーブルとして使えるのですが、 これをいちいち設定しなければならないのはどうかと思うので。



コマンドを実行する

Execute_Command

スクリプトからコマンドを実行するには、例えば次のようにします。

startpage.js

var {WScript} = require("wsh");

var WShell = WScript.CreateObject("WScript.Shell");
WShell.Run("http://homepage3.nifty.com/aya_js/");

ブラウザが立ち上がり、ここのホームが表示されます。

WshShell.Run(strCommand, [intWindowStyle, [bWaitOnReturn]);

strCommand は実行するコマンドを表す文字列です。
intWindowStyle はウィンドウのスタイルを表す整数値です。
bWaitOnReturn はスクリプトがコマンドの実行を待つかどうかを表すブール値です。

ウィンドウスタイル

intWindowStyle の値によって次のようにウィンドウスタイルが変わります。

0 非表示
1 通常の大きさ
2 最小表示
3 最大表示

同期・非同期

bWaitOnReturnfalse または省略するとそのコマンドが終わるのを待たずにスクリプトが進行します。 true なら終わるのを待ちます。



ショートカット

Shortcut

ショートカットを作る

ショートカットは次のように簡単に作れます。

shortcut.js

var {WScript} = require("wsh");

var WShell, fs, fldDesktop, pathname, url, oShellLink;

WShell = WScript.CreateObject("Wscript.Shell");
fs = WScript.CreateObject("Scripting.FileSystemObject");
//デスクトップフォルダオブジェクト
fldDesktop = fs.GetFolder(WShell.SpecialFolders("Desktop"));

//作成するショートカットのパス
pathname = fldDesktop.Path + "\\wsh.lnk";
//ショートカットのリンク先
url = "http://homepage3.nifty.com/aya_js/wsh/wsh_frm.htm";
//ショートカットオブジェクトの作成
oShellLink = WShell.CreateShortcut(pathname);
oShellLink.TargetPath = url;          //リンク先
oShellLink.Save();                    //ショートカットの作成

デスクトップにここのトップページへのショートカットを作ります。

ショートカットオブジェクトは次のように作成します。

    objShortcut = WshShell.CreateShortcut(strPathname)

strPathname には 実際に作成するショートカットファイルのパスを指定します。
このあと、ショートカットオブジェクトのプロパティを設定して、 Save メソッドでショートカットファイルを作成します。

上では最低限必要なリンク先を指定する TargetPath プロパティを設定します。

ショートカットオブジェクトのプロパティ

TargetPath

リンク先のパスを指定します。

Arguments

引数を指定します。
例えば、デスクトップにBook1.xlsというファイルを作り、 次のようなスクリプトを動かします。

//以上省略(上の例と同じ)
pathname = fldDesktop.Path + "\\Book1.lnk";
oShellLink = WShell.CreateShortcut(pathname);
oShellLink.TargetPath = "...\\EXCEL.EXE";
oShellLink.Arguments = fldDesktop.Path + "\\Book1.xls";
oShellLink.Save();

このようにして作成されたショートカットを開くと、結局

    "...\\EXCEL.EXE " + fldDesktop.Path + "\\Book1.xls"

が実行されたのと同じことになります。

WorkingDirectory

作業領域を指定します。
D:\work にa.txtというファイルを作り、 次のようなスクリプトを動かします。

//以上省略(上の例と同じ)
pathname = fldDesktop.Path + "\\a.lnk";
oShellLink = WShell.CreateShortcut(pathname);
oShellLink.TargetPath = "...\\NOTEPAD.EXE";
oShellLink.Arguments = "a.txt";
oShellLink.WorkingDirectory = "D:\\work";
oShellLink.Save();

作成されたショートカットファイルを開くと、作業領域がD:\workになって、 D:\workにあるa.txtが開きます。

IconLocation

アイコンの位置を指定します。

oShellLink.IconLocation = "...\\Excel.exe,12";

"Path,index"と指定します。 index は0から始まる整数をとります。

Hotkey

ショートカットキーを指定します。

oShellLink.Hotkey = "ALT+CTRL+F";

こうすると、ショートカットキーでショートカットファイルを開くことができます。

Description

説明文を付加します。

oShellLink.Description = "これはショートカットのテストです";

WindowStyle

ショートカットを開いたときのウィンドウスタイルを指定します。

1 ウィンドウをアクティブにして表示します。ウィンドウが最小化または最大化されている場合は、元のサイズと位置に戻ります。
3 ウィンドウをアクティブにし、最大化ウィンドウとして表示します。
7 ウィンドウを最小化し、次に上位となるウィンドウをアクティブにします。


URLショートカットオブジェクト

ショートカットオブジェクトを作成するとき、 パス名の拡張子を.lnkではなく.urlとすれば URLショートカットオブジェクトが作成され、 結局、インターネットショートカットファイルが作成されます。

pathname = fldDesktop.Path + "\\wsh.url";
url = "http://homepage3.nifty.com/aya_js/wsh/wsh_frm.htm";
oUrlLink = WShell.CreateShortcut(pathname);
oUrlLink.TargetPath = url;
oUrlLink.Save();



レジストリ

Registory

値を書きこむ

レジストリには次のように値を書きこむことができます。

regnew.js

var {WScript} = require("wsh");

var WShell = WScript.CreateObject("Wscript.Shell");
var strDate = (new Date()).toLocaleString();    //現在の日時
//値を書きこむ
WShell.RegWrite("HKCU\\Software\\aya\\date", strDate);

HKEY_CURRENT_USER\Softwareの下にayaというキーを作り、その下にdateという値を作って現在の日時を書きこみます。
RegWriteは次のように使います。

WshShell.RegWrite(strName, anyValue, [strType])

strNameはキーまたは値の名前です。上の例のようにルートから書かなければなりません。すなわち、次の5つのキーから始めなればなりません。

   HKEY_CURRENT_USER
   HKEY_LOCAL_MACHINE
   HKEY_CLASSES_ROOT
   HKEY_USERS
   HKEY_CURRENT_CONFIG

ただし、上の3つは短縮形を用いることができます。

   HKCU
   HKLM
   HKCR

strNameが\で終わると、キーの標準の値を書きこむことになります。

strTypeでデータ型を指定できます。指定できる型は次の通りです。

REG_SZ 文字列
REG_EXPAND_SZ 文字列
REG_DWORD 32ビット整数値
REG_BINARY バイナリ

データ型を指定すると、値が適当に変換されて書きこまれます。

var d = new Date();
WShell.RegWrite("HKCU\\Software\\aya\\date", d, "REG_SZ");

このようにすると、dは自動的に"Fri Oct 2 22:13:48 UTC+0900 1998" と変換されて書きこまれます。
REG_BINARYを指定した場合は、値は32ビット整数値でなければなりません。 32ビットより長いバイナリ値を書きこむ方法は今のところなさそうです。

値を読み取る

レジストリの値は次のように読み取ります。

regread.js

var {WScript} = require("wsh");

var WShell = WScript.CreateObject("Wscript.Shell");

var a = WShell.RegRead("HKCU\\Software\\aya\\date");
WScript.Echo(a);

var strDate = (new Date()).toLocaleString();
WShell.RegWrite("HKCU\\Software\\aya\\date", strDate);

さきほど作ったキーの値を読みとって表示します。そのあと、また新しく書きこまれます。
RegReadは次のように使います。

WshShell.RegRead(strName)

strNameの値を返します。 strNameが存在しない場合はエラーが発生します。

値を削除する

レジストリの値は次のように削除します。

regdel.js

var {WScript} = require("wsh");

var WShell = WScript.CreateObject("Wscript.Shell");

WShell.RegDelete("HKCU\\Software\\aya\\date");

上で作った値を削除します。
RegDeleteは次のように使います。

WshShell.RegDelete(strName)

strNameで表される値を削除します。 strNameが存在しない場合はエラーが発生します。 strNameがキーの場合は、その下のキー・値は全て削除されます。



WshShell

WshShell

Environment

次のように環境変数を得ることができます。

path.js

var {WScript} = require("wsh");

var WShell = WScript.CreateObject("Wscript.Shell");
var WshEnv = WShell.Environment;
WScript.Echo(WshEnv("PATH").$);

PATHの値を得ることができます。

    var WshEnv = WShell.Environment);

で、WshEnvironmentオブジェクトを得て、

    WshEnv("PATH").$

で、個々の環境変数を得ます。

得られる環境変数には、個々の環境によって違うでしょうが、次のようなものがあります。

COMSPEC コマンドプロンプトの実行ファイルのフルパス
PATH 切ってあるパス
WINDIR Windowsディレクトリ
PROMPT コマンドプロンプト ex) $p$g
TEMP テンポラリディレクトリ
TMP テンポラリディレクトリ
WINBOOTDIR Windowsディレクトリ?
BLASTER
CMDLINE WINって出るけど

SpecialFolders

次のように特別なフォルダのフルパスを得ることができます。

desktop.js

var {WScript} = require("wsh");

var WShell = WScript.CreateObject("Wscript.Shell");
WScript.Echo(WShell.SpecialFolders("Desktop"));

デスクトップフォルダのフルパスが得られます。

これも環境によって違うかと思いますが、以下のような特別なフォルダのフルパスが得られます。

   Desktop
   Favorites
   Fonts
   MyDocuments
   NetHood
   Programs
   Recent
   SendTo
   StartMenu
   Startup

Popup

次のようにメッセージボックスを出すことができます。

popup.js

var {WScript} = require("wsh");

var WShell = WScript.CreateObject("Wscript.Shell");
WShell.Popup("はにゃ~~~ん");

これだと Echo となんら変わらないのですが、 Popup は色々なオプションをつけることができます。構文は次のようです。

    WShell.Popup(strText,
            [natSecondsToWait], [strTitle], [natType])

strText は表示するテキスト、 strTitle はメッセージボックスのタイトル、 natSecondsToWait を指定すると、表示されてからボタンを押さないでその指定した秒数待つと自然に消えます。

natType は次に示すオプションの値の足し算になります。

0 「OK」ボタンのみ表示
1 「OK」と「キャンセル」ボタンを表示
2 「中止」と「再試行」と「無視」ボタンを表示
3 「はい」と「いいえ」と「キャンセル」ボタンを表示
4 「はい」と「いいえ」ボタンを表示
5 「再試行」と「キャンセル」ボタンを表示
16 「ストップマーク」を表示
32 「クエスチョンマーク」を表示
48 「びっくりマーク」を表示
64 「情報マーク」( i のマーク)を表示

返り値は押したボタンによって以下のようになります。

1 「OK」ボタン
2 「キャンセル」ボタン
3 「中止」ボタン
4 「再試行」ボタン
5 「無視」ボタン
6 「はい」ボタン
6 「いいえ」ボタン

natSecondsToWait が指定してあり、自動的に消えた場合は -1 が返ります。



CommonDialog

CommonDialog_1

このページのスクリプトを実行するには、コモンダイアログコントロール (Comdlg32.ocx)がインストールされている必要があります。インストールされていない場合は、 Visual Basic 6.0 Service Pack 6:ランタイム再頒布可能パッケージ から拾ってきてください。

ActiveX「MSComDlg.CommonDialog」は、64ビット版Windows上で動作しないので注意してください。

「Windows JavaScript」-「CommonDialogクラス」を使えば、32,64ビット版Windowsどちらも動作します。

「ファイルを開く」ダイアログ

WSHであるファイルに対して何か処理を行いたいということが多いかと思いますが、今までは引数で直接ファイルを指定してきた、すなわちファイル名(フルパス)を入力してきました。そいういうとき普通のWindowsアプリなら「ファイルを開く」ダイアログを開いてマウスでファイルを選びますが、同じことをWSHでも行いましょう。

cat.js

var {WScript} = require("wsh");

var fs = WScript.CreateObject("Scripting.FileSystemObject");

//コモンダイアログコントロール
var ComDlg = WScript.CreateObject("MSComDlg.CommonDialog");

//ファイル名を格納する場所のサイズ
ComDlg.MaxFileSize = 256;

//「ファイルを開く」ダイアログを開く
ComDlg.ShowOpen();

if (ComDlg.FileName.length==0) {
  // キャンセル
  WScript.Quit();
}

var stream = fs.OpenTextFile(ComDlg.FileName);
while(!stream.AtEndOfStream)
    WScript.Echo(stream.ReadLine());
stream.Close();

これは指定したテキストファイルの内容を表示するスクリプトです。「ファイルを開く」ダイアログを開いてマウスでファイルを選び、「開く」ボタンを押してください。そうすると、コモンダイアログコントロールの FileName プロパティにファイル名が格納されるので、それを用いてファイルを開きテキストを表示します。

複数のファイルを選択する

cat は UNIX では連結する(concatenate)という意味のコマンドです。そのため複数のファイルが選択できないといけません。上の例では1つのファイルしか選択できませんが、 Flagsプロパティを変えることにより複数のファイルが選択できるようになります。

cat2.js

var {WScript} = require("wsh");

var fs = WScript.CreateObject("Scripting.FileSystemObject");

var ComDlg = WScript.CreateObject("MSComDlg.CommonDialog");
var CDL = WScript.loadConsts(ComDlg);

ComDlg.MaxFileSize = 256;
//複数のファイル選択&エクスプローラ風
ComDlg.Flags = CDL.cdlOFNAllowMultiselect | CDL.cdlOFNExplorer;

ComDlg.ShowOpen();

if (ComDlg.FileName.length==0) {
  // キャンセル
  WScript.Quit();
}

var fnames = new Array();
GetPaths(ComDlg.FileName, fnames);      //ファイル名を配列に

var stream;
for(var i = 0; i < fnames.length; i++) {
    stream = fs.OpenTextFile(fnames[i]);
    while(!stream.AtEndOfStream)
        WScript.Echo(stream.ReadLine());
    stream.Close();
    stream = null;
}

function GetPaths(str, arr) {
    var len, nnull, npath, path, pos;
    len = str.length;
    nnull = npath = path = 0;
    path = "";
    
    for(var i = 0; i < len; i++)
        if(str.charAt(i) == "\0") {
            if(nnull++ == 0) {
                path = str.substring(0, i);
                if(path.charAt(path.length - 1) != "\\")
                    path += "\\";
            }
            else
                arr[npath++] = path + str.substring(pos, i);
            pos = i + 1;
        }
    arr[npath] = path + str.substring(pos, i);
}

FlagscdlOFNAllowMultiselect(0x200)(複数のファイルを選択できる)とcdlOFNExplorer(0x80000)(エクスプローラ風ダイアログ)を設定しています。複数の設定を両立させるには上のように論理和をとります。

複数のファイル名が取得されたときそれらはヌル文字で区切られて、 Filename に設定されます。例えばCドライブのルートでa.txtとb.txtを選ばれたときは次のようになります。

C : \\ \0 a . t x t \0 b . t x t

このように、最初のヌル文字の前まででディレクトリが指定され、そのあとヌル文字で区切られてファイル名が記述されるようです。

初期ディレクトリの設定

ダイアログが開くとき、最初にカレントディレクトリを見に行きたいときは、 InitDir に設定します。

cat3.js

var {WScript} = require("wsh");

var fs = WScript.CreateObject("Scripting.FileSystemObject");

var ComDlg = WScript.CreateObject("MSComDlg.CommonDialog");

ComDlg.MaxFileSize = 256;
ComDlg.Flags = CDL.cdlOFNAllowMultiselect | CDL.cdlOFNExplore;
//カレントディレクトリを最初に見に行く
ComDlg.InitDir = ".";

ComDlg.ShowOpen();

//以下略

拡張子による限定

特定の拡張子のファイルのみ表示したいときは Filter に次のように設定します。

ComDlg.Filter = "JScript(*.js)|*.js|VBScript(*.vbs)|*.vbs";

このように、

ファイルの種類|拡張子|ファイルの種類|拡張子

と設定します。

上では、初期画面のダイアログのファイルの種類リストには

    JScript(*.js)

と表示されますが、これを VBScript(*.vbs) にするには FilterIndexを次のように設定します。

ComDlg.FilterIndex = 2;

2番目のファイルの種類が表示されるという意味です。



Input

Input

今回は入力について書いてみたいと思います。入力と出力がソフトウェアの基本だと思っているのですが、 WSHにはどうやら標準入力というものが無いようです。 VBScriptにはInputBoxという関数があり、これで入力できますが、 JavaScriptにはこれに対応するものがありません。入力というと最初のほうに書いた、引数とテキストファイルくらいでしょうか。このあと、InputBox関数とその代用について述べます。

InputBoxはprompt関数を使用

VBScriptにはInputBox関数というものがあって、これによって入力を行えます。

Dim strRet
strRet = InputBox("なんか入力してね")
WScript.Echo(strRet)

これを実行すると、「なんか入力してね」という文字とOKボタンCancelボタン、それにテキストボックスが配置されたウィンドウが開きます。テキストボックスに何か文字列を入力してOKボタンを押すと、その文字列が返り値となります。

これを jsLibライブラリーにあるprompt関数を使用してプログラムできます。

input.js

var {WScript} = require("wsh");

var strRet = prompt("なんか入力してね");
WScript.Echo(strRet);

Excelで代用する

Excelを使ってプログラミングしてみます。

input2.js

var {WScript} = require("wsh");

var excel = WScript.CreateObject("Excel.Application");
var strRet = excel.InputBox("はじめまして",
                "あいさつ", "どうぞよろしく");
excel.Quit();
WScript.Echo(strRet);

ExcelのメソッドとしてVBAの関数を使っています。非常に応用範囲が広そうです。



FTP

FTP

ウェブページを作っていると、ページを自動的に更新したくなることがあるかもしれません。すなわち、ファイルをFTPでサーバに送るのですが、こういう場合は意外にもDOSのコマンドのFTPが使えます。
Shell32.dllを使うと高度な制御が出来るかもしれません。

FTPを自動的に行う

FTPコマンドは通常インタラクティブに使いますが、次のようにしてスクリプトファイルを指定し、コマンドを次々と実行することができます。

    ftp -s:scriptfile

スクリプトファイルにはコマンドを次のように列挙しておきます。

    open host
    user-id
    password
    cd directory
    asc
    put filename
    quit

これで1つファイルをASCIIモードで送ることができます。

ページを更新する

例えば、Excelに毎日何歩歩いたかをこんな風につけていて、

日付 歩数
2010/1/1 6264
2010/1/2 9368
2010/1/3 5219
2010/1/4 9013
2010/1/5 4619

これをウェブ上に公開するとします。
このページを作ってはFTPしてるんではダイヤルアップの場合電話代がもったいないので、毎日の定期巡回のときに次のスクリプトを実行します。

walking.js

var {WScript} = require("wsh");

//Excelのシートから情報を得る
var objXL = WScript.CreateObject("Excel.Application");
objXL.WorkBooks.Open("c:\\windows\\デスクトップ\\walking.xls");
var d = new Array();        //日付
var nsteps = new Array();   //歩数
var tmp, r;
with(objXL) {
    for(r = 2; (tmp = Cells(r, 1).Text) != ""; r++) {
        d[r-2] = tmp;
        nsteps[r-2] = Cells(r, 2).Value;
    }
}
objXL.Quit();

//HTMLファイルを作成する
var fs = WScript.CreateObject("Scripting.FileSystemObject");
var stream = fs.CreateTextFile("walking.htm", true);
stream.Write("<HTML>\n<BODY>\n<TABLE BORDER>\n")
stream.Write("<TR><TH>日付</TH><TH>歩数</TH></TR>\n");
for(var i = 0; i < d.length; i++)
    stream.Write("<TR><TD>" + d[i] + "</TD><TD ALIGN=RIGHT>"
            + nsteps[i] + "</TD></TR>\n");
var sum = 0;            //合計の歩数
for(i = 0; i < d.length; i++)
    sum += nsteps[i];
stream.Write("<TR><TD>計</TD><TD>" + sum + "</TD></TR>\n");
stream.Write("</TABLE>\n</BODY>\n</HTML>\n");
stream.Close();

//FTP
var WShell = WScript.CreateObject("WScript.Shell");
WShell.Run("ftp -s:walking.scr", 0, true);

WScript.Echo("ファイル転送おわったよ");

Excelのファイルを読んで(DAO を使ったほうがかっこいいかもしれませんが)、そのデータを元に次のようなHTMLファイルを作っています。

日付 歩数
1999/1/1 6264
1999/1/2 9368
1999/1/3 5219
1999/1/4 9013
1999/1/5 4619
34483

このファイルを転送します。 FTPのスクリプトファイルwalking.scrはいつも一定なので上に倣ってあらかじめ用意します。



イベントを拾う

Catch_Event

イベントの拾い方

オブジェクトに何かが起こった場合、例えばサイズが変わったとか、終了したとかいうときに、イベントが発生します。 CreateObject でオブジェクトを作るとそのイベントを拾うことができます。次のコードを見てください。

word_quit.js

var {WScript} = require("wsh");

//Wordを立ち上げる
var word = WScript.CreateObject("Word.Application");

//イベントを設定
WScript.addEventHandlers(word,
  {
    Quit: WD_Quit,
    NewDocument: WD_NewDocument
  }
);


word.Visible = true;       //Wordを可視にする

//イベントを待つためのループ
WScript.waitEvents();

alert("Wordが終了しました");

WScript.unAdvise(word);  //イベントを切断
word = null;

// 終了イベント
function WD_Quit() {
  WScript.cancelWaitEvents();  //イベントループを終了させる
}

// 新規ドキュメント作成イベント
function WD_NewDocument(doc) {
  alert("New Document!");
}

WScript.addEventHandlers関数で、wordのイベントをキャッチする関数が登録されます。QuitイベントはWD_Quit関数、NewDocumentイベントはWD_NewDocument関数が処理します。
上の例だと、Wordを立ち上げた後は、WScript.waitEvents()で無限ループをずっと回っているのですが、ウィンドウの右上のところをクリックしたりしてWord を終わらせようとするとQuitイベントが発生します。そうすると、WD_Quitというサブルーチンが実行されて、 "Wordが終了しました"と表示して、Wordが終わって、スクリプトも終わります。

イベントを扱う場合、次の3つの約束を守らなければ無限ループに入って終了できないことがあります。

(1) 少なくとも1つイベント処理関数を作成しておく。
(2) イベント待ちループ(WScript.waitEvents())を抜けるには、
    イベント処理関数内で WScript.cancelWaitEvents() を実行する。
(3) スクリプト終了では、WScript.unAdvise(...)を実行する。



Shell(1)

Shell_1

Shellオブジェクトはウィンドウズの色々なシェル機能を提供します。 WindowsやIEのバージョンによって動作が異なるようですが、 ここで確認しているのは、Windows7、IE8です。主にScriptable Shell Objectsを参考にしています。 このページと次のページで Shellオブジェクトのメソッドを紹介しますが、 抜けているところはここを参考にしてください。

Shellオブジェクトを得る

Shellオブジェクトは次のように得ます。

var Shell = WScript.CreateObject("Shell.Application");

フォルダを開く

blue,Open メソッドを使うとフォルダを開くことができます。フォルダはエクスプローラタイプがデフォルトで開く場合はエクスプローラが開くようです。

Shell.Open(vDir)

vDir はフォルダのパスです。

openexplorer.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
Shell.Open("d:\\");

vDir に定数を指定して特殊フォルダを開くこともできます。

opendesktop.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var SSF = WScript.loadConsts(Shell);

Shell.Open(SSF.ssfDESKTOP);

定数と特殊フォルダの関係は以下のようになっています。この表はShellSpecialFolderConstants Enumerationに基づいています。

ssfDESKTOP 0 デスクトップ
ssfPROGRAMS 2 ユーザのスタートメニューのプログラム
ssfCONTROLS 3 コントロールパネル
ssfPRINTERS 4 プリンタ
ssfPERSONAL 5 ユーザのMy Document
ssfFAVORITES 6 ユーザのお気に入り
ssfSTARTUP 7 ユーザのスタートアップ
ssfRECENT 8 ユーザの最近使ったファイル
ssfSENDTO 9 ユーザのSendTo
ssfBITBUCKET 10 ごみ箱
ssfSTARTMENU 11 ユーザのスタートメニュー
ssfDESKTOPDIRECTORY 16 ユーザのデスクトップ
ssfDRIVES 17 マイコンピュータ
ssfNETWORK 18 マイネットワーク
ssfNETHOOD 19 ユーザのNetHood
ssfFONTS 20 FONTS
ssfTEMPLATES 21 Templates
ssfCOMMONSTARTMENU 22 共通のスタートメニュー
ssfCOMMONPROGRAMS 23 共通のプログラム
ssfCOMMONSTARTUP 24 共通のスタートアップ
ssfCOMMONDESKTOPDIR 25 共通のデスクトップ
ssfAPPDATA 26 共通のApplication Data
ssfPRINTHOOD 27 ユーザのPrintHood
ssfLOCALAPPDATA 28 ユーザのApplication Data
ssfALTSTARTUP 29 ユーザのローカルでないスタートアップ
ssfCOMMONALTSTARTUP 30 共通のローカルでないスタートアップ
ssfCOMMONFAVORITES 31 共通のお気に入り
ssfINTERNETCACHE 32 ユーザのInternetのキャッシュ
ssfCOOKIES 33 ユーザのCookie
ssfHISTORY 34 History
ssfCOMMONAPPDATA 35 共通のApplication Data
ssfWINDOWS 36 Windowsディレクトリ
ssfSYSTEM 37 Systemディレクトリ
ssfPROGRAMFILES 38 Program Files
ssfMYPICTURES 39 ユーザのMy Pictures
ssfPROFILE 40 ユーザのProfile

Explore メソッドを使うと設定にかかわらずエクスプローラを開くことができます。

Shell.Explore(vDir)

vDir はフォルダのパスです。

explore.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
Shell.Explore("d:\\");

Open メソッドと同様に、 vDir に定数を指定して特殊フォルダを開くこともできます。

フォルダ選択ダイアログを開く

BrowseForFolder を使うとフォルダ選択ダイアログを開くことができます。

Shell.BrowseForFolder(Hwnd, Title, Options[, RootFolder]);

BrowseForFolder メソッドはフォルダ選択ダイアログを開いて選択された Folder オブジェクトを返します。 Hwndは親のウィンドウハンドルで0に指定しておけばいいです。 Titleはダイアログに表示されるタイトルです。 Optionsはダイアログのスタイルです(後述)。 RootFolderはダイアログのツリーの一番上のフォルダを指定します。上のvDirと同様です。

browseforfolder.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.BrowseForFolder(0, "フォルダを選ぶ", 0, "d:\\");
if(!objFolder) {
    WScript.Echo("フォルダを選択してください");
    WScript.Quit();
}
WScript.Echo(objFolder.Items().Item().Path);

最後の行はフォルダのパスを表示しています。
Options を次の表の値の Or を取ったものです。下の定数の表は shlobj.h を参照しました。最後のカラムは自分で実行してみたものですが、バージョンが新しすぎるためか shlobj.h のコメントと合わないものが多く見受けられました。

BIF_RETURNONLYFSDIRS 0x0001
BIF_DONTGOBELOWDOMAIN 0x0002
BIF_STATUSTEXT 0x0004
BIF_RETURNFSANCESTORS 0x0008
BIF_EDITBOX 0x0010 フォルダ名を入力することができます
BIF_VALIDATE 0x0020
BIF_NEWDIALOGSTYLE 0x0040
BIF_USENEWUI 0x0050
BIF_BROWSEINCLUDEURLS 0x0080 URLを選択または入力することができます。BIF_USENEWUIと併用が必須。
BIF_UAHINT 0x0100
BIF_BROWSEFORCOMPUTER 0x1000
BIF_BROWSEFORPRINTER 0x2000 プリンタの参照
BIF_BROWSEINCLUDEFILES 0x4000 ファイルも参照
BIF_SHAREABLE 0x8000 共有も参照



Shell(2)

Shell_2

ウィンドウをまとめて操作する

以下の操作が Shell オブジェクトのメソッドのより可能です。

CascadeWindows ウィンドウをカスケードに並べる cascade.js
MinimizeAll すべて最小化する minimize.js
UndoMinimizeAll 最小化したウィンドウを元に戻す minimize.js
TileHorizontally ウィンドウをタイル状に左右に並べる tile.js
TileVertically ウィンドウをタイル状に上下に並べる tile.js

minimize.jsというスクリプトは MinimizeAll した後に3秒待って UndoMinimizeAll するスクリプトです。

minimize.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
Shell.MinimizeAll();
WScript.Sleep(3000);
Shell.UndoMinimizeAll();

tile.jsも似たような感じです。

アプレットを開く

ControlPanelItem メソッドでコントロールパネルを開くことができます。

Shell.ControlPanelItem(szDir);

szDir はコントロールパネルのパスです。また、引数をコントロールパネルを開くと同じように指定することができます。

cpanel.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
Shell.ControlPanelItem("c:\\windows\\system\\access.cpl ,3");

その他に、以下の個々のアプレット(?)を Shell オブジェクトのメソッドで開くことができます。

FileRun ファイル名を指定して実行 filerun.js
FindComputer コンピュータを検索 findcomputer.js
FindFiles ファイルとフォルダを検索 findfiles.js
SetTime 日付と時刻のプロパティ settime.js
ShutdownWindows Windowsの終了 shutdown.js

Windows

&color(blue,Windows メソッドを使うと、 ShellWindows オブジェクトという IEやエクスプローラのコレクションを得ることができます。

詳しくは次のページへ。

NameSpace

NameSpace メソッドを使うと、 Folder オブジェクトが得られます。

詳しくは次の次のページに書く予定です。



ShellWindows

ShellWindows

WindowsShellオブジェクト

WindowsShell オブジェクトにより現在開いている IE とエクスプローラを制御できます。 WindowsShell オブジェクトは次のように ShellオブジェクトのWindowsメソッドにより得ます。

var Shell = WScript.CreateObject("Shell.Application");
var WindowsShell = Shell.Windows();

個々の IE オブジェクトを得るには次のようにします。

WindowsShell.item(index)

index は0から始まる整数です。 index はウィンドウを開いた順に付くようです。
いくつウィンドウが開いているかは Count プロパティで得られます。

window_count.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var WindowsShell = Shell.Windows();
WScript.Echo(WindowsShell.Count);

もちろん IE やエクスプローラを立ち上げれば Count は増えます。

windows_increment.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var WindowsShell = Shell.Windows();
WScript.Echo(WindowsShell.Count);

//IEを立ち上げる
var IE = WScript.CreateObject("InternetExplorer.Application");
WScript.Echo(WindowsShell.Count);    //1つ増えている
IE.Quit();

IEとエクスプローラを判別する

IE とエクスプローラを判別するには色々な方法があると思いますが(決定的なものがないともいう)、とりあえず FullName プロパティを使ってみましょう。これは実行ファイルのパスを返すようです。 IE なら ~\iexplore.exe となるので次の例のように判定します。

windowtype.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var WindowsShell = Shell.Windows();
var str = "";
for(var i = 0; i < WindowsShell.Count; i++) {
    if(WindowsShell.item(i).FullName.match(/iexplore.exe$/i))
        str += i + " : iexplorer\n";
    else
        str += i + " : explorer\n";
}
WScript.Echo(str);

上のスクリプトは各 window のタイプを表示します。

IE

IE のタイプの場合、スクリプトで起動していないウィンドウも スクリプトで起動したウィンドウと同じように制御する ことができることになります。下のスクリプトでは IE をすべて閉じます。

ie_allquit.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var WindowsShell = Shell.Windows();
for(var i = WindowsShell.Count - 1; i >= 0; i--)
    //IEタイプなら閉じる
    if(WindowsShell.item(i).FullName.match(/iexplore.exe$/i))
        WindowsShell.item(i).Quit();

エクスプローラ

エクスプローラのタイプでも同様に制御することができます。次のスクリプトは最初のエクスプローラの表示をc:\にします。

to_C.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var WindowsShell = Shell.Windows();
for(var i = 0; i < WindowsShell.Count; i++) {
    if(!WindowsShell.item(i).FullName.match(/iexplore.exe$/i)) {
        WindowsShell.item(i).Navigate("c:\\");
        WScript.Quit();
    }
}



Folder

Folder

Folder オブジェクトによりフォルダを操作することができます。

Folderオブジェクトを得る

FolderオブジェクトはShellオブジェクトの NameSpaceメソッドで得られます。

objFolder = Shell.NameSpace(vDir);

vDirShellオブジェクトOpenメソッドなどと同様です。
また、復習になりますが、BrowseForFolderメソッドでも得られます。

Folderの情報を得る

Titleプロパティでフォルダのタイトルを得ることができます。
ParentFolderプロパティでは親のFolderオブジェクトを得ることができます。

fldtitle.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.NameSpace(3);
WScript.Echo(objFolder.Title);
var objFolder2 = objFolder.ParentFolder;
WScript.Echo(objFolder2.Title);

NameSpaceの引数は3になっていますが、これはコントロールパネルを表します。 Titleプロパティは"コントロール パネル"となります。要するにエクスプローラの表示になるんですね。
ParentFolderは"マイ コンピュータ"を表します。ここもエクスプローラのツリーを反映しています。

Itemsメソッドでフォルダの中のアイテムを列挙することができます。
まず、Itemsメソッドで FolderItemsオブジェクトを得て、 FolderItemsオブジェクトの Itemメソッドでフォルダの中の一つ一つのFolderItemオブジェクトを得ます。

flditems.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.NameSpace(0);     //デスクトップ
var objFolderItems = objFolder.Items();
for(var i = 0; i < objFolderItems.Count; i++)
    WScript.Echo(objFolderItems.Item(i).Name);

FolderItemオブジェクトの Nameプロパティでアイテムの名前を得ることができるので、デスクトップの下のアイテムの名前を列挙することになります。
FolderItemオブジェクトについては 次のページで詳しく述べています。

GetDetailsOfで個々のアイテムの詳細な情報を得ることができます。

objFolder.GetDetailsOf(vItem, iColumn);

vItemFolderItemオブジェクトを表します。 iColumnに応じて返す情報が以下のように変わります。

iCound 説明
0 オブジェクトの名前
1 オブジェクトのサイズ
2 オブジェクトの種類
3 オブジェクトの更新日時
4 オブジェクトの属性
-1 オブジェクトの説明

0だと上のスクリプトと同じことになります。

getdetailsof.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.NameSpace(0);
var objFolderItems = objFolder.Items();
for(var i = 0; i < objFolderItems.Count; i++)
    WScript.Echo(objFolder.GetDetailsOf(objFolderItems.Item(i), 0));

ParseNameメソッドで名前がわかっているアイテムに対応する FolderItemオブジェクトを得ることができます。

objFolder.ParseName(bName);

bNameはアイテムの名前です。

parsename.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var c_root = Shell.NameSpace("c:\\");
WScript.Echo(c_root.Title);
var a = c_root.ParseName("autoexec.bat");        //FolderItemオブジェクト
WScript.Echo(a.Name);

フォルダを操作する

CopyHereメソッドでアイテムをそのフォルダにコピーすることができます。

objFolder.CopyHere(vItem), [vOptions]);

vItemFolderItemオブジェクトか FolderItemsオブジェクトかアイテムの名前です。

copyhere1.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var desktop = Shell.NameSpace(0);
var test = Shell.NameSpace("c:\\work\\test");
var item1 = test.Items().Item(0);
desktop.CopyHere(item1);     //FolderItemオブジェクト

copyhere2.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var desktop = Shell.NameSpace(0);
var test = Shell.NameSpace("c:\\work\\test");
var items1 = test.Items();
desktop.CopyHere(items1);    //FolderItemsオブジェクト

copyhere3.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var desktop = Shell.NameSpace(0);
desktop.CopyHere("c:\\autoexec.bat");    //名前

vOptionsは次の表のFlagの組合せです。

Flag 説明
FOF_ALLOWUNDO 0x0040 Undoが有効
FOF_NOCONFIRMATION 0x0010 上書きしますかとか聞いてこなくなる
FOF_NO_CONNECTED_ELEMENTS 0x2000
FOF_NOCOPYSECURITYATTRIBS 0x0800
FOF_NOERRORUI 0x0400 エラーを表示しない
FOF_NORECURSION 0x1000 再帰的なディレクトリの処理はしない
FOF_RENAMEONCOLLISION 0x0008 同じ名前があったら名前を付け替える
FOF_SILENT 0x0004 進度を表す表示がない
FOF_SIMPLEPROGRESS 0x0100 進度を表す表示でファイル名を省略

まだ調べることができていない項目については説明を省いています。また、関係なさそうな定数は消去しています。

copyhere4.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var desktop = Shell.NameSpace(0);
desktop.CopyHere("c:\\Program Files", 0x1040);

上の場合はFOF_ALLOWUNDOFOF_NORECURSIONのフラグが立っているので、デスクトップに"Program Files"というフォルダだけコピーされます。また、Undo(Ctrl+Z)は有効です。
vOptionsが省略された場合、または、0の場合は、 FOF_ALLOWUNDOが立っているようです。

MoveHereメソッドでアイテムをそのフォルダに移動することができます。

objFolder.MoveHere(vItem, [vOptions]);

vItemvOptionsCopyHereと同じです。

movehere.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var desktop = Shell.NameSpace(0);
desktop.MoveHere("c:\\work\\test\\worker.txt");

NewFolderメソッドでそのフォルダに新しいフォルダを作ることができます。

objFolder.NewFolder(bName, [vOptions]);

bNameは新しいフォルダの名前です。 vOptionsは今は使われていないそうです。

newfolder.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var favorites = Shell.NameSpace(0);     //デスクトップ
favorites.NewFolder("天気予報でございます");



FolderItem

FolderItem

FolderItem オブジェクトはフォルダの中のアイテムを表します。
主にFolderオブジェクトから FolderItemsコレクションを得て、そこからFolderItemオブジェクトを得ます。

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.NameSpace("C:\\");    //Folderオブジェクト
var objFolderItems = objFolder.Items();     //FolderItemsコレクション
for(var i = 0; i < objFolderItems.Count; i++)
    var ofitem = objFolderItems.Item(i);    //FolderItemオブジェクト

FolderItemの情報を得る

次の例のようにFolderItemの基本情報を得ることができます。

flditem1.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.NameSpace(0);         //デスクトップ
var objFolderItems = objFolder.Items();
for(var i = 0; i < objFolderItems.Count; i++) {
    var ofitem = objFolderItems.Item(i);
    WScript.Echo("Name : " + ofitem.Name);  //名前
    WScript.Echo("Path : " + ofitem.Path);  //パス
    WScript.Echo("Size : " + ofitem.Size);  //大きさ
    WScript.Echo("Type : " + ofitem.Type);  //種類
    //更新日時
    WScript.Echo("ModifyDate : " + ofitem.ModifyDate + "\n");
}

フォルダのサイズは常に0のようですね。

次の例のようにIs付きプロパティで FolderItemの性質を判別することができます。

flditem2.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.NameSpace(0);
var objFolderItems = objFolder.Items();
for(var i = 0; i < objFolderItems.Count; i++) {
    var ofitem = objFolderItems.Item(i);
    if(ofitem.Name == "ごみ箱") {
        WScript.Echo("" + ofitem.IsBrowsable);  //参照できるか
        WScript.Echo("" + ofitem.IsFileSystem); //FileSystemの一部か
        WScript.Echo("" + ofitem.IsFolder);     //フォルダか
        WScript.Echo("" + ofitem.IsLink);       //ショートカットか
    }
}

ちなみにごみ箱では上から順にfalse, false, true, falseです。

ショートカットならGetLinkプロパティで IShellLinkDualオブジェクトを得ることができます。このTargetプロパティでリンク先の FolderItemオブジェクトを得ます。

getlink.js

var {WScript} = require("wsh");

var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.NameSpace(0);        //デスクトップ
var objFolderItems = objFolder.Items();
for(var i = 0; i < objFolderItems.Count; i++) {
    var ofitem = objFolderItems.Item(i);
    if(ofitem.IsLink) {         //ショートカットなら
        var olink = ofitem.GetLink;
        var otargetitem = olink.Target;
        WScript.Echo(ofitem.Name + " -> " + otargetitem.Path);
    }
}

フォルダならGetFolderプロパティでFolderオブジェクトを得ることができます。これによって下の階層を全てスキャンすることができます。

update.js

var {WScript} = require("wsh");

var Now = (new Date()).getTime();
var Shell = WScript.CreateObject("Shell.Application");
var objFolder = Shell.NameSpace("C:\\work");
ScanFolder(objFolder);

function ScanFolder(objFolder) {
    var objFolderItems = objFolder.Items();
    for(var i = 0; i < objFolderItems.Count; i++) {
        var ofitem = objFolderItems.Item(i);
        if(ofitem.IsFolder)
            ScanFolder(ofitem.GetFolder);
        //24時間しか経っていないアイテムを出力する
        if(Now - (new Date(ofitem.ModifyDate)).getTime()
                                        <= 24 * 60 * 60000)
            WScript.Echo(ofitem.ModifyDate + " " + ofitem.Path);
    }
}

上のスクリプトはCドライブの24時間以内に更新されたファイルを列挙します。これをFileSystemObjectを使ったときと比べてみましょう。

update2.js

var {WScript, Enumerator} = require("wsh");

var Now = (new Date()).getTime();
var fs = WScript.CreateObject("Scripting.FileSystemObject");
var f = fs.GetFolder("c:\\work");

ScanFolder(f)

function ScanFolder(f) {
    var fc = new Enumerator(f.SubFolders);
    for(; !fc.atEnd(); fc.moveNext()) {
        var ofolder = fc.item();
        ScanFolder(ofolder);
        if(Now - (new Date(ofolder.DateLastModified)).getTime()
                                            <= 24 * 60 * 60000)
            WScript.Echo(ofolder.DateLastModified
                                        + " " + ofolder.Path);
    }
    var fic = new Enumerator(f.Files);
    for(; !fic.atEnd(); fic.moveNext()) {
        var ofile = fic.item();
        if(Now - (new Date(ofile.DateLastModified)).getTime()
                                            <= 24 * 60 * 60000)
            WScript.Echo(ofile.DateLastModified
                                        + " " + ofile.Path);
    }
}

Folderオブジェクトを使ったときのほうが Temporary Internet Filesのスキャンがかなり速いですね。でもその他は遅いような。

コマンドを発行する

InvokeVerbメソッドでコンテキストメニューのコマンドを発行できます。

objFolderItem.InvokeVerb(vVerb);

vVerbは後述するコマンドを表す文字列です。例えば次のようにごみ箱を開きます。

invokeverb.js

var {WScript} = require("wsh");

var oTrash = GetTrash();
oTrash.InvokeVerb("開く(&O)");

function GetTrash() {
    var Shell = WScript.CreateObject("Shell.Application");
    var objFolder = Shell.NameSpace(0);
    var objFolderItems = objFolder.Items();
    for(var i = 0; i < objFolderItems.Count; i++) {
        var ofitem = objFolderItems.Item(i);
        if(ofitem.Name == "ごみ箱")
            return ofitem;
    }
    return null;
}

vVerbは次のように FolderItemVerbオブジェクトの Nameプロパティから得られます。

verbs.js

var {WScript} = require("wsh");

var oTrash = GetTrash();
var oVerbs = oTrash.Verbs();
for(var i = 0; i < oVerbs.Count; i++)
    WScript.Echo(oVerbs.Item(i).Name);

//以下略

上のスクリプトはごみ箱に対して使えるvVerbを列挙しているのですが、使えないvVerbもあるようですね。FolderItemVerbオブジェクトの DoItメソッドを使ってもコマンドを発行できます。

verbs2.js

var {WScript} = require("wsh");

var oTrash = GetTrash();
var oVerbs = oTrash.Verbs();
for(var i = 0; i < oVerbs.Count; i++) {
    if(oVerbs.Item(i).Name.charAt(0) == "開")
        oVerbs.Item(i).DoIt();
}

//以下略

FTP

Shellオブジェクトの NameSpaceメソッドに FTPサーバのディレクトリを指定すると、ローカルのフォルダのように操作できます。
次のスクリプトは指定したディレクトリ以下の全てのファイルのサイズの合計を表示します。

ftp1.js

var {WScript} = require("wsh");

var oShell = WScript.CreateObject("Shell.Application");
var oFolder = oShell.NameSpace(
                "ftp://user:password@sitename/directory/");
var objFolderItems = oFolder.Items();

WScript.Echo(GetFolderSize(oFolder) + "Byte");

function GetFolderSize(objFolder) {     //フォルダのサイズを得る
    var objFolderItems = objFolder.Items();
    var size = 0;
    for(var i = 0; i < objFolderItems.Count; i++) {
        var ofitem = objFolderItems.Item(i);
        if(ofitem.IsFolder)             //フォルダのとき
            size += GetFolderSize(ofitem.GetFolder);
        else                            //ファイルのとき
            size += ofitem.Size;
    }
    return size;
}

次は指定したディレクトリのa.txtというファイルをデスクトップにダウンロードします。

ftp2.js

var {WScript} = require("wsh");

var oShell = WScript.CreateObject("Shell.Application");
var oFolder = oShell.NameSpace(
                "ftp://user:password@sitename/directory/");
var objFolderItems = oFolder.Items();

var objFolderItems = oFolder.Items();

for(var i = 0; i < objFolderItems.Count; i++) {
    var ofitem = objFolderItems.Item(i);
    if(ofitem.Name == "a.txt") {
        oShell.NameSpace(0).CopyHere(ofitem);
        break;
    }
}

次はデスクトップのa.txtというファイルを指定したディレクトリにアップロードします。

ftp3.js

var {WScript} = require("wsh");

var oShell = WScript.CreateObject("Shell.Application");
var oFolder = oShell.NameSpace(
                "ftp://user:password@sitename/directory/");

var desktop = oShell.NameSpace(0);
var objFolderItems = desktop.Items();
for(var i = 0; i < objFolderItems.Count; i++) {
    var ofitem = objFolderItems.Item(i);
    if(ofitem.Name == "a.txt") {
        oFolder.CopyHere(ofitem);
        WScript.Sleep(6000);        //いくらか待つ必要あり
        break;
    }
}



Network

Network

WshNetwork オブジェクトはネットワーク上のリソースへのアクセスを可能にします。 WshNetwork オブジェクトは次のように得ます。

var ownet = WScript.CreateObject("WScript.Network");

ネットワークプリンタ

SetDefaultPrinter でデフォルトのネットワークプリンタを設定することができます。

defaultNP.js

var {WScript} = require("wsh");

var ownet = WScript.CreateObject("WScript.Network");
ownet.SetDefaultPrinter("\\\\nono\\Epson");

EnumPrinterConnections でネットワークプリンタの一覧を得ることができます。これは文字列のコレクションを返すのですが、これらは次の例で示すように、プリンタ名とネットワークパスのペアとなっています。

enumNP.js

var {WScript} = require("wsh");

var ownet = WScript.CreateObject("WScript.Network");
var oPrinters = ownet.EnumPrinterConnections();
for(var i = 0; i < oPrinters.length; i += 2)
    WScript.Echo(oPrinters.Item(i) + "\t" + oPrinters.Item(i+1));

RemovePrinterConnection でプリンタの接続を解除できます。

removeNP.js

var {WScript} = require("wsh");

var ownet = WScript.CreateObject("WScript.Network");
ownet.RemovePrinterConnection("\\\\nono\\Epson");

ネットワークドライブ

MapNetworkDrive でネットワークドライブに接続することができます。

ownet.MapNetworkDrive(DriveName, RemoteName,
                      bUpdateProfile, username, password);

bUpdateProfile は次にログインするときにも接続するかどうかです。

mapND.js

var {WScript} = require("wsh");

var ownet = WScript.CreateObject("WScript.Network");
ownet.MapNetworkDrive("G:", "\\\\nono\\nono-D", true, "aya");

EnumNetworkDrives でネットワークドライブの一覧を得ることができます。 EnumPrinterConnectionsと同様に、ドライブ名とネットワークパスのペアとなっています。

enumND.js

var {WScript} = require("wsh");

var ownet = WScript.CreateObject("WScript.Network");
var oDrives = ownet.EnumNetworkDrives();
for(var i = 0; i < oDrives.length; i += 2)
    WScript.Echo(oDrives.Item(i) + " " + oDrives.Item(i+1));

RemoveNetworkDrive でネットワークドライブの接続を解除できます。

ownet.MapNetworkDrive(DriveName, bForce, bUpdateProfile);

bForce はドライブを使用中でも強制的に解除するかどうかです。 bUpdateProfile は次にログインしたときにネットワークドライブを接続するかどうかです。true なら接続しません。デフォルトは false です。

removeND.js

var {WScript} = require("wsh");

var ownet = WScript.CreateObject("WScript.Network");
ownet.RemoveNetworkDrive("G:", true, true);

その他

WshNetwork オブジェクトには次の3つのプロパティがあります。

netprop.js

var {WScript} = require("wsh");

var ownet = WScript.CreateObject("WScript.Network");
WScript.Echo("ComputerName : " + ownet.ComputerName);
WScript.Echo("UserDomain   : " + ownet.UserDomain);
WScript.Echo("UserName     : " + ownet.UserName);

あと、AddWindowsPrinterConnection メソッドと AddPrinterConnection メソッドでプリンタの接続ができるらしいです。



ADO

ADO

AxtiveX Data Objects(ADO)はDAOよりフラットな構造に なっています。

    [Connection -] Recordset

以下、簡単に解説しますが、詳しいことは、

     Microsoft ActiveX Data Objects (ADO)
     ADO API Reference

をご覧ください。

基本的な例

基本的な使い方は、まず次のように Connection オブジェクトを得ます。

    var Conn = WScript.CreateObject("ADODB.Connection");

次に、データベースに接続します。

    Conn.Open(ConnectionString);

そして、SQL文やテーブル名を指定して Recordset オブジェクトを得ます。

    var rs = Conn.Execute(CommandText);

次に例を用意しました。
ここで使っているデータベースのソースは、 DAOのときと同じものです。
ここでは DSN を使っていないデータベースを扱っていますが、 DSN を使った例はそこら中にあるので適当に検索してください。

score.lzh(score.mdbをLHAで圧縮したもの 8kB)

score5.js

var {WScript} = require("wsh");

var Conn = WScript.CreateObject("ADODB.Connection");
Conn.Open("Driver={Microsoft Access Driver (*.mdb)};Dbq=score.mdb;");
var rs = Conn.Execute("SELECT Sum(算数) AS 総得点 FROM Score");
WScript.Echo(rs.Fields("総得点").Value);
rs.Close();

もっと簡単な例

実は、上に書いた構造にあるようにいきなり Recordsetオブジェクトを得ることができます。

    var rs = WScript.CreateObject("ADODB.Recordset");

そして、次のようにデータベースに接続してSQL文を発行してRecordsetを得ます。

    rs.Open(CommandText, ConnectionString);

引数は上と同じです。

score6.js

var {WScript} = require("wsh");

var rs = WScript.CreateObject("ADODB.Recordset");
rs.Open("SELECT Sum(算数) AS 総得点 FROM Score",
        "Driver={Microsoft Access Driver (*.mdb)};Dbq=score.mdb;");
WScript.Echo(rs.Fields("総得点").Value);
rs.Close();

他のデータベースの例

ExcelはDAOでも書いたようにテーブル名を指定するところが 特徴的です。

score7.js

var {WScript} = require("wsh");

var rs = WScript.CreateObject("ADODB.Recordset");
rs.Open("SELECT Sum(算数) AS 総得点 FROM [Score$]",
        "Driver={Microsoft Excel Driver (*.xls)};Dbq=score.xls;");
WScript.Echo(rs.Fields("総得点").Value);
rs.Close();

テキストファイルは、パスにディレクトリを、テーブル名にファイルを指定します。

score8.js

var {WScript} = require("wsh");

var rs = WScript.CreateObject("ADODB.Recordset");
rs.Open("SELECT Sum(算数) AS 総得点 FROM score2.csv",
        "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=.");
WScript.Echo(rs.Fields("総得点").Value);
rs.Close();

ソースのscore2.csvは次の通りです。

score2.csv

名前,性,国語,算数,理科,社会
さくら,女,75,71,8,66
知世,女,62,2,89,60
小狼,男,51,28,70,31
千春,女,68,61,46,12
奈緒子,女,89,55,69,24
利佳,女,79,30,79,81

タイプライブラリ

WScript.loadConsts関数を使えば、 ADOの定数を使うことができます。 次の例は、テキストのデータベースにレコードを追加します。 ここでは、adOpenKeyset, adLockOptimistic, adCmdTableを使っています。

addnew.js

var {WScript} = require("wsh");

var rs = WScript.CreateObject("ADODB.Recordset");
var ADC = WScript.loadConsts(rs);
rs.Open("score2.csv",
      "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=.",
      ADC.adOpenKeyset, ADC.adLockOptimistic, ADC.adCmdTable);
rs.AddNew();
rs.Fields("名前").Value = "エリオル";
rs.Fields("性").Value = "男";
rs.Fields("国語").Value = 10;
rs.Fields("算数").Value = 20;
rs.Fields("理科").Value = 30;
rs.Fields("社会").Value = 40;
rs.Update();
rs.Close();