WSH(JScript)でリパースポイント(ジャンクション、シンボリックリンク)のターゲットパスを得る
前提
- OS
- Vista以降
- C:\test内の構造
-
<DIR> dir 725 dir.lnk 0 file 466 file.lnk <JUNCTION> junction [c:\test\dir] <SYMLINKD> linkd [c:\test\dir] <SYMLINKD> linkdr [dir] <SYMLINK> linkf [c:\test\file] <SYMLINK> linkfr [file]
シンボリックリンクの参照先フルパスを取得
「WSH(・∀・)スレッド! Part 4」にあるとおりにプログラムを書いてcscriptで実行してみたところ、以下のようになりました。- test.js
-
var fso = new ActiveXObject("Scripting.FileSystemObject"); var e = new Enumerator( (new ActiveXObject("Shell.Application")) .nameSpace("c:\\test") .items() ); for (var f; !e.atEnd(); e.moveNext()) if (fso[fso.fileExists((f = e.item()).path) ? "getFile" : "getFolder"](f.path).attributes & 1024) WScript.echo([f.name, f.extendedProperty("linktarget")].join(" : "));
- cscriptでの実行結果
-
junction : linkd : C:\test\dir linkdr : C:\test\dir linkf : C:\test\file linkfr : C:\test\file
この方法はシンボリックリンクの参照先のフルパスが分かればよいという場合に使えます。なお、(ファイル|フォルダ)1つだけを調べるには以下のように書けます。
(new ActiveXObject("Shell.Application")).nameSpace("C:\\test").parseName("linkf").extendedProperty("linktarget") //C:\test\file
CMD.EXEのDIRコマンドを利用したリパースポイントの情報取得
junctionのターゲットパスとシンボリックリンクのターゲット相対パスを取得するために、CMD.EXEのDIRコマンドを利用することにします。WshShell.execを利用した場合は以下のようになりました。
- test3.js
-
WScript.echo( (new ActiveXObject("WScript.Shell")) .exec("cmd /c dir C:\\test") .stdout.readAll() .match(/\n\d{4}\/\d\d\/\d\d +\d\d:\d\d +<(?:JUNCTION|SYMLINKD?)> +junction \[(.+)\]\r/)[1] )
- cscriptでの実行結果
-
c:\test\dir
ウィンドウを隠すためにWshShell.runを使ったものが以下のtest4.jsになります。
- test4.js
-
(new ActiveXObject("WScript.Shell")).run("cmd /c dir C:\\test > C:\\test\\tmp.txt", 0, true); WScript.echo( (new ActiveXObject("Scripting.FileSystemObject")).openTextFile("C:\\test\\tmp.txt").readAll() .match(/\n\d{4}\/\d\d\/\d\d +\d\d:\d\d +<(?:JUNCTION|SYMLINKD?)> +linkdr \[(.+)\]\r/)[1] );
- cscriptでの実行結果
-
dir
この方法を使って簡単に取得するコードを書いたものが以下のtest5.jsになります。
- test5.js
-
var WshShell = new ActiveXObject("WScript.Shell"); var fso = new ActiveXObject("Scripting.FileSystemObject"); var objShell = new ActiveXObject("Shell.Application"); var tmpFilePath = WScript.scriptFullName.replace(/[^\\]+$/, "tmp.txt"); function escapeRegExp(str) { return str.replace(/([\\\^\$\*\+\?\.\{\}\(\)\[\]\|])/g, "\\$1"); } function map(collection, func) { for (var e = new Enumerator(collection), a = []; !e.atEnd(); e.moveNext()) a.push(func(e.item())); return a; } function getReparsePoints(dir, file) { dir = dir.replace(/\\+$/, ""); WshShell.run('cmd /u /c dir /a- "' + dir + '" > "' + tmpFilePath + '"', 0, true); var reg = new RegExp( "\\n\\d{4}\\/\\d\\d/\\d\\d +\\d\\d:\\d\\d +<(JUNCTION|SYMLINKD?)> +(" + (file ? escapeRegExp(file) : map(objShell.nameSpace(dir).items(), function (o) { return escapeRegExp(o.name);}).join("|")) + ") \\[(.+)\\]\\r", "ig"); var reparsePoints = {}; fso.openTextFile(tmpFilePath, 1, false, -1).readAll().replace(reg, function (s0, s1, s2, s3) { reparsePoints[s2] = { type : s1, path : dir + "\\" + s2, target : s3}; return s0; }); return reparsePoints; } var a = getReparsePoints("C:\\test"); for (var i in a) WScript.echo([a[i].path, a[i].type, a[i].target]);
- cscriptでの実行結果
-
C:\test\junction, JUNCTION, c:\test\dir C:\test\linkd, SYMLINKD, c:\test\dir C:\test\linkdr, SYMLINKD, dir C:\test\linkf, SYMLINK, c:\test\file C:\test\linkfr, SYMLINK, file