2022年5月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
無料ブログはココログ

« 2008年10月 | トップページ | 2008年12月 »

2008年11月27日 (木)

コマンドラインでショートカットを作成、変更、表示するバッチファイル

以前は、Shortcut.exeがありましたが、最近は、入手困難です。
そこで、コマンドラインで、ショートカット(.lnk)とインターネットショートカット(.url)を作成、変更、表示するバッチファイルです。

shortcut.cmd [/t:TargetPath] [/a:Arguments] [/w:WorkingDirectory] [/s:WindowStyle] [/k:HotKey] [/i:IconLocation] [/d:Description] name.{lnk|url}

@if(0)==(0) ECHO OFF
CScript.exe //NoLogo //E:JScript "%~f0" %*
GOTO :EOF
@end
var TargetPath;
var Arguments;
var WorkingDirectory;
var WindowStyle;
var HotKey;
var IconLocation;
var Description;
f1:for(var k=0;k<WScript.Arguments.Count();k++){
  switch(WScript.Arguments.Item(k).substr(0,3).toLowerCase()){
  case "/t:":
    TargetPath=WScript.Arguments.Item(k).substr(3);
    break;
  case "/a:":
    Arguments=WScript.Arguments.Item(k).substr(3);
    Arguments=Arguments.replace(/`/g,'"');
    break;
  case "/w:":
    WorkingDirectory=WScript.Arguments.Item(k).substr(3);
    break;
  case "/s:":
    WindowStyle=WScript.Arguments.Item(k).substr(3);
    WindowStyle=parseInt(WindowStyle);
    if(isNaN(WindowStyle)){
      WScript.Echo("Invalid Window Style - " + WScript.Arguments.Item(k));
      WScript.Quit();
    }
    break;
  case "/k:":
    HotKey=WScript.Arguments.Item(k).substr(3);
    break;
  case "/i:":
    IconLocation=WScript.Arguments.Item(k).substr(3);
    break;
  case "/d:":
    Description=WScript.Arguments.Item(k).substr(3);
    break;
  default:
    break f1;
  }
}
if(k==WScript.Arguments.Count()){
  WScript.Echo("Usage: Shortcut [/t:TargetPath] [/a:Arguments] [/w:WorkingDirectory] [/s:WindowStyle] [/k:HotKey] [/i:IconLocation] [/d:Description] name.{lnk|url}");
  WScript.Quit();
}
var FullName=WScript.Arguments.Item(k);
if(FullName.substr(FullName.length-4).toLowerCase()==".url"){
  var fso=new ActiveXObject("Scripting.FileSystemObject");
  var FullName=fso.GetAbsolutePathName(FullName);
  var Shell=new ActiveXObject("Shell.Application");
  if(!fso.FileExists(FullName)) fso.CreateTextFile(FullName);
  var FolderName=fso.GetParentFolderName(FullName);
  var FileName=fso.GetFileName(FullName);
  var Folder=Shell.NameSpace(FolderName);
  var FolderItem=Folder.Items().Item(FileName);
  var Link=FolderItem.GetLink;
  if(k){
    if(TargetPath!=undefined) Link.Path=TargetPath;
    if(WorkingDirectory!=undefined) Link.WorkingDirectory=WorkingDirectory;
    if(WindowStyle!=undefined) Link.ShowCommand=WindowStyle;
    if(HotKey!=undefined) Link.HotKey=HotKey;
    if(IconLocation!=undefined) Link.SetIconLocation(IconLocation.split(",")[0],parseInt(IconLocation.split(",")[1]));
    if(Description!=undefined) Link.Description=Description;
    Link.Save();
  }else{
    WScript.Echo(new Array(
    "FullName\t " + FolderItem.Path,
    "TargetPath\t " + Link.Path,
    "WorkingDirectory " + Link.WorkingDirectory,
    "ShowCommand\t " + Link.ShowCommand,
    "Hotkey\t\t " + Link.Hotkey,
    "IconLocation\t " + GetIconLocation() + "," + Link.GetIconLocation(""),
    "Description\t " + Link.Description).join("\n"));
  }
}else{
  var wShell=new ActiveXObject("WScript.Shell");
  var Link=wShell.CreateShortcut(FullName);
  if(k){
    if(TargetPath!=undefined) Link.TargetPath=TargetPath;
    if(Arguments!=undefined) Link.Arguments=Arguments;
    if(WorkingDirectory!=undefined) Link.WorkingDirectory=WorkingDirectory;
    if(WindowStyle!=undefined) Link.WindowStyle=WindowStyle;
    if(HotKey!=undefined) Link.HotKey=HotKey;
    if(IconLocation!=undefined) Link.IconLocation=IconLocation;
    if(Description!=undefined) Link.Description=Description;
    Link.Save();
  }else{
    WScript.Echo(new Array(
    "FullName\t " + Link.FullName,
    "TargetPath\t " + Link.TargetPath,
    "Arguments\t " + Link.Arguments,
    "WorkingDirectory " + Link.WorkingDirectory,
    "WindowStyle\t " + Link.WindowStyle,
    "Hotkey\t\t " + Link.Hotkey,
    "IconLocation\t " + Link.IconLocation,
    "Description\t " + Link.Description).join("\n"));
  }
}
function GetIconLocation(){
  var r=fso.OpenTextFile(FolderItem.Path).ReadAll().match(/IconFile=([^\r]*)/im);
  return r?r[1]:"";
}

2008年11月25日 (火)

WSHの引数で二重引用符 " をエスケープするには?(その2)

一般的なコンベンションでは、引数に"を渡すときは、引数を"で囲み、引数の中の"を""に変えて書きます。
"引""数"
アプリ側には、引数を囲む"は渡らず、引数の中の""が"に戻されて渡ります。
引"数

しかし、WSHでは、引数の"がすべて消えてしまいます。

そこで、もし、WSHで引数に"を渡したいときは、`で代用し、スクリプト側で戻します。
"引`数" → 引`数 → 引"数

ここで、もし、WSH(JScript)をバッチファイルでラップすると、一般的なコンベンションが使えます。
"引""数" → "引`数" → 引`数 → 引"数

@if(0)==(0) ECHO OFF
SETLOCAL
SET ARGS=
FOR %%1 IN (%*) DO (
SET "ARG=%%~1"
IF DEFINED ARG CALL SET "ARG=%%ARG:""=`%%"
CALL SET ARGS=%%ARGS%% "%%ARG%%"
)
CScript.exe //NoLogo //E:JScript "%~f0" %ARGS%
GOTO :EOF
@end
for(var k=0;k<WScript.Arguments.Count();k++){
  WScript.Echo(WScript.Arguments.Item(k).replace(/`/g,'"'));
}

VBScriptの場合は、別ファイルにします。

hoge.cmd
---
@ECHO OFF
SETLOCAL
SET ARGS=
FOR %%1 IN (%*) DO (
SET "ARG=%%~1"
IF DEFINED ARG CALL SET "ARG=%%ARG:""=`%%"
CALL SET ARGS=%%ARGS%% "%%ARG%%"
)
CScript.exe //NoLogo ".\hoge.vbs" %ARGS%
---

hoge.vbs
---
For Each Arg In WScript.Arguments
  WScript.Echo Replace(Arg,"`","""")
Next
---

2008年11月24日 (月)

CreateFolder() フォルダを再帰的に作成する関数

FileSystemObjectのCreateFolder()メソッドは、
指定したフォルダが既に存在していた場合は、エラーが発生します。
また、親フォルダが存在しない場合も、エラーが発生します。

そこで、これらの面倒を解消した代替関数を作ります。

Option Explicit
Dim fso
Set fso=CreateObject("Scripting.FileSystemObject")

Sub CreateFolder(ByVal Folder)
Dim ParentFolder
'WScript.Echo Folder
ParentFolder=fso.GetParentFolderName(Folder)
If ParentFolder<>"" Then If Not fso.FolderExists(ParentFolder) Then CreateFolder ParentFolder
If Not fso.FolderExists(Folder) Then fso.CreateFolder Folder
End Sub

CreateFolder "c:\a\b\c\d"
CreateFolder "x:\a\b\c\d"
CreateFolder "c:a"
CreateFolder "x:a"
CreateFolder "a\b"

再帰処理は、無限ループにならないよう、歯止めが必要です。
ここでは、If ParentFolder<>"" が歯止めになっています。
もし、この歯止めがないと、存在しないドライブ(x:)で無限ループします。
WScript.Echo Folder でログを取ると、無限ループの様子がよく分かります。

2008年11月20日 (木)

アプリやバッチファイルを非表示で起動するバッチファイル

もし、引数がなければ、バッチファイルだけで、アプリやバッチファイルを非表示で起動することができます。

HideRun.CMD ファイル

@echo off
if not exist "%~f1" (
echo not found - "%~f1"
goto :eof
)
> %temp%\.url echo;[InternetShortcut]
>>%temp%\.url echo;URL=%~f1
>>%temp%\.url echo;ShowCommand=0
%temp%\.url
del %temp%\.url

テンポラリのインターネットショートカットファイルを作って実行して削除します。

引数があるときは、引数付きのショートカットを作って、そのショートカットファイルを指定します。

2008年11月19日 (水)

インターネットショートカットで、アプリやバッチファイルを非表示で起動する。

スクリプトなどを使って、アプリやバッチファイルを非表示で起動する方法がよくありますが、もし、引数がなければ、インターネットショートカットだけでも可能です。

メモ帳などで以下のようなテキストファイルを作ります。

[InternetShortcut]
URL=アプリやバッチファイルのフルパス
ShowCommand=0

これを保存して、拡張子を.urlに変えます。

もし、引数があるときは、まず、引数付きのショートカットを作り、そのショートカットへのインターネットショートカットを作ればよいのです。

ショートカットへのショートカットは作れませんが、ショートカットへのインターネットショートカットは作れます。

また、ショートカットの「実行時の大きさ」は「非表示」が選択できませんが、インターネットショートカットの「実行時の大きさ」はメモ帳で書けます。

2008年11月18日 (火)

文字列リソースを取り出して見る。

レジストリなどに、
@%SystemRoot%\system32\SHELL32.dll,-22978
のような文字列があります。

これが具体的にどういう文字列に展開されるのか?

それをWin32APIを使わず、スクリプトだけで調べることができます。
それもWScript.Shellを使って。

[cscript] GetResource.VBS [@DLL,ID]

Option Explicit

Dim Resource
Dim Location

For Each Location In WScript.Arguments
  WScript.Echo GetResource(Location)
Next
If WScript.Arguments.Count Then WScript.Quit
Do
  Location=InputBox("Enter @DLL,ID.",WScript.ScriptName,Resource)
  If Location="" Then Exit Do
  Resource=GetResource(Location)
  If Resource="" Then Resource=Location
Loop

Function GetResource(Location)
Dim wShell
Dim Link
Set wShell=CreateObject("WScript.Shell")
Set Link=wShell.CreateShortCut(".LNK")
Link.Description=Location
GetResource=Link.Description
End Function

2008年11月14日 (金)

フォルダサイズを表示するバッチファイル

FolderSize.CMD フォルダ...(ワイルドカード可)

@echo off
setlocal
for /d %%0 in (%*) do (
for /f "tokens=1-3 delims= " %%1 in ('dir /s /a-d %%0') do if %%2==個のファイル set size=%%3
call echo;%%size%% %%0
)

2008年11月13日 (木)

「検索コンパニオン」を開く。

XPに「Windows Search」を入れると、「検索」で開くのは、「Windows Search」になって、「検索コンパニオン」は、一度「Windows Search」を開いて、そこから開くようになります。

では、「検索コンパニオン」を直接、開く方法はないものか?

「新規作成」の「テキストドキュメント」で空のファイルを作って、拡張子を.fnd にします。

というか、ファイル名を例えば、検索コンパニオン.fnd にします。

2008年11月12日 (水)

改行文字変換フィルタをバッチファイルで作る。(その4)

CR を CR+LF に変換します。

cr2dos.cmd <CR >CR+LF
---
@echo off
setlocal enabledelayedexpansion
set LF=^

for /f "delims=" %%1 in ('cmd /u /c echo;名') do (
set CR=%%1
set CR=!CR:~0,1!
)
setlocal disabledelayedexpansion
for /f "delims=" %%1 in ('find /n /v ""') do (
set LINE=%%1
setlocal enabledelayedexpansion
set LINE=!LINE:*]=!
if defined LINE (
cmd /v:on /c echo;%%LINE:!CR!=^^!CR^^!^^!LF^^!%%
) else (
echo;
)
endlocal
)
---

ここで、
for /f "tokens=1* delims=]" %%1 in ('find /n /v ""') do (
set LINE=%%2
としないのは、行頭の ] が消えるからです。

また、
set LINE=%%1
の行で遅延展開を無効にしているのは、もし有効だと、行中の ! が消えるからです。

2008年11月11日 (火)

環境変数の置換文字列に環境変数を使う。

%環境変数:文字列1=文字列2%
で「文字列1」や「文字列2」に環境変数を使うには、「文字列1」や「文字列2」を通常展開、全体を遅延展開します。

!環境変数:%文字列1%=%文字列2%!

もし、「文字列1」や「文字列2」を遅延展開する必要があるとき、「文字列2」は遅延展開できます。

%環境変数:文字列1=!文字列2!%

しかし、「文字列1」は遅延展開できません。

%環境変数:!文字列1!=文字列2% → NG

「文字列1」(と「文字列2」)を遅延展開するには、「文字列1」(と「文字列2」)を遅延展開、全体をCALL %%で遅延展開します。

CALL %%環境変数:!文字列1!=!文字列2!%%

ただし、この場合の「文字列2」の遅延展開は、1パス目に行われるので、2パス目の通常展開時に評価されます。

「文字列2」が2パス目の通常展開時に評価されないようにするには、全体をCMD %%で遅延展開、「文字列2」の遅延展開をエスケープして2パス目に遅延させます。

CMD /V:ON /C %%環境変数:!文字列1!=^^!文字列2^^!%%

2008年11月10日 (月)

環境変数の遅延展開を遅延展開する。

遅延展開有効での展開の順序は、
(1) %環境変数%
(2) %バッチ変数、%%FOR変数
(3) !環境変数!
(4) CALL %%環境変数%%
(5) CALL %%バッチ変数
(6) CMD /V:ON /C ^^!環境変数^^!

遅延展開有効での!のエスケープは^^!です。(1)と(3)で2回エスケープするため?

ただし、
CALL ECHO;^^!環境変数^^!
では、展開されません。

CMD /V:ON /C ECHO;^^!環境変数^^!
なら展開されます。

2008年11月 9日 (日)

改行文字変換フィルタをバッチファイルで作る。(その3)

CR+LF を CR に変換します。

dos2cr.cmd <CR+LF >CR
---
@echo off
setlocal enabledelayedexpansion
for /f "delims=" %%1 in ('cmd /u /c echo;名') do (
set CR=%%1
set CR=!CR:~0,1!
)
setlocal disabledelayedexpansion
for /f "delims=" %%1 in ('find /n /v ""') do (
set LINE=%%1
setlocal enabledelayedexpansion
<NUL set /p LINE=!LINE:*]=!!CR!
endlocal
)
---

2008年11月 7日 (金)

改行文字変換フィルタをバッチファイルで作る。(その2)

異常な改行文字(CR+CR+LF)を正常な CR+LF に変換します。

pingなどのunix由来のネットワーク系コマンドの改行文字は異常です。
CR+CR+LF になっています。
コンソール画面で見た目には同じですが、プログラムで処理するときに困ります。

CrCrLf.CMD <CR+CR+LF >CR+LF
---
@echo off
setlocal disabledelayedexpansion
for /f "delims=" %%1 in ('find /n /v ""') do (
set LINE=%%1
setlocal enabledelayedexpansion
call echo;!LINE:*]=!
endlocal
)
---

CRは、%環境変数%の展開時に消えます。

%%FOR変数や!環境変数!は、%環境変数%の後に展開されるので、
echo;%%FOR変数

echo;!環境変数!
では残ります。

しかし、CALL文では、展開が2回実行されるので、
call echo;%%FOR変数

call echo;!環境変数!
では、2回目で消えます。

2008年11月 6日 (木)

コマンドプロンプトやバッチファイルで、環境変数に改行文字(CR)を入れて使う。

環境変数に改行文字(CR)を入れる。

名 の unicode が 540D、これをシフトJISで読むと、0D 54 つまり、CR+T であることを利用して、CR を抜き出します。

setlocal enabledelayedexpansion
for /f "delims=" %%1 in ('cmd /u /c echo;名') do (
set CR=%%1
set CR=!CR:~0,1!
)

改行文字(CR)を使うときは、環境変数を遅延展開します。

echo aaa!CR!bbb

もし、環境変数を遅延展開しないと、改行文字(CR)は消えます。

echo aaa%CR%bbb

しかし、これはこれで、「改行文字(CR)を消す」ために利用できます。

2008年11月 5日 (水)

コマンドプロンプトやバッチファイルで、環境変数に制御文字を入れる。

元になるシフトJIS文字を選びます。

まず、候補の文字の一覧を出します。

cscript hoge.vbs > hoge.txt

For n=0 To 15
  For k=&H8140 To &Hea9e
    If k=Asc(Chr(k)) Then
      If (AscW(Chr(k)) And 255) = n Then
        WScript.StdOut.WriteLine Join(Array(Hex(k),Chr(k),Hex(AscW(Chr(k)))),vbTab)
      End If
    End If
  Next
Next

この中から、制御文字が cc なら、unicode が hhcc の文字を選びます。

例えば、CR(0D) なら 名(540D) などです。

環境変数に制御文字を入れる。

setlocal enabledelayedexpansion
for /f "delims=" %%1 in ('cmd /u /c echo;名') do (
set CR=%%1
set CR=!CR:~0,1!
)

名 の unicode が 540D、これをシフトJISで読むと、0D 54 つまり、CR+T であることを利用して、CR を抜き出します。

ただし、LF(0A)は、このやり方ではできません。

2008年11月 4日 (火)

改行文字変換フィルタをバッチファイルで作る。

テキストファイルの改行文字は、OSで異なります。
DOS/Windows CR+LF
Unix/Linux  LF
Mac/MainFrame  CR

変換フィルタは、SFUにあり、それだけコピーしても使えます。
dos2unix.exe
unix2dos.exe

SFUがなくても、バッチファイルで代替できます。

dos2unix.cmd <CR+LF >LF
---
@echo off
setlocal disabledelayedexpansion
set LF=^

for /f "delims=" %%1 in ('find /n /v ""') do (
set LINE=%%1
setlocal enabledelayedexpansion
<NUL set /p LINE=!LINE:*]=!!LF!
endlocal
)
---

unix2dos.cmd <LF >CR+LF
---
@find /v ""
---
または、
---
@echo off
setlocal disabledelayedexpansion
for /f "delims=" %%1 in ('find /n /v ""') do (
set LINE=%%1
setlocal enabledelayedexpansion
echo;!LINE:*]=!
endlocal
)
---

moreを使ってもできますが、その場合はタブが空白展開されます。

2008年11月 3日 (月)

FORコマンドで、行のフィールドを順次取り出す。

例えば、CSVのような行で、各フィールドを決め打ちで取り出すには、

FOR /F "tokens=1-3 delims=," %%1 IN ("aaa,bbb,,ccc") DO (
ECHO;"%%1"
ECHO;"%%2"
ECHO;"%%3"
)

ですが、フィールド数が可変で、各フィールドを順次取り出すには?

再帰的に先頭フィールドを取り出します。

SETLOCAL ENABLEDELAYEDEXPANSION
SET LINE=aaa,bbb,,ccc
:LOOP
FOR /F "tokens=1* delims=," %%1 IN ("!LINE!") DO (
ECHO;"%%1"
SET LINE=%%2
GOTO :LOOP
)

フィールド区切りを改行文字に変えて、複数フィールドを複数行にします。

SETLOCAL ENABLEDELAYEDEXPANSION
SET LF=^(改行)
(改行)
(改行)
SET LINE=aaa,bbb,,ccc
SET LINE=%LINE:,=!LF!%
FOR /F "delims=" %%1 IN ("!LINE!") DO (
ECHO;"%%1"
)

いずれのやり方も、連続する区切り文字や先行する区切り文字が無視されます。

そこで、ダミーのヘッダ文字を付けると、空のフィールドが取り出せます。

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET LF=^

SET LINE=aaa,bbb,,ccc
SET LINE=]%LINE:,=!LF!]%
FOR /F "delims=," %%1 IN ("!LINE!") DO (
SET LINE=%%1
ECHO;"!LINE:~1!"
)

2008年11月 2日 (日)

コマンドプロンプトやバッチファイルで、環境変数に改行文字(LF)を入れて使う。

環境変数に改行文字(LF)を入れる。

コマンドプロンプトでは、

SET LF=^(改行)
More? (改行)
More? (改行)

バッチファイルでは、

SET LF=^(改行)
(改行)
(改行)

改行文字(LF)を使うときは、環境変数を遅延展開します。

コマンドプロンプトでは、

CMD /V:ON
SET x=aaa!LF!bbb
ECHO !x!
EXIT

バッチファイルでは、

SETLOCAL ENABLEDELAYEDEXPANSION
SET x=aaa!LF!bbb
ECHO !x!

遅延展開しないと、改行されて、改行文字以降が消えます。

ECHO aaa%LF%bbb

また、FOR /F IN ("文字列")の中で改行文字(LF)を使うと、「複数行の文字列」になります。

FOR /F %%1 IN ("aaa!LF!bbb") DO ECHO;"%%1"

2008年11月 1日 (土)

ECHOなどの内部コマンドの区切り文字は、=;,を使うべし。:\./+[]は使わないこと。

ECHOの区切り文字に、:\./+[]を使う例がよくありますが、よくないようです。

echo.%date:/=-%

は通りますが、

setlocal enabledelayedexpansion
echo.!date:/=-!

は通りません。

« 2008年10月 | トップページ | 2008年12月 »