« 2006年11月 | トップページ | 2007年1月 »

2006年12月31日 (日)

HTAの表示/非表示と<hta:application>タグとの関係

<hta:application>タグがなければ、WindowState=0を指定して起動すれば、HTAを非表示にできます。

<hta:application>タグがあると、WindowState=0を指定して起動しても、HTAを非表示にできません。

しかし、<hta:application>タグを指定して、かつ、HTAを「非表示」風にすることはできます。

<html><head>
<script>
while(true){
  try{
    resizeTo(0,0);
    break;
  }catch(e){}
}
</script>
<hta:application border="none" showintaskbar="no"></hta:application>
</head></html>

または、

<html><head>
<script language="vbscript">
Sub Try()
  On Error Resume Next
  resizeTo 0,0
End Sub
Do
  Try
Loop While Err
</script>
<hta:application border="none" showintaskbar="no"></hta:application>
</head></html>

実際には縦横1ピクセルで表示されています。
Alt+TabでアクティブにしてAlt+F4で終了します。

2006年12月30日 (土)

コマンドラインでPDFファイルを印刷する。(Acrobat Reader 6.0)

Acrobat Reader 6.0には、印刷などのコマンドラインオプションがありますが、
その説明がありません。:-(

START ACRORD32.EXE オプション ファイル

オプション
/n  New Instance                新規プロセス
/o  ?                                 不明
/s  Supress Splash Window  起動ウィンドウ抑止
/h  Hide Window                  最小化ウィンドウ/印刷設定画面抑止
/p  Print                            デフォルトプリンタへ印刷
/t  PrintTo                         指定プリンタへ印刷 (6.0:プリンタ必須;7.0:プリンタ省略可)

使用例
START ACRORD32.EXE /p ファイル                       印刷設定画面表示
START ACRORD32.EXE /p /h ファイル                   印刷設定画面非表示
START ACRORD32.EXE /t "ファイル"                    印刷設定画面非表示 (7.0)
START ACRORD32.EXE /t "ファイル" "プリンタ名"  印刷設定画面非表示

いずれの場合も印刷後、アプリが残るので別途終了(CTRL+Q)が必要です。

新規でないとき、/tは、新規ウィンドウを開いて、印刷後消えます。

6.0では、新規でないとき、ファイル名がフルパスでないとエラーになります。

2006年12月29日 (金)

コマンドラインでHTMLファイルをテキストファイルにする。

html2text.CMD <HTMLファイル >テキストファイル

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0"
GOTO :EOF
@end
var htmlfile=new ActiveXObject('htmlfile');
htmlfile.write(WScript.StdIn.ReadAll());
WScript.Echo(htmlfile.body.innerText);

HTMLEncodeされたテキストをデコードするには、

HTMLDecode.CMD <HTML >テキスト

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0"
GOTO :EOF
@end
var htmlfile=new ActiveXObject('htmlfile');
htmlfile.write('<html><body></body></html>');
htmlfile.body.innerHTML=WScript.StdIn.ReadAll();
WScript.Echo(htmlfile.body.innerText);

2006年12月26日 (火)

HTA起動時にmoveTo/resizeToがエラーになるのを防止する。

HTA起動時に「エラー: アクセスが拒否されました。」のエラーになることがあります。
これはマウスダウンしていると発生するようです。

この対策は、エラーを捕捉してリトライループすることです。
つまり、起動時、マウスダウンしている間は、CPUループして待ち合わせます。
マウスを離すと、ループを抜けてHTAが表示されます。

<html><head>
<script>
while(true){
  try{
    resizeTo(300, 300);
    moveTo(100,100);
    break;
  }catch(e){}
}
</script>
<hta:application></hta:application>
</head><body></body></html>

この部分はJScriptで書いたほうが簡単ですが、VBScriptの例も。

<html><head>
<script language="vbscript">
Sub Try()
On Error Resume Next
resizeTo 300,300
moveTo 100,100
End Sub
Do
Try
Loop While Err
</script>
<hta:application></hta:application>
</head><body></body></html>

2006年12月25日 (月)

コマンドラインでテキストファイルをHTMLファイルにする。

Webサイトで、テキストファイルをそのままContent-Type: text/plainで公開すると、
IEで別の種類のファイルとして開かれる危険があるので止めましょう。
テキストファイルはHTMLファイルに変換して、Content-Type: text/htmlにしましょう。

以下のバッチファイルはコマンドラインで簡単にテキストファイルをHTMLファイルに変換します。

HTML変換.CMD <テキストファイル >HTMLファイル

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0"
GOTO :EOF
@end
var htmlfile=new ActiveXObject('htmlfile');
htmlfile.write('<html><body></body></html>');
htmlfile.body.innerText=WScript.StdIn.ReadAll();
WScript.Echo(htmlfile.documentElement.outerHTML);

最終行を以下に変えると、HTML中に記述するテキストをHTMLEncodeするのに使えます。
WScript.Echo(htmlfile.body.innerHTML);

2006年12月21日 (木)

VBSファイルでタイプライブラリの定数を参照する。

WSFでは、<reference>要素や<object>要素のreference="yes"属性(隠し)で、
定数が参照できるようになりますが、VBSやJSでは、この機能が使えません。
そこで、VBSファイルでも、定数が参照できないものか、試してみました。
一応、これで取れます。

For Each Constants In CreateObject("TLI.TLIApplication").InterfaceInfoFromObject(CreateObject("Scripting.FileSystemObject")).Parent.Constants
  For Each Member In Constants.Members
    On Error Resume Next
    Execute "Const " & Member.NAME & "=" & Member.VALUE
    On Error GoTo 0
  Next
Next

WScript.Echo ForReading

でも、上のExecuteをWScript.Echoに変えてファイルに出力し、
必要な定数宣言だけを貼り付けたほうが、早いし、速いような。

2006年12月20日 (水)

バッチファイルの実行を逐次化する。

2番手はsleep.exeで待ち合わせしてリトライします。

Serial.CMD

:top
(
notepad.exe
goto :eof
) 0>>%0
sleep.exe 10
goto top

sleep.exeは、もしなければ、以下から入手できます。

Windows 98 Resource Kit

Windows Server 2003 Resource Kit Tools

2006年12月19日 (火)

コマンドラインでUTF-8、EUC、JIS、Unicodeなどのテキストファイルを表示する。

Unicode Little Endianは、TYPE、MORE、FINDコマンドで読めます。

その他のUTF-8、EUC、JIS、Unicode Big Endianなどは、以下で読めます。
このとき、拡張子は.txtにしてください。

タイプ.CMD テキストファイル.TXT

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0" "%~f1"
GOTO :EOF
@end
var htmlfile=WScript.GetObject(WScript.Arguments.Item(0),'htmlfile');
while(htmlfile.readyState!='complete') WScript.Sleep(100);
WScript.Echo(htmlfile.body.innerText);

末行を以下に変えると、Unicodeで出力します。
new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1,true).Write(htmlfile.body.innerText);
コンソールへはUnicodeでも表示可能です。

2006年12月11日 (月)

画像やテキストファイルなど、HTML以外のファイルをIEで開くのは危険です!

IEは、HTMLでなくても、画像やテキストファイルなどを直接指定して、表示できます。
これはこれで便利なのですが。。。
もし、それが拡張子なしや不明な拡張子の場合、それはとっても危険な行為です。
ダウンロードしたファイルの場合は、なおさらです。
画像ファイルだと思ってダウンロードしても、拡張子がなかったり、
画像の拡張子でなかったら、決してIEで開いてはなりません。

試しに、以下のテキストを拡張子なしのファイルに保存し、

<html><script>alert('!');</script></html>

そのファイルをIEの画面にドロップしてみてください。
テキストが表示されたら、更新ボタンを押してみてください。
IEはファイルをHTMLと思って、スクリプトを実行しようとします。

画像ファイルでも同じです。もし、画像ファイルにHTMLが埋め込まれていると、
最初は画像が表示されても、更新ボタンを押すと、
IEは画像ファイルをHTMLと思って、スクリプトを実行しようとします。

2006年12月10日 (日)

「信頼済みサイトゾーン」の設定は危険です!

一般にクロスサイトスクリプティングを許す設定になっています。

「信頼済みサイトゾーン」や「イントラネットゾーン」の設定は、
一般に「中」以下にすることが普通ですが、
「中」以下の設定では「拡張子ではなく、内容によってファイルを開くこと」を
「有効にする」ため、クロスサイトスクリプティングを許容します。

一般に、「怪しいURLをクリックすると危険です。避けましょう。」と言われていますが、
実際には、「信頼済みサイト」や「イントラネット」のURLをクリックすることも危険なのです。

2006年12月 9日 (土)

「拡張子ではなく、内容によってファイルを開くこと」は『クロスサイトスクリプティングを許すこと』と同じ。

[参考URL] http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-3312

と言っても、どういうふうに危険なのか、分りました?

例えば、
「これは、MVP紹介ページの写真です。」
というリンクがあって、これをクリックすると、画像ファイルが読み込まれます。
この場合は、問題ありませんが、
一般には、こういう安全そうなURLをクリックすることが危険なのです。

このような場合に、セキュリティレベル「中」以下の設定では、
画像ファイルをその中身でHTMLと判断することがあり、
その場合は、スクリプトがそのセキュリティゾーンで動きます。こわー。

もし、そのサイトが信頼済みサイトに登録されていれば、信頼済みサイトゾーンで動きます。

信頼済みサイトゾーンのデフォルトのセキュリティレベルは「低」なので、
もし、デフォルトで使っていれば、スクリプトは自由自在、何でも出来ます。オー、こわー。

この例では、画像として表示されるので問題ありませんが、
この画像ファイルを保存してメモ帳で開いて見ると、中にHTMLが入っています。
拡張子をHTMLに変えると、動きます。

この画像ファイルの場合は、IEによってHTMLと判定されることはありませんが、
一般に、画像ファイルに、HTMLを組み込んで、IEによってHTMLと判定されるようにできます。
その場合も、画像ファイルとしては正しいので、サイト側でチェックするのは、困難です。
世間的に見ると、正しい画像ファイルをHTMLと判定するIEの側に「障害」があるのですが、
MSは昔から一貫してこれを「仕様」と主張しているので、修正は全く望めません。
なので、現状、ユーザの自己防衛以外に、身を守る手立てはありません。

2006年12月 4日 (月)

On Error Resume Nextの正しい使い方

よく、On Error Resume Nextを先頭に置いたスクリプトを見かけますが、
まるで、Option Explicitをスクリプトの先頭に置くような感覚で、
「適当にエラーをリカバるオプション」のような誤解があるのではないでしょうか。

On Error Resume Nextの意味は、言わば、
「エラーがあっても無視して、どうなってもいいから暴走しろ」ですから、
そんな、自暴自棄に走らなくても、と思ってしまいます。

では、どう書くのが清く、正しく、安全か、というと、

例えば、リネーム、
Set fo=fso.GetFile(filename)
fo.Name=newName
は、同じ名前があるとエラーになります。

そこで、まず、
Set fo=fso.GetFile(filename)
Sub Rename(fo,newName)
  On Error Resume Next
  fo.Name=newName
End Sub
Call Rename(fo,newName)
If Err<>0 Then
  WScript.Echo Err.Number & " : " & Err.Description
  WScript.Quit
End If
と変えて、Err.Numberを調べます。すると、58と分かります。

最終的に、
Set fo=fso.GetFile(filename)
Sub Rename(fo,newName)
  On Error Resume Next
  fo.Name=newName
End Sub
Call Rename(fo,newName)
If Err=58 Then
  ' 同名ファイルがあったときの処理
ElseIf Err<>0 Then
  WScript.Echo Err.Number & " : " & Err.Description
  WScript.Quit
  ' または Err.Raise Err.Number でも可。
End If
のようにします。

ポイントは、
エラーの想定される行だけに局限する。
想定されるエラーだけに局限する。

WSH2.0でOn Error GoTo 0が追加されましたが、要らんことです。

例えば、
Set fo=fso.GetFile(filename)
On Error Resume Next
fo.Name=newName
On Error GoTo 0
If Err<>0 Then
とすると、Err.Numberが分からなくなります。

また、
Set fo=fso.GetFile(filename)
On Error Resume Next
fo.Name=newName
'++++++++++++++++++++
If Err=58 Then
  ' 同名ファイルがあったときの処理
ElseIf Err<>0 Then
  WScript.Echo Err.Number & " : " & Err.Description
  WScript.Quit
End If
'++++++++++++++++++++
On Error GoTo 0
とすると、この区間でエラーを起こしても無視して暴走です。

どちらももうひとつです。

因みに、JScriptのtry catch風をVBScriptでお望みの場合、

Sub Try()
'
' ここにtryのコード
'
End Sub
Sub Catch()
On Error Resume Next
Call Try()
End Sub
Call Catch()
If Err<>0 Then
'
' ここにcatchのコード
'
End If

で、似たようなことが出来ます。
これでErr.NumberやErr.Descriptionは分かりますが、
一番知りたい、エラーを起こしたソース行番号が分かりません。

で、やっぱり、お勧めは最初に述べた通りです。

2006年12月 3日 (日)

すべてのゾーン/すべてのレベルで「拡張子ではなく、内容によってファイルを開くこと」を「無効にする」べし。

インターネット 高
イントラネット 高
信頼済みサイト 中
にしていれば安全かと思っていましたが、それだけではとんでもなく危険なそうです。

URLをクリックすると、信頼済みサイトに置かれたユーザ作成物(テキストや画像など)に
仕掛けられたスクリプトが信頼済みサイトゾーンで動くそうです。

セキュリティレベルが「中」以下のセキュリティゾーンは、「レベルのカスタマイズ」で、
適切なレベルに「カスタム設定のリセット」して、さらに、
「拡張子ではなく、内容によってファイルを開くこと」を「無効にする」べし。

それより、レベル、中、中低、低の
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\TemplatePolicies\Medium]
;"DisplayName"="安全性 - 中 (安全)"
"2100"=dword:00000000

"2100"=dword:00000003
に変えておいたほうが楽かも。

VBScript/JScriptの正規表現で改行を含む任意の文字は?

改行を含まない任意の文字は、「.」ですが、
改行を含む任意の文字には、[\s\S]が使えます。
VBScript/JScriptのヘルプには、[.\n]が使えるように書いてありますが、実際には使えません。

set re=new regexp
re.multiline=true

re.pattern="[.\n]+"
set matches=re.execute("a" & vbcrlf & "b")
msgbox """" & matches(0).value & """",,"NG"

re.pattern="[\s\S]+"
set matches=re.execute("a" & vbcrlf & "b")
msgbox """" & matches(0).value & """",,"OK"


最近のドキュメントは、[\s\S]に修正してあるようです。

テキストファイルから正規表現でテキストを切り出す。

例えば、切り出し.CMD /開始[\s\S]*?終了/g <標準入力

切り出し.CMD 正規表現 <標準入力

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0" %1
GOTO :EOF
@end
var matches=WScript.StdIn.ReadAll().match(eval(WScript.Arguments.Item(0)));
if(matches) WScript.Echo(matches.join('\r\n'));

2006年12月 2日 (土)

コマンドラインでフォルダサイズ(フォルダ配下のファイルサイズ総合計)を表示する。

フォルダサイズ.CMD フォルダ...

ワイルドカード可。

@if(0)==(0) ECHO OFF
FOR /D %%0 IN (%*) DO FOR /F %%1 IN ('CScript.exe //NoLogo //E:JScript "%~f0" "%%~f0"') DO ECHO %%1 %%0
GOTO :EOF
@end
WScript.Echo(new ActiveXObject('Scripting.FileSystemObject').GetFolder(WScript.Arguments.Item(0)).Size);

« 2006年11月 | トップページ | 2007年1月 »