« 2009年12月 | トップページ | 2010年2月 »

2010年1月31日 (日)

メモ帳やコマンドプロンプトで制御文字(RS/US)を入力する。

メモ帳(などのGUI)では、右クリック、「Unicode制御文字の挿入」で、RSとUSが入力可能です。
RS ^^ ALT+30 001e{F5}
US ^_ ALT+31 001f{F5}

メモ帳やコマンドプロンプトでは、日本語キーボードでは、CTRL+^ やCTRL+_ では、^^や^_が入力できません。
代わりに、
^^ CTRL + SHIFT + 6/&
^_ CTRL + SHIFT + -/=

2010年1月30日 (土)

コマンドプロンプトやバッチファイルで{ESC}文字を使う。

^[ や 001b{F5} などの特別な入力法を知らなくても使えます。

for /f %i in ('cmd /k prompt $e^<nul') do set {ESC}=%i
echo %{ESC}%

2010年1月29日 (金)

メモ帳で制御文字を見る。

メモ帳で普通に見ると、制御文字が見えません。それはフォントのせいです。

以下のフォントにすると見えます。
FixedSys
System
Terminal
MS UI Gothic

2010年1月28日 (木)

IEを常に最大化で開く。(その2)

これを設定で行うのは困難なようです。

なので、HTAでIEを監視して、IEを常に全画面表示(F11)で開きます。

IeMaximizer.hta

<head><title>IE Maximizer</title>
<script language=vbscript>
resizeTo 210,10
Set ies=CreateObject("Shell.Application").Windows()
setInterval "proc",1000
Sub proc
For Each ie In ies
  If InStr(LCase(ie.FullName),"iexplore.exe") Then If ie.Left>0 Then ie.TheaterMode=True
Next
End Sub
</script>
</head>

これなら複数タブ状態でも効きます。

全画面表示(F11)=(ie.TheaterMode=True)≠(ie.Fullscreen=True)=(iexplore.exe -k)

2010年1月27日 (水)

IEを少なくとも1つは開く。

HTAでIEを監視して、少なくとも1つは開くようにします。

IeOneOpener.hta

<head><title>IE 1 Opener</title>
<script language=vbscript>
resizeTo 210,10
Set ies=CreateObject("Shell.Application").Windows()
setInterval "proc",1000
Sub proc
For Each ie In ies
  If InStr(LCase(ie.FullName),"iexplore.exe") Then Exit Sub
Next
open
End Sub
</script>
</head>

2010年1月26日 (火)

IEを常に最大化で開く。

これを設定で行うのは困難なようです。

なので、HTAでIEを監視して、IEを常に疑似最大化(最大化の位置とサイズ)で開きます。

IeMaximizer.hta

<head><title>IE Maximizer</title>
<script language=vbscript>
resizeTo 210,10
Set ies=CreateObject("Shell.Application").Windows()
setInterval "proc",1000
Sub proc
For Each ie In ies
  If InStr(LCase(ie.FullName),"iexplore.exe") Then
    If ie.Left>0 Then
      ie.Left=0
      ie.Top=0
      ie.Width=screen.availWidth
      ie.Height=screen.availHeight
    End If
  End If
Next
End Sub
</script>
</head>

ただし、複数タブ状態では効かないようです。

2010年1月25日 (月)

VistaにはCLIPBRD.EXEがない。

代わりに、ExcelのOffice Clipboardを使う。

Clipbrd.vbs

Set Application=CreateObject("Excel.Application")
Application.Visible=True
Application.DisplayClipboardWindow=True
Application.UserControl=True

2010年1月24日 (日)

PowerShellがあれば、文字コード変換も簡単です。

ファイルからファイルへ、例えば、UTF-8からUTF-7へ。

powershell "get-content utf8.txt -encoding utf8|set-content utf7.txt -encoding utf7"

powershell "get-content utf8.txt -encoding utf8|add-content utf7.txt -encoding utf7"

powershell "get-content utf8.txt -encoding utf8|out-file utf7.txt -encoding utf7"

フィルタで、例えば、UTF-8からUTF-7へ。

powershell "[console]::inputencoding=[text.encoding]::getencoding('utf-8');[console]::outputencoding=[text.encod
ing]::getencoding('utf-7');$input" < utf8.txt >utf7.txt

2010年1月21日 (木)

タスクスケジューラのタスクに引数を与えて起動する。

schtasksコマンドではできませんが、スクリプトからは可能です。

タスクの引数に、仮引数を、$(Arg0),$(Arg1),$(Arg2)...などと書いておけば、実引数に置き換えられます。
実引数に置き換わらなかった仮引数はそのまま残ります。

Set TaskService=CreateObject("Schedule.Service")
TaskService.Connect
Set Folder=TaskService.GetFolder("\")
Set Task=Folder.GetTask("hoge")
Task.Run "引数0"

VBScriptでは、String型の配列が作れないので渡せるのは1個の文字列です。

PowerShellなら、複数の文字列が渡せます。

$TaskService=New-Object -ComObject schedule.service
$TaskService.Connect()
$Folder=$TaskService.GetFolder("\")
$Task=$Folder.GetTask("hoge")
[String[]]$a="引数0","引数1","引数2"
$Task.Run($a)

2010年1月20日 (水)

タスクスケジューラのタスクをスクリプトから起動する。

Set TaskService=CreateObject("Schedule.Service")
TaskService.Connect
Set Folder=TaskService.GetFolder("\")
Set Task=Folder.GetTask("hoge1")
Task.Run Empty

schtasksコマンドとの違いは、
コンソールウィンドウが出ない。
引数が渡せる。

2010年1月19日 (火)

タスクスケジューラで、リモートshellもどきの疑似的な対話処理を行う。

「ユーザーがログオンしているかときのみ実行する」場合は、表示して対話が可能です。

「ユーザーがログオンしているかどうかにかかわらず実行する」場合は、表示しての対話ができません。

標準入出力のコンソールアプリならリモートshellもどきで疑似的な対話処理が可能です。

shelld.cmdをタスクスケジューラで実行します。

call >"%~dp00"
tail -f "%~dp00"|(cmd 1>"%~dp01"
echo !!! enter CTRL+Z to terminate input service !!!>&2) 2>"%~dp02"

shell.cmdをコンソールから実行します。

@echo off
start /b tail -f "%~dp01"
start /b tail -f "%~dp02"
copy /y con "%~dp00"
echo exit>>"%~dp00"
sleep 2
echo exit>>"%~dp00"
sleep 2
call >"%~dp00" 1>"%~dp01" 2>"%~dp02"
sleep 2
for /f %%I in ('del "%~dp00" "%~dp01" "%~dp02"') do echo !!! enter CTRL+BREAK to terminate output srvices !!!

2010年1月18日 (月)

リモートshellもどき実験

同じカレントディレクトリで2つのコマンドプロンプトを開き、

サーバ側で、

call >0
tail -f 0|cmd 1>1 2>2

クライアント側で、

start /b tail -f 1
start /b tail -f 2
copy /y con 0

ここでコマンドを入力すると、サーバ側で実行されて、結果がクライアント側に表示されます。

終了は、
exitでサーバのcmdを止める。
exitのエコーを確認したら何か入力してサーバのtailを止める。
^Zでcopyを閉じる。
^breakでtailの2つを止める。

2010年1月17日 (日)

dirコマンドで更新日時の秒まで表示する。

ファイルシステムの更新日時は秒まであるのに、dirコマンドは分まで。:-(
仕方がないので、FSOかShellを使います。

fdir [ファイルまたはディレクトリ...]

@if(0)==(0) ECHO OFF
setlocal
set x=%*
if not defined x set x=*
FOR %%I IN (%x%) DO FOR /F "delims=" %%J IN ('CScript.exe //NoLogo //E:JScript %0 "%%~fI"') DO ECHO %%~aI %%J
GOTO :EOF
@end
var fso=new ActiveXObject('Scripting.FileSystemObject');
if(fso.FileExists(WScript.Arguments.Item(0))){
  var File=fso.GetFile(WScript.Arguments.Item(0));
  WScript.Echo(File.DateLastModified,File.Size,File.Name);
}
else if(fso.FolderExists(WScript.Arguments.Item(0))){
  var Folder=fso.GetFolder(WScript.Arguments.Item(0));
  WScript.Echo(Folder.DateLastModified,Folder.Size,Folder.Name);
}

sdir [ファイルまたはディレクトリ...]

@if(0)==(0) ECHO OFF
setlocal
set x=%*
if not defined x set x=*
FOR %%I IN (%x%) DO FOR /F "delims=" %%J IN ('CScript.exe //NoLogo //E:JScript %0 "%%~dpI" "%%~nxI"') DO ECHO %%~aI %%J
GOTO :EOF
@end
var Shell=new ActiveXObject('Shell.Application');
var Folder=Shell.NameSpace(WScript.Arguments.Item(0));
var FolderItem=Folder.Items().Item(WScript.Arguments.Item(1));
WScript.Echo(FolderItem.ModifyDate,FolderItem.Size,FolderItem.Name);

Shellだと、ディレクトリのサイズやショートカットの拡張子が出ません。
なのでFSOを推奨。

2010年1月16日 (土)

「別のユーザーとして実行」して「管理者として実行」する。

別のユーザーの「管理者として実行」するには、「別のユーザーとして実行」してから「管理者として実行」する必要があります。

ユーザ名をハードコードして、パスワードをプロンプトで与える場合、

RunAsUserAdmin0.cmd コマンド [引数...]

set x=%*
runas /user:user "powershell -command \"start-process 'cmd' '/c %x:"=\\\"%' -verb 'runas'\""

ユーザ名をハードコードして、パスワードをダイアログで与える場合、

RunAsUserAdmin1.cmd コマンド [引数...]

set x=%*
powershell -command "start-process 'powershell' '-command \"start-process ''cmd'' ''/c %x:"=\\\"%'' -verb ''runas''\"' -credential (get-credential 'user')"

ユーザ名とパスワードをダイアログで与える場合、

RunAsUserAdmin2.cmd コマンド [引数...]

set x=%*
powershell -command "start-process 'powershell' '-command \"start-process ''cmd'' ''/c %x:"=\\\"%'' -verb ''runas''\"' -credential $null"

ユーザ名とパスワードをハードコードする場合、

RunAsUserAdmin3.cmd コマンド [引数...]

set x=%*
powershell -command "start-process 'powershell' '-command \"start-process ''cmd'' ''/c %x:"=\\\"%'' -verb ''runas''\"' -credential (new-object Management.Automation.PSCredential 'user', (ConvertTo-SecureString -AsPlainText -Force 'password'))"

いずれの場合も、UACダイアログは出ます。

2010年1月15日 (金)

エクスプローラから「別のユーザーとして実行」する。

RunAsコマンドは引数でユーザ名を与えねばならず、エクスプローラから起動してユーザを選択することができません。:-(

PowerShellを使えば、GUIでユーザを選択することができます。

例えば、コマンドラインでは、

RunAsUser.cmd コマンド [引数...]

set x=%*
powershell "start-process -credential $null 'cmd' '/c %x:"=\""%'"

これをコンテキストメニューから利用するには、関連付けに、

HKCR\ファイルタイプ\shell\RunAsUser\command

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "start-process -credential $null 'cmd' '/c \"%1\" %*'"

「送る」から利用するには、ショートカット RunAsUser.lnk のリンク先に、

cmd.exe /v:on /c for /l %n in (1,1,2) do if %n==2 (for %y in (!x!) do powershell "start-process -credential $null 'cmd' '/c \""%~y\""'") else set x=

このとき、コンソール画面が開きますが、それが煩わしいときは、-windowstyle hidden を追加します。

関連付け

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -windowstyle hidden "start-process -credential $null 'cmd' '/c \"%1\" %*'"

ショートカット

cmd.exe /v:on /c for /l %n in (1,1,2) do if %n==2 (for %y in (!x!) do powershell -windowstyle hidden "start-process -credential $null 'cmd' '/c \""%~y\""'") else set x=

それでも、コンソール画面が一時開きます。そこで、ショートカットの「ウィンドウの大きさ」を「最小化」にしておきます。

2010年1月14日 (木)

環境変数を遅延展開する第3の方法とは?

第1は、!環境変数!
第2は、call %%環境変数%%
第3は、for

for /f "delims== tokens=1*" %%i in ('set 環境変数') do echo %%j

数字限定でよければ、

for /f %%i in ('set /a 環境変数') do echo %%i

第2の方法は、ifやforに使えませんが、第3の方法なら使えます。

(rem これは駄目。
set x=1
call if %%x%%==1 echo %%x%%
)

(rem これはおk。
set x=1
for /f "delims== tokens=1*" %%i in ('set x') do if %%j==1 echo %%j
)

また、第3の方法ならバッチファイル外でも使えます。

2010年1月13日 (水)

「管理者として実行」されたコマンドラインから、「標準ユーザとして実行」する。

SchTasksコマンドを使えば、「標準ユーザ」に降格できます。

schtasks /create /tn hoge /tr "cmd" /sc once /st 00:00 /it /rl limited

schtasks /run /tn hoge

/rl limited は省略可。

2010年1月12日 (火)

バッチファイルで、「管理者として実行」されているか?「整合性レベル:低」か?を判定する。(その2)

IsIL.cmd

for /f "tokens=3 delims=\ " %%i in ('whoami /groups^|find "Mandatory"') do set LEVEL=%%i
echo %LEVEL%

ここで、
High 管理者として実行
Medium 標準ユーザ
Low 「整合性レベル:低」 (「保護モード:有効」)

2010年1月11日 (月)

Vistaでsleepを代替する。

timeoutは標準入力がリダイレクトされているとエラーになるので使わない方がよい。

waitfor hoge /t 秒

ただし、以下のようにすれば標準入力がリダイレクトされていても大丈夫です。

start /min /wait timeout 秒

2010年1月10日 (日)

標準入力がリダイレクトされているかどうか?を判定する。

timeout 0 >nul 2>nul
if errorlevel 1 (echo redirected) else echo console

2010年1月 8日 (金)

標準出力がリダイレクトされているかどうか?を判定する。

color 0f
if errorlevel 1 (echo redirected) else echo console

引数なしのcolorでもよさそうですが、cmd /cで実行するとエラーなので。

2010年1月 7日 (木)

遅延展開が有効か無効か?を判定する。

if !errorlevel! == %errorlevel% (echo enable) else echo disable

if "!" == "" でも判定できそうですが、これはバッチファイル内限定なので。

2010年1月 6日 (水)

.NETなどのコマンドラインの引数で引用符をエスケープする。(その2)

RunAsコマンドは、.NETではありませんが、RunAs.exeをメモ帳で開くと、CommandLineToArgvWという文字列が見えます。なので標準シンタクスです。

例えば、cmd /k title "a b"なら、

RunAs ... "cmd /k title \"a b\""

か、

RunAs ... "cmd /k title """a b""""

と書けますが、cmd /k title "a < b"ならどうするか?

cmd.exeの遅延展開を使っても、cmd.exeの制御文字をエスケープできます。

set "x=RunAs ... ""cmd /k title \""a < b\"""""
if !errorlevel! == %errorlevel% (!x:""^=^"!) else cmd /v:on /c !x:""^^="!

set "x=コマンドライン"の中の"を2倍個します。外側の"で制御文字は無効です。
遅延展開で、""を半減して実行します。遅延展開後の制御文字は無効です。
遅延展開が有効なら、その場で実行し、無効ならサブシェルで有効にして実行します。

2010年1月 5日 (火)

.NETなどのコマンドラインの引数で引用符をエスケープする。

.NETのエスケープ法は、\"(\と1個の")または"""(3個の")ですが、cmd.exeのエスケープ法は""(偶数個の")なので、合いません。

そこで、.NETとcmd.exeの両方でエスケープする方法ですが、これは、PowerShell.exeのように簡単には行きません。

しかし、PowerShell.exeを使えば、なんとか可能です。

PowerShell ".\ファイル '引数...';"

ここで、'引数...'内の、

"の左に隣接する\を2倍個の\でエスケープします。

"を\""(\と2個の")または"""(3個の")でエスケープします。ただし、奇数のときは、cmd.exeのエスケープのため、+1して偶数にします。

\"によるエスケープはC以来の伝統。"""によるエスケープはundocumented。

このエスケープ法は共に、.NETというより、Win32APIのCommandLineToArgvW()の仕様です。つまり、MSの標準シンタクスです。

2010年1月 3日 (日)

PowerShell.exe -command "スクリプト" で引用符をエスケープする。(その2)

そこで、PowerShell.exeとcmd.exeの両方でエスケープする方法です。

"スクリプト"内では、

"の左に隣接する\を2倍個の\でエスケープします。

"を\""(\と2個の")でエスケープします。

あるいは、

"を"""(3個の")でエスケープします。ただし、奇数のときは、cmd.exeのエスケープのため、+1して偶数にします。

PowerShell.exeは、"スクリプト"を評価するときに、3n個の"をn個の"に変換して、端数個の"を切り捨てるようです。
ただし、最初の端数2個の"は、例外的に1個の"に切り上げて変換するようです。

単純さで、\""がお勧めです。

例えば、write-host "a""b";というスクリプトは、

PowerShell "write-host \""a\""\""b\"";"

PowerShell "write-host """"a""""""b"""";"

のように書けます。

2010年1月 2日 (土)

PowerShell.exe -command "スクリプト" で引用符をエスケープする。

PowerShell "スクリプト"で、PowerShellのone linerがバッチファイル内に書けます。

ただ、PowerShellスクリプトをそのまま"スクリプト"内に書くと、引用符が悪さします。

エスケープしようにも、簡単には行きません。

PowerShell.exeのエスケープ法は、\"(\と1個の")または"""(3個の")ですが、cmd.exeのエスケープ法は""(偶数個の")なので、合いません。

例えば、"a;b"という文字列は、

PowerShell "write-host \"a;b\";"

PowerShell "write-host """a;b""";"

で、うまく行きますが、"a<b"という文字列は、

PowerShell "write-host \"a<b\";"

PowerShell "write-host """a<b""";"

で、失敗します。

<>|&などのcmd.exeの制御文字は、奇数個目の"~偶数個目の"でエスケープされ、偶数個目の"~奇数個目の"でエスケープされません。

« 2009年12月 | トップページ | 2010年2月 »