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

2007年12月29日 (土)

Windows 2000 Support Toolsのtlist.exeとkill.exeのダウンロード元

Windows XP Home Editionには、TaskList.exeやTaskKill.exeがありません。

その代替となるのが、Windows 2000 Support Toolsのtlist.exeとkill.exeです。

これらは以下に含まれています。

Debugging Tools for Windows 32 ビット バージョンのインストール

また、TaskKill.exeは、XP Home Editionにもあるtskill.exeで代替することもできます。

2007年12月28日 (金)

PowerShellの1行バッチでコマンドラインからファイルを関連付けで印刷する。

PowerShellの1行バッチを使えば、コマンドラインからファイルを関連付けで印刷することができます。

ShellPrint.CMD ファイル

PowerShell.exe -command "$shell=new-object -com shell.application;$shell.shellexecute('%~f1',$null,$null,'print');"

バッチファイルからCOMオブジェクトや.NET、Win32APIを呼び出すコマンド

何それ?って、PowerShell.exeの1行スクリプト、インラインスクリプトのことです。:-p

こんなに強力で便利なコマンドを使わない手はありません。MS純正で、しかも無料なのだから。

2007年12月27日 (木)

コマンドラインからPowerShellの1行バッチでExcelオブジェクトを操作する。

Excelファイルを開くバッチファイルの例。

ExcelOpen.CMD Excelファイル

PowerShell.exe -command "$sc=new-object -com scriptcontrol;$sc.language='vbscript';$sc.timeout=-1;$sc.addcode('Set App=CreateObject('+[char]34+'Excel.Application'+[char]34+'):App.Visible=True:App.UserControl=True:App.AutomationSecurity=2:Set Book=App.WorkBooks.Open('+[char]34+'%~f1'+[char]34+'):');"

このように、PowerShellの1行バッチを使えば、別個のスクリプトファイルを作らずとも、バッチファイルだけで、オブジェクトが操作できます。:-)

2007年12月26日 (水)

PowerShellからExcelオブジェクトを使う。

PowerShellからExcelオブジェクトを普通に使うことができません!:-(

$App=new-object -com Excel.Application;
$App.WorkBooks.Open("Excelファイルのフルパス");

"1" 個の引数を指定して "Open" を呼び出し中に例外が発生しました: "ライブラリの形式が古いか、または種類が無効です。 (HRESULT からの例外: 0x80028018 (TYPE_E_INVDATAREAD))"

PowerShellとExcelの間にScriptControlを挟めば、一応、使えますが、そこまでして使う意味があるかどうか。。。

$sc=new-object -com scriptcontrol;
$sc.language='vbscript';
$sc.timeout=-1;
$sc.addcode(@'
Set App=CreateObject("Excel.Application")
App.Visible=True
App.UserControl=True
App.AutomationSecurity=2
Set Book=App.WorkBooks.Open("Excelファイルのフルパス")
'@)

2007年12月25日 (火)

PowerShellの1行バッチでコンソールウィンドウを最小化/最大化/元に戻す。

コンソールウィンドウを最小化します。

PowerShell.exeの1行バッチを使えば、バッチファイルからそのコンソールウィンドウを最小化/最大化/元に戻すことができます。

以下は長いけれど1行です。

PowerShell.exe -command "$title=$Host.UI.RawUI.WindowTitle;$Host.UI.RawUI.WindowTitle+=(new-object random).next();$process=(ps|where {$_.MainWindowTitle -eq $Host.UI.RawUI.WindowTitle});$Host.UI.RawUI.WindowTitle=$title;$hwnd=$process.MainWindowHandle;[void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms');$message=[System.Windows.Forms.Message]::Create($hwnd,274,61472,0);$nativeWindow=new-object System.Windows.Forms.NativeWindow;$nativeWindow.DefWndProc([ref]$message);$nativeWindow=$null;"

コンソールウィンドウを最大化します。

PowerShell.exe -command "$title=$Host.UI.RawUI.WindowTitle;$Host.UI.RawUI.WindowTitle+=(new-object random).next();$process=(ps|where {$_.MainWindowTitle -eq $Host.UI.RawUI.WindowTitle});$Host.UI.RawUI.WindowTitle=$title;$hwnd=$process.MainWindowHandle;[void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms');$message=[System.Windows.Forms.Message]::Create($hwnd,274,61488,0);$nativeWindow=new-object System.Windows.Forms.NativeWindow;$nativeWindow.DefWndProc([ref]$message);$nativeWindow=$null;"

コンソールウィンドウを元に戻します。

PowerShell.exe -command "$title=$Host.UI.RawUI.WindowTitle;$Host.UI.RawUI.WindowTitle+=(new-object random).next();$process=(ps|where {$_.MainWindowTitle -eq $Host.UI.RawUI.WindowTitle});$Host.UI.RawUI.WindowTitle=$title;$hwnd=$process.MainWindowHandle;[void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms');$message=[System.Windows.Forms.Message]::Create($hwnd,274,61728,0);$nativeWindow=new-object System.Windows.Forms.NativeWindow;$nativeWindow.DefWndProc([ref]$message);$nativeWindow=$null;"

2007年12月24日 (月)

コマンドラインからタスクスケジューラのタスクを終了する。

これをタスクスケジューラに登録すれば、指定時刻に他のタスクを終了することができます。

TaskEnd.CMD [タスク名|番号]

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0" %*
GOTO :EOF
@end
var Shell=new ActiveXObject("Shell.Application");
var Folder=Shell.NameSpace("::{d6277990-4c6a-11cf-8d87-00aa0060f5bf}");
if(WScript.Arguments.Count()){
  for(var j=0;j<Folder.Items().Count;j++){
    var FolderItem=Folder.Items().Item(j);
    if(FolderItem.Name==WScript.Arguments.Item(0)){
      FolderItem.InvokeVerb("タスクの終了(&E)");
      WScript.Quit();
    }
  }
  if(!isNaN(WScript.Arguments.Item(0))){
    var j=parseInt(WScript.Arguments.Item(0));
    if(0<j&&j<Folder.Items().Count){
      var FolderItem=Folder.Items().Item(j);
      FolderItem.InvokeVerb("タスクの終了(&E)");
      WScript.Quit();
    }
  }
  WScript.Echo(WScript.Arguments.Item(0),"Not Found.");
}else{
  var Cols=new Array();
  Cols[0]="#";
  for(var k=0;k<7;k++){
    Cols[k+1]=Folder.GetDetailsOf(null,k);
  }
  var Rows=new Array();
  Rows.push(Cols.join('\t'));
  for(var j=0;j<Folder.Items().Count;j++){
    var FolderItem=Folder.Items().Item(j);
    Cols[0]=j;
    for(var k=0;k<7;k++){
      Cols[k+1]=Folder.GetDetailsOf(FolderItem,k);
    }
    Rows.push(Cols.join('\t'));
  }
  WScript.Echo(Rows.join('\n'));
}

2007年12月23日 (日)

コマンドラインからタスクスケジューラのタスクを実行する。

TaskRun.CMD [タスク名|番号]

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0" %*
GOTO :EOF
@end
var Shell=new ActiveXObject("Shell.Application");
var Folder=Shell.NameSpace("::{d6277990-4c6a-11cf-8d87-00aa0060f5bf}");
if(WScript.Arguments.Count()){
  for(var j=0;j<Folder.Items().Count;j++){
    var FolderItem=Folder.Items().Item(j);
    if(FolderItem.Name==WScript.Arguments.Item(0)){
      FolderItem.InvokeVerb("タスクの実行(&U)");
      WScript.Quit();
    }
  }
  if(!isNaN(WScript.Arguments.Item(0))){
    var j=parseInt(WScript.Arguments.Item(0));
    if(0<j&&j<Folder.Items().Count){
      var FolderItem=Folder.Items().Item(j);
      FolderItem.InvokeVerb("タスクの実行(&U)");
      WScript.Quit();
    }
  }
  WScript.Echo(WScript.Arguments.Item(0),"Not Found.");
}else{
  var Cols=new Array();
  Cols[0]="#";
  for(var k=0;k<7;k++){
    Cols[k+1]=Folder.GetDetailsOf(null,k);
  }
  var Rows=new Array();
  Rows.push(Cols.join('\t'));
  for(var j=0;j<Folder.Items().Count;j++){
    var FolderItem=Folder.Items().Item(j);
    Cols[0]=j;
    for(var k=0;k<7;k++){
      Cols[k+1]=Folder.GetDetailsOf(FolderItem,k);
    }
    Rows.push(Cols.join('\t'));
  }
  WScript.Echo(Rows.join('\n'));
}

2007年12月22日 (土)

PDFファイルをページを指定して印刷する。(その2)

Adobe ReaderのCOMを使うと、どうもうまく行かないので、印刷ダイアログをSendKeysで操作します。

wShell.SendKeys "%g{tab}1-3,5{enter}"の要領でページを指定します。

Option Explicit
Dim File
Dim ie
Dim wShell

File="PDFファイルのフルパス"
Set wShell=CreateObject("WScript.Shell")
Set ie=CreateObject("InternetExplorer.Application")
ie.Visible=True
ie.Navigate File
Do While ie.Busy Or ie.ReadyState<>4
  WScript.Sleep 100
Loop
ie.Document.GetVersions
ie.ExecWB 6,0
Do While Not wShell.AppActivate("印刷")
  WScript.Sleep 100
Loop
wShell.SendKeys "%g{tab}1-3,5{enter}"
Do While Not wShell.AppActivate("進行状況")
  WScript.Sleep 100
Loop
Do While wShell.AppActivate("進行状況")
  WScript.Sleep 100
Loop
ie.Quit

2007年12月21日 (金)

PDFファイルをページを指定して印刷する。

Adobe ReaderのDDEには、そういう機能がないので、AcroPDF.dllを利用します。
しかし、そのまま、CreateObject("AcroPDF.PDF")しても、使えないので、IEに貼り付けて利用します。

printPages(印刷開始ページ, 印刷終了ページ)の要領で指定します。

Option Explicit
Dim File
Dim ie

File="PDFファイルのフルパス"
Set ie=CreateObject("InternetExplorer.Application")
ie.Visible=True
ie.Navigate File
Do While ie.Busy Or ie.ReadyState<>4
  WScript.Sleep 100
Loop
Call ie.Document.PrintPages(1,3)
Call ie.Document.PrintPages(5,5)

COMからの印刷は、非同期に行われます。
IEを先に終了すると印刷されないので、IEを残します。
また、COMから印刷すると、Adobe Readerが残ります。
はたまた、警告ダイアログも出ます。

このやり方で印刷終了を待ち合わせるのは無理です。諦めました。:-(
なので、お勧めしません。

2007年12月20日 (木)

「Web ページ、完全」をひとつのフォルダにまとめて管理する。

~.htm を ~.files フォルダの中に default.htm として入れます。
~.htm 内のリンクも「~.files」を含まない相対パスに書き換えます。

MakeDefaultPage.VBS ~.htm

Option Explicit
Dim Path
Dim fso
Dim BaseName
Dim Stream
Dim Text
Dim re
Dim Matches
Dim charset
Path=WScript.Arguments.Item(0)
Set fso=CreateObject("Scripting.FileSystemObject")
BaseName=fso.GetBaseName(Path)
Const adTypeText=2
Set Stream=CreateObject("ADODB.Stream")
Stream.Open
Stream.Type=adTypeText
Stream.Charset="iso-8859-1"
Stream.LoadFromFile Path
Text=Stream.ReadText(-1)
Set re=new RegExp
re.IgnoreCase=True
re.Pattern="<META\s+[^>]*charset\s*=\s*([-A-Za-z0-9_]+)"
re.Global=False
Set Matches=re.Execute(Text)
If Matches.Count Then charset=Matches.Item(0).SubMatches.Item(0)
Stream.Position=0
If charset<>"" Then Stream.Charset=charset
Text=Stream.ReadText(-1)
re.Pattern="src=""" & BaseName & ".files/"
re.Global=True
Text=re.Replace(Text,"src=""")
Stream.Position=0
Stream.WriteText Text
Stream.SaveToFile fso.GetParentFolderName(Path) & "\" & BaseName & ".files\default.htm"
Stream.Close
Set Stream=Nothing

処理後、default.htm が問題なく表示されれば、元の ~.htm を削除します。
再度処理するときは、先に default.htm を削除します。

OpenDefaultPage.VBS フォルダ

SendTo フォルダに置くか、htmfile に関連付けます。

CreateObject("WScript.Shell").Run """" & WScript.Arguments.Item(0) & "\default.htm"""

フォルダを右クリックや「送る」で default.htm を開きます。

「Web ページ、完全」で保存すると、ファイル名が変更できない。

「Web ページ、完全」で保存すると、~.htm と ~.files フォルダが出来ます。
両者が分かれて存在するのは、トラブルの元です。

「フォルダオプション」-「表示」
□ ファイル及びフォルダ
 □ Web ページとフォルダを対で管理します。

  ○ 対になった部分を 1 つのファイルとして表示し、管理も 1 つのファイルとして行います。
  ○ 対になった部分を両方とも表示し、管理は 1 つのファイルとして行います。
になっている場合、リネームしようとすると、警告ダイアログが出ます。

これは、~.htm から ~.files フォルダへのリンクがあり、リネームすると、リンクが無効になるからですね。

もし、
  ◎ 対になった部分を両方とも表示しますが、管理は別々に行います。
にすれば、~.htm はリネームできるようになります。
しかし、~.files をリネームする場合は、同時に、~.htm 内のリンクを書き換える必要があります。

そこで、「Web ページ、完全」をひとつのフォルダにまとめて管理しましょう。

まず、トラブルの元の「対の管理」は切ってしまいます。

次に、MakeDefaultPage.VBS を使用して、
~.htm を ~.files フォルダの中に default.htm として入れます。
~.htm 内のリンクも「~.files」を含まない相対パスに書き換えます。
これで、~.files を自由にリネームできます。

その後は、OpenDefaultPage.VBS を使用して、
フォルダを右クリックや「送る」で default.htm を開きます。

MakeDefaultPage.VBS と OpenDefaultPage.VBS は別途。

2007年12月19日 (水)

Cookieを削除する。

Cookie削除の警告ダイアログを出さずに、Cookieだけを削除する方法はどうもなさそうです。:-(
Cookiesフォルダ側の実体だけを消しても、Cacheフォルダ側の情報が消えないし。

なので、WSFで、Cookie削除の警告ダイアログに自動応答します。

以下は、キャッシュファイルとCookieの両方を削除します。

<package>
<job id=main>
<script language=vbscript>
Option Explicit
Dim wShell
Dim oExec
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("WScript.exe //job:sub """ & WScript.ScriptFullName & """")
Do While oExec.Status=0
  If wShell.AppActivate("警告") Then wShell.SendKeys "%y"
  WScript.Sleep 1000
Loop
</script>
</job>
<job id=sub>
<script language=vbscript>
CreateObject("Shell.Application").NameSpace(32).Items().InvokeVerbEx("delete")
</script>
</job>
</package>

以下は、Cookieだけを削除します。

<package>
<job id=main>
<script language=vbscript>
Option Explicit
Dim wShell
Dim oExec
Set wShell=CreateObject("WScript.Shell")
Set oExec=wShell.Exec("WScript.exe //job:sub """ & WScript.ScriptFullName & """")
Do While oExec.Status=0
  If wShell.AppActivate("警告") Then wShell.SendKeys "%y"
  WScript.Sleep 100
Loop
</script>
</job>
<job id=sub>
<script language=vbscript>
Option Explicit
Dim Folder
Dim FolderItem
Set Folder=CreateObject("Shell.Application").NameSpace(32)
For Each FolderItem In Folder.Items()
  If Left(Folder.GetDetailsOf(FolderItem,1),7)="Cookie:" Then FolderItem.InvokeVerb("delete")
Next
</script>
</job>
</package>

2007年12月18日 (火)

エクスプローラから起動されたバッチファイルでPAUSEする。(その2)

前記事は、バッチファイル実行後にコンソールを使う。

新作は前作と違って1行です。遅延展開を使うところが味噌です。

以下の1行をバッチファイルの最後に入れます。

@SETLOCAL ENABLEDELAYEDEXPANSION & SET CMDCMDLINE=!CMDCMDLINE! & (IF "cmd /c """=="!CMDCMDLINE:~0,9!" PAUSE) & SET CMDCMDLINE=

2007年12月17日 (月)

コマンドでディレクトリ自身の情報を表示する。

dir ディレクトリは、ディレクトリの内容を表示します。
unix の ls -d のようなディレクトリ自身の情報を表示するコマンドやオプションがありません。:-(
そこで、バッチファイル、

dir1.cmd ディレクトリなど...(ファイルにはワイルドカードも使えます)

@for %%1 in (%*) do @if exist %%1 echo %%~atznx1

doskeyマクロの場合、

doskey dir1=for %1 in ($*) do @if exist %1 echo %~atznx1

2007年12月16日 (日)

CScript.exeからコンソールアプリを同じコンソールウィンドウで実行する。

CScript.exeからWScript.ShellのRun()でコンソールアプリを起こすと、別のコンソールウィンドウが開いて実行されます。
しかも、コンソールアプリが終了すると、別のコンソールウィンドウも閉じてしまうではありませんか!
なんで、わざわざ、別のコンソールウィンドウを開くんでしょうね。全く。。。

一方、Exec()は別のコンソールウィンドウを開きません。:-)
ところが、標準入出力がリダイレクトされていて、コンソールアプリからコンソールウィンドウに入出力できないやおまへんか。わちゃーでんな。何とかならんの?

そこで、コンソールアプリを同じコンソールウィンドウで実行します。
しかも、コンソールアプリからコンソールウィンドウに入出力します。

以下のサンプルは、代表的なコンソールアプリであるcmd.exeをCScript.exeから同じコンソールウィンドウで実行します。

CScript.exe ExecRun.VBS

Sub ExecRun(Command)
Dim wShell
Dim oExec
Set wShell=CreateObject("WScript.Shell")
WScript.Echo wShell.CurrentDirectory & ">" & Command
Set oExec=wShell.exec("cmd.exe /c <con 2>&1 " & Command)
Do While Not oExec.StdOut.AtEndOfStream
  WScript.StdOut.Write oExec.StdOut.Read(1)
Loop
Do While oExec.Status=0
  WScript.Sleep 100
Loop
WScript.Echo "リターンコード (ERRORLEVEL) :",oExec.ExitCode
End Sub

ExecRun "cmd.exe"

これでコマンドプロンプトからcmd.exeを実行したときと同じように使えます!?

2007年12月14日 (金)

インターネット一時ファイルを削除する。

キャッシュファイルとCookieの両方を削除するには、1行

CreateObject("Shell.Application").NameSpace(32).Items().InvokeVerbEx("delete")

ですが、Cookie削除前に警告ダイアログが出ます。

キャッシュファイルだけを削除するには、4行

Set Folder=CreateObject("Shell.Application").NameSpace(32)
For Each FolderItem In Folder.Items()
  If Left(Folder.GetDetailsOf(FolderItem,1),7)<>"Cookie:" Then FolderItem.InvokeVerb("delete")
Next

で、警告ダイアログは出ません。

Cookie削除の警告ダイアログを出さずに、Cookieだけを削除する方法はどうもなさそうです。:-(
Cookiesフォルダ側の実体だけを消しても、Cacheフォルダ側の情報が消えないし。

2007年12月13日 (木)

ごみ箱を空にする。(XP)

Shell.Applicationを使えば、一行で出来るものの、削除の確認ダイアログが出ます。

CreateObject("Shell.Application").NameSpace(10).Self.InvokeVerb "ごみ箱を空にする(&B)"

※ XPまでは、InvokeVerb "ごみ箱を空にする(&B)"は同期です。

FileSystemObjectを使えば、ダイアログなしに、ごみ箱を空に出来ます。ただし、その場合は、デスクトップのゴミ箱のアイコンが空に変わりません。:-(
そこで、ファイルをひとつ、空になったゴミ箱に送って、元に戻せば、デスクトップのゴミ箱のアイコンが空に変わります。

ごみ箱を空にする.VBS

Set fso=CreateObject("Scripting.FileSystemObject")
Set Shell=CreateObject("Shell.Application")
Set Folder=Shell.NameSpace(10)
For Each FolderItem In Folder.Items()
  If fso.FileExists(FolderItem.Path) Then
    fso.DeleteFile FolderItem.Path,True
  ElseIf fso.FolderExists(FolderItem.Path) Then
    fso.DeleteFolder FolderItem.Path,True
  End If
Next
If Folder.Items().Count=0 Then
  Set sFolder=Shell.NameSpace(fso.GetParentFolderName(WScript.ScriptFullName))
  Folder.MoveHere sFolder.Items().Item(WScript.ScriptName)
  Do While Not sFolder.Items().Item(WScript.ScriptName) Is Nothing
    WScript.Sleep 100
  Loop
  sFolder.MoveHere Folder.Items().Item(0)
End If

2007年12月12日 (水)

PowerShellでファイルやフォルダをごみ箱に捨てる。(XP)

XPまでは、ごみ箱へのCopyHere()は、非同期なので、元がなくなるのを待ち合わせます。

remove.ps1 files...

$Shell=new-object -com shell.application;
$Folder=$Shell.NameSpace(10);
foreach($arg in $args){
  $FileName=[System.IO.Path]::GetFileName($arg);
  $sFolder=$Shell.NameSpace([System.IO.Path]::GetFullPath($arg+"\.."));
  if(-not $sFolder){
    write-output ("Folder Not Found. - " + $arg);
    break;
  }
  $sFolderItem=$sFolder.ParseName($FileName);
  if($sFolderItem){
    $Folder.CopyHere($sFolderItem);
    while($sFolder.ParseName($FileName)){Start-sleep -milliseconds 1000;}
  }else{
    write-output ("File Not Found. - " + $arg);
    break;
  }
}

2007年12月11日 (火)

ファイル名をエクスプローラと同じ順序にソートする。(その2)

XPより前、2000のエクスプローラの並び順にするときは、エクスプローラでなく、Shell.Applicationを使います。

先のものがそれぞれ以下のようになります。以下、CScript.exeで実行のこと。

FolderName="フルパス"
Set Shell=CreateObject("Shell.Application")
Set Folder=Shell.NameSpace(FolderName)
For Each FolderItem In Folder.Items()
  WScript.Echo FolderItem.Name
Next

FolderName="フルパス"
Set fso=CreateObject("Scripting.FileSystemObject")
Set Shell=CreateObject("Shell.Application")
Set Folder=Shell.NameSpace(FolderName)
For Each FolderItem In Folder.Items()
  If FolderItem.Type<>"ファイル フォルダ" Then
    WScript.Echo fso.GetFileName(FolderItem.Path)
  End if
Next

FolderName="フルパス"
Set fso=CreateObject("Scripting.FileSystemObject")
Set Shell=CreateObject("Shell.Application")
Set Folder=Shell.NameSpace(FolderName)
For Each FolderItem In Folder.Items()
  If FolderItem.Type="ファイル フォルダ" Then
  ElseIf LCase(fso.GetExtensionName(FolderItem.Path))="txt" Then
    WScript.Echo fso.GetFileName(FolderItem.Path)
  End If
Next

ファイル名をエクスプローラと同じ順序にソートする。

エクスプローラと同じ順序にソートするにはどうするか?
一般的には、Win32APIのStrCmpLogicalWを使えばよいようです。
しかし、スクリプトではどうするか?
エクスプローラと同じ順序にソートするんだったら、エクスプローラを使えばいいじゃん。
ということで、以下、CScript.exeで実行のこと。

FolderName="フルパス"
Set ie=GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
ie.Navigate FolderName
Do While ie.Busy Or ie.ReadyState<>4
  WScript.Sleep 100
Loop
Set Folder=ie.Document.Folder
For Each FolderItem In Folder.Items()
  WScript.Echo FolderItem.Name
Next
ie.Quit

ただし、FolderItem.Nameは使わないほうがよいので、fso.GetFileName(FolderItem.Path)を使います。
※ FolderItem.Nameは、.lnkなど拡張子が表示されない。

また、フォルダを除いて、ファイルだけを取り出すには、FolderItem.IsFolderは使わないほうがよいので、FolderItem.Typeで絞り込みます。
※ FolderItem.IsFolderは、.zipなどがフォルダの扱い。

FolderName="フルパス"
Set fso=CreateObject("Scripting.FileSystemObject")
Set ie=GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
ie.Navigate FolderName
Do While ie.Busy Or ie.ReadyState<>4
  WScript.Sleep 100
Loop
Set Folder=ie.Document.Folder
For Each FolderItem In Folder.Items()
  If FolderItem.Type<>"ファイル フォルダ" Then
    WScript.Echo fso.GetFileName(FolderItem.Path)
  End if
Next
ie.Quit

更に、拡張子などで絞り込むには、fso.GetExtensionName(FolderItem.Path)などで判定します。

FolderName="フルパス"
Set fso=CreateObject("Scripting.FileSystemObject")
Set ie=GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
ie.Navigate FolderName
Do While ie.Busy Or ie.ReadyState<>4
  WScript.Sleep 100
Loop
Set Folder=ie.Document.Folder
For Each FolderItem In Folder.Items()
  If FolderItem.Type="ファイル フォルダ" Then
  ElseIf LCase(fso.GetExtensionName(FolderItem.Path))="txt" Then
    WScript.Echo fso.GetFileName(FolderItem.Path)
  End If
Next
ie.Quit

2007年12月 9日 (日)

VBSファイルをCMDファイルにする。

今までも、JSファイルをCMDファイルにすることは出来ましたが、VBSファイルをCMDファイルにするのは無理、と諦めていました。が、

@if(0)==(0) ECHO OFF
CScript.exe //E:JScript //NoLogo "%~f0" %*
GOTO :EOF
@end
var SC=new ActiveXObject('ScriptControl');SC.TimeOut=-1;
SC.Language='VBScript';SC.AddObject("WScript",WScript)
SC.AddCode(f.toString().split('\r\n').slice(1,-1).join('\r\n'));
function f(){/*
WScript.Echo WScript.ScriptFullName
WScript.Echo WScript.Arguments.Count()
For Each Arg In WScript.Arguments
  WScript.Echo Arg
Next
*/}

2007年12月 7日 (金)

関連付けは非同期実行なので、連続処理に向かない。(その2)

具体的にどういう問題が起こるかの再現テストです。

Hey, Scripting Guy!に、こんな記事があります。
スクリプトを使用してテキスト ファイルを印刷することはできますか?

そこのサンプルコードは、こうです。

TargetFolder = "C:\Logs"
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(TargetFolder)
Set colItems = objFolder.Items
For Each objItem in colItems
    objItem.InvokeVerbEx("Print")
Next

テキストファイルでは、一度にたくさんのメモ帳が立ち上がるくらいで、あまり問題ないでしょう。

ExcelファイルやPDFファイルならどうか? 試してみてください。

ExcelやAdobe Readerが起動されてない状態で、スクリプトを起動すると、何も起きないか、ExcelやAdobe Readerが起動されるだけで、印刷されなかったりします。

これは、関連付けの非同期処理を待たないで、先にプロセスが終了するからです。

次に、コードの最後に、
MsgBox "Wait!"
を入れて、ExcelやAdobe Readerが起動されてない状態で、起動します。
すると、ファイルの一つは、印刷されますが、残りのファイルは、印刷されたり、されなかったりします。
また、普通はひとつ起動されて終了するはずのExcelがたくさん起動されたり終了しないで残ったりします。
Adobe Readerは仕様でひとつ終了しないで残ります。

次に、ExcelやAdobe Readerが起動されている状態で、起動します。
この場合は、問題なく印刷されます。印刷順序が変わったりしますが。

今度は、サンプルコードの
For Each objItem in colItems
    objItem.InvokeVerbEx("Print")
Next

colItems.InvokeVerbEx("Print")
に変えて、ExcelやAdobe Readerが起動されてない状態で、起動します。
この場合も、問題なく印刷されます。印刷順序は変わりません。
これは、エクスプローラで複数選択してコンテキストメニューで印刷した場合に相当します。

そこで、正しいアプローチですが、例えば、テキストファイルでは、
notepad.exe /p テキストファイル
をひとつずつ同期実行すればよいのです。

ExcelやAdobe Readerの場合は、簡単にコマンドラインで印刷という訳には行きませんが、考え方は同じです。

2007年12月 6日 (木)

スクリプトを使わずに、関連付けで、Excelファイルをコマンドラインで印刷する。

スクリプトの使用が制限されているような環境で、Excelファイルをコマンドラインで印刷するには?

Excelファイル印刷専用の拡張子(.ExcelPrint)を追加し、そのダミーファイルを作って、

Start Excelファイル印刷専用.ExcelPrint Excelファイル

で印刷できます。

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.ExcelPrint\shell\Open]
@="印刷(&P)"

[HKEY_CLASSES_ROOT\.ExcelPrint\shell\Open\command]
@="\"C:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE\" /e"

[HKEY_CLASSES_ROOT\.ExcelPrint\shell\Open\ddeexec]
@="[open(\"%2\")][print()][close()]"

[HKEY_CLASSES_ROOT\.ExcelPrint\shell\Open\ddeexec\application]
@="Excel"

[HKEY_CLASSES_ROOT\.ExcelPrint\shell\Open\ddeexec\ifexec]
@="[open(\"%2\")][print()][quit()]"

[HKEY_CLASSES_ROOT\.ExcelPrint\shell\Open\ddeexec\topic]
@="system"

2007年12月 3日 (月)

PowerShellでZIP圧縮する。

VB.NETからPowerShellに焼き直し。

MakeZIP.ps1 ZIPファイル ファイル...

if($args.length -lt 2){
  write-output "Arguments Missing.";
  write-output "Usage: MakeZIP.PS1 ZIPfile files...";
  return;
}
if([System.IO.Path]::GetExtension($args[0]) -ne ".zip"){
  write-output ("Invalid Extension Name - " + $args[0]);
  return;
}
if(-not [System.IO.File]::Exists($args[0])){
  set-content $args[0] ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18));
}
$shell=new-object -com shell.application;
$zFolder = $Shell.NameSpace([System.IO.Path]::GetFullPath($args[0]));
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
for($k=1;$k -lt $args.length;$k++){
  $File=[System.IO.Path]::GetFileName($args[$k]);
  $sFolderItem=$Shell.NameSpace([System.IO.Path]::GetFullPath($args[$k]+"\..")).ParseName($File);
  if(-not $sFolderItem){
    write-output ("File Not Found. - " + $args[$k]);
    break;
  }
  for($answer=[System.Windows.Forms.DialogResult]::Yes;$answer -eq [System.Windows.Forms.DialogResult]::Yes;){
    $zFolderItem=$zFolder.ParseName($File);
    if(-not $zFolderItem){
      $Count=$zFolder.Items().Count;
      $zFolder.CopyHere($sFolderItem);
      while($zFolder.Items().Count -le $Count){
        Start-sleep -milliseconds 1000;
      }
      break;
    }else{
      $answer = [System.Windows.Forms.MessageBox]::Show("このフォルダには既に次のファイルが存在します:`n`n" + '"' + $File + '"' +"`n`n既存のファイルと置き換えますか?", "ファイル置換の確認", [System.Windows.Forms.MessageBoxButtons]::YesNoCancel, [System.Windows.Forms.MessageBoxIcon]::Question)
      if($answer -eq [System.Windows.Forms.DialogResult]::Yes){$zFolderItem.InvokeVerb("delete");}
    }
  }
  if($answer -eq [System.Windows.Forms.DialogResult]::Cancel){break;}
}

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