ラベル bat の投稿を表示しています。 すべての投稿を表示
ラベル bat の投稿を表示しています。 すべての投稿を表示

2009年3月4日水曜日

コマンドプロンプトはタイトルつけとくといいよ

Windows使っているならコマンドプロンプト使うよね?
OKわかった、"title" コマンドを使うべきだ。
 
 

要はいくつか開いたコマンドプロンプトのウインドウを区別つくようにしておこうという趣旨。
"title" コマンドはタイトルバーの文字を変えてくれる、例えばL2スイッチに telnet する前に "title L2" としてみよう。

[caption id="attachment_1261" align="alignnone" width="677" caption="画像:titleコマンド結果"]画像:titleコマンド結果[/caption]
 

タイトルバーが変わったのが分かるはず。Vistaだと、「管理者:」 ってのが固定だから少々じゃまだが、XPだとすっきりしているはずだ。
 

これはタスクバーにコマンドプロンプトを並べたとき特に威力を発揮する。

[caption id="attachment_1262" align="alignnone" width="148" caption="画像:タスクバー"]画像:タスクバー[/caption]
※ 追記:タスクバーを右にして使っています。
 

それぞれのウインドウでやってることがわかる、これは作業効率に地味に効いてくるので癖をつけたほうがいいと思う。
「Windows+Rキー → cmd → title hogehoge」 という流れを意識しよう。
 

2008年12月4日木曜日

MS-DOSバッチファイルでFizzBuzz

昨日の記事:VBScript で FizzBuzz の続編。
FizzBuzz、今度はDOSバッチファイルで作ってみた。
単純にやってみたかっただけなので、コードを短くする工夫とかはまあ置いておこう。
 
 

FizzBuzzをDOSバッチでやる際に、とりあえず剰余(mod)が取れるのかよく分からなかったので3の倍数、5の倍数を判断するカウンタをつくることにして書いてみた。
記事書く前に、本で算術演算子を調べたら、mod 取れるみたい…
100を3で割った余りなら、
> set /a hoge=100%3
でOKだった。まぁコレはコレでありかな。。

 

ちょっと引っかかったのが遅延展開、forの中で普通に変数 %hoge% って使うと、forの中でいくら中身をいじろうと、for に入る前の変数の中身が展開されちゃう。
setlocalで 遅延展開有効 にして、!hoge! って使えばfor内でもその時点の変数内容が展開される。
あとは特に工夫も無く。
[sourcecode language='sh']
@echo off

REM // 遅延展開有効
setlocal enabledelayedexpansion

REM // ウインドウタイトル変更
TITLE FizzBuzz

REM // カウントダウン用の変数
set SAN=3
set GO=5

REM // 繰り返し
for /l %%I in (1,1,100) do (

rem // 表示用の変数、空っぽ比較用も
set STRING=
set STRING_FLG=

rem // 3と5のカウンターが0ならリセット
if !SAN!==0 (set SAN=3)
if !GO!==0 (set GO=5)

rem // 3と5のカウンターを一つ減らす
set /a SAN=!SAN!-1
set /a GO=!GO!-1

rem // 3のカウンターが0なら表示用にFizz追加
if !SAN!==0 (set STRING=Fizz)

rem // 5のカウンターが0なら表示用にBuzz追加
if !GO!==0 (set STRING=!string!Buzz)

rem // ここでFizzもBuzzも入ってなければループ数字追加
if !STRING!==!STRING_FLG! (set STRING=!STRING!%%I)

rem // 現在の数と、FizzBuzzの結果を出力
echo %%I !STRING!
)
pause
endlocal
[/sourcecode]


実行結果。
[caption id="attachment_1099" align="alignnone" width="428" caption="画像:FizzBuzz"]画像:FizzBuzz[/caption]
 

デキター。
 

剰余の計算処理もちゃんと調べてればもう少しスマートだったが、まあ結果オーライという事にしよう。
set のヘルプに一応ヒントらしきものはあったが見逃した。
setの詳しい解説があった。

2008年9月23日火曜日

なんとなくWindowsでC言語プログラミング_(2)

「なんとなくPシリーズ」タグを作って続行。タイトルは 続 → 新 → … と続けたかったがやめておく。
一応コンセプトとしてはC言語を勉強してLinuxカーネルソースに迫ろうとしているのだが、果たして。
 
 

前回のなんとなくWindowsでC言語プログラミングで思い出したものがある。
こんにちはマイコン」、1982年!の本。次は折角なのでそれっぽいことをやってみよう。
変数のお勉強でたしかこんなコード、N-88 Basic だっけ?
10 INPUT "ナマエ ヲ ニュウリョク";A$
20 PRINT A$;"ノ アホー"
(30 goto 20)
※3行目gotoもしたかったけど、今回大分話がそれていくのでパス。
 
キーボードから文字列の入力を促し、変数に代入。それを標準出力から表示する単純なプログラムだ。
これの下りは面白かった記憶がある。
 

ついでなのでbatで再現


[sourcecode language='bash']
@echo off
set /P name="ナマエ ヲ ニュウリョク"
:10
echo %name% ノ アホー
goto 10
[/sourcecode]
簡単だが、やはりこれでは展開がない。
 
 

それではCで再現


main(void)とコメントを覚えた。
[sourcecode language='c']
#include

int main(void) {
char name[8]; /*メモリ8バイト確保!*/
printf("ナマエ ヲ ニュウリョク");
scanf("%s",name); /*入力をnameのポインタのとこに並べる*/
printf("%sノ アホー\n",name); /*nameの中身を出力*/
return 0;
}

[/sourcecode]

収穫は変数の宣言とscanfのおかげでポインタがなんとなく分かった事。

実行してみる。
>inputter.exe
ナマエ ヲ ニュウリョクarashi
arashiノ アホー

上々。
 
char宣言で8バイトメモリを確保、アドレスの情報をポインタとしてnameに格納しているというわけかいな。
 

実験タイム1


ほなここで実験してみよう、変数2つ宣言したら並ぶの?
[sourcecode language='c']
#include

int main(void) {
char name[8]; /*メモリ8バイト確保!*/
char name1[8]; /*同様にname1を宣言する*/
printf("ナマエ ヲ ニュウリョク");
scanf("%s",name);
printf("%sサンハ テンサイ\n",name);
printf("%x\n",&name); /*nameのアドレス*/
printf("%x\n",&name1); /*name1のアドレス*/
return 0;
}

[/sourcecode]


>inputter.exe
ナマエ ヲ ニュウリョクsatoru
satoruサンハ テンサイ
12ff64
12ff6c


えーと、8バイトだからー。 12ff64 から 12ff6b までで8バイト、次は 12ff6c から、、合ってる。並んでるね。
 

実験タイム2


入出力で実験、入力してない変数を出力するとか。
[sourcecode language='c']
#include

int main(void) {
char name[8];
char name1[8];
printf("ナマエ ヲ ニュウリョク");
scanf("%s",name);
printf("%sサンハ テンサイ\n",name);
printf("%sノ アホー\n",name1); /*入力してないname1を出力する*/
return 0;
}
[/sourcecode]

実行する、まずは普通の入力
>inputter.exe
ナマエ ヲ ニュウリョクippata
ippataサンハ テンサイ
3n@ノ アホー

3n@ てなんじゃらほい。確保したメモリに元からあった情報と言うことらしいけど、まあ0で埋めるなりの初期化すれば問題ないことが分かった。
 

でも次の入力。20文字入れてみる。
>inputter.exe
ナマエ ヲ ニュウリョク123456789a123456789b
123456789a123456789bサンハ テンサイ
9a123456789bノ アホー

ああああぁ、は、はみ出したーー
scanf()に脆弱性が、っていうのはテクニカルエンジニアで習ったけどこういうことか、ものすごく納得。
とはいえ、狙ったコードの実行は至難の技にも見えるんだけど、どうなんだろう。なんか手法が確立されてるんだろうか。
 
 

そして脱線へ


これはどうやって動いているんだろうと思ったのでちょっと追う。
WindowsのCコンパイラは "/Fa" というオプションをつけたらアセンブリリストのファイルを作ってくれる。
で、作ってみた。ちょっと省略してこんな感じ。
_main PROC
; File c:\cprog\inputter.c
; Line 3
push ebp
mov ebp, esp
sub esp, 20 ; 00000014H
mov eax, DWORD PTR ___security_cookie
xor eax, ebp
mov DWORD PTR __$ArrayPad$[ebp], eax
; Line 6
push OFFSET $SG2471
call _printf
add esp, 4
; Line 7
lea eax, DWORD PTR _name$[ebp]
push eax
push OFFSET $SG2472
call _scanf
add esp, 8
; Line 8
lea ecx, DWORD PTR _name$[ebp]
push ecx
push OFFSET $SG2473
call _printf
add esp, 8
; Line 9
lea edx, DWORD PTR _name1$[ebp]
push edx
push OFFSET $SG2474
call _printf
add esp, 8
; Line 10
xor eax, eax
; Line 11
mov ecx, DWORD PTR __$ArrayPad$[ebp]
xor ecx, ebp
call @__security_check_cookie@4
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END

 

うーん。。まさにこれは全部書いてあるんだろうけど、次回だな。
 
 

しかし カーネル への道のはずなんだが。。。やっぱり遠回りなのでは。
そうだコンテキストスイッチというのはこれを切り替えているんだろうなと言うことでまとめよう。

2008年9月9日火曜日

イベントログを詳細付きでCSVに出力、ツール追加なし@WindowsServer

イベントログをゆっくり見ようと思ったら、CSV→Excelとかにしたくなる。
しかし標準のイベントビュアー付属のファイル出力機能を使っても、スカスカなものが出来上がる。はっきり言って使い物にならない。
こんなときLogParserがやっぱり便利なんだけど、入れてないサーバもある。
人様のサーバだったりすると勝手に入れるのはアカンし、よい場合でもLogParser落として入れてパス通して… といちいちやるのも結構面倒、急いでいるときはなおさら。
 
 

ってことで、"eventquery.vbs":リンク/TechNet の使い方をメモ。
あまり使わないのでいつも使い方を忘れて何度も日時で引っかかる。このツールでは「年/月/日」ではなくて「月/日/年」で指定するんだぞ自分よ。あと一日の始まりは「12:00AM」だからよろしく。
 
 

?オプションで起動してヘルプを出す
>cscript %systemroot%\system32\eventquery.vbs /?

Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.


EVENTQUERY.vbs [/S システム [/U ユーザー名 [/P パスワード]]] [/V] [/FI フィルタ]
[/FO 形式] [/R 範囲] [/NH] [/L ログ名 | *]

説明:
EVENTQUERY.vbs スクリプトにより、管理者は 1 つ以上のイベント
ログ中のイベントとイベントのプロパティを一覧表示できます。

パラメータ一覧:
/S サーバー 接続先のサーバーを指定します。

/U [ドメイン\]ユーザー コマンドが実行されるユーザー
のコンテキストを指定します。

/P パスワード 指定のユーザー コンテキストの
パスワードを指定します。

/V 詳細情報を表示します。出力時に詳細情報を
画面に表示するように指定します。


/FI フィルタ クエリによりフィルタして取り込むまたは
除外するイベントの種類を指定します。

/FO 形式 出力を表示する形式を指定します。
有効な形式は "TABLE"、"LIST" および
"CSV" です。

/R 範囲 一覧表示するイベントの範囲を指定します。
有効な値:
'N' - 最近の N 個のイベントを一覧表示します。
'-N' - 最古の N 個のイベントを一覧表示します。
'N1-N2' - N1 から N2 のイベントを一覧表示します。

/NH "列ヘッダー" が出力に表示されないように指定
します。
"TABLE" および "CSV" の形式にのみ有効です。

/L ログ名 照会するログを指定します。

/? このヘルプ/使用法を表示します。

有効なフィルタ 使用できる演算子 有効な値
------------- ------------------ ------------
DATETIME eq,ne,ge,le,gt,lt MM/dd/yy(yyyy),hh:mm:ssAM(/PM)
TYPE eq,ne SUCCESS, ERROR, INFORMATION,
WARNING, SUCCESSAUDIT,
FAILUREAUDIT
ID eq,ne,ge,le,gt,lt 負でない整数(0 - 65535)
USER eq,ne 文字列
COMPUTER eq,ne 文字列
SOURCE eq,ne 文字列
CATEGORY eq,ne 文字列

注意: フィルタ "DATETIME" は "開始日- 終了日" のように指定可能です。
この形式では "eq" 演算子のみ利用可能です。

例:
EVENTQUERY.vbs
EVENTQUERY.vbs /L system
EVENTQUERY.vbs /S system /U user /P password /V /L *
EVENTQUERY.vbs /R 10 /L Application /NH
EVENTQUERY.vbs /R -10 /FO LIST /L Security
EVENTQUERY.vbs /R 5-10 /L "DNS Server"
EVENTQUERY.vbs /FI "Type eq Error" /L Application
EVENTQUERY.vbs /L Application
/FI "Datetime eq 08/15/02,03:15:00AM-08/15/02,03:15:00PM"
EVENTQUERY.vbs /FI "Datetime gt 07/04/02,04:27:00PM"
/FI "Id gt 700" /FI "Type eq warning" /L System
EVENTQUERY.vbs /FI "Type eq error OR Id gt 1000 "

 

特に難しい使い方はしない、冒頭の日時の指定さえ迷わなければ問題ない。
とりあえず今日(2008年9/9)のイベントログを表示してみる。
コマンドプロンプトから、
>cscript %systemroot%\system32\eventquery.vbs /FI "Datetime ge 09/09/2008,12:00:00AM"

これで今日記録されたイベントログだけ出力される、これだけだと詳細は出ないしフォーマットはCSVではないけど。
eventquery.vbs は System32 においてあるので、cscriptから立ち上げるためフルパスで指定してます。
 
 

イベントログの詳細を含めてCSVにしたい場合


>cscript //nologo %systemroot%\system32\eventquery.vbs /FI "Datetime gt 09/09/2008,12:00:00AM" /V /FO CSV

"/V" で詳細込み、"/FO CSV" でCSVフォーマット指定と。後はこれをリダイレクトでファイルに落とせばOK。
"/FI" はフィルタ。条件を複数指定したいときは "/FI 条件1 and 条件2" と書いてもいいし、 "/FI 条件1 /FI 条件2" としてもOKみたい。or は前者でしか使えないかも、オプション複数は and だった。
 
 


追記:
前は上記の内容で 年/月/日 の指定を MM/DD/YY で書いていたが、Wshの仕様でYYが2桁だと正確な年にならない、詳しくはコメントで。
指摘を貰ったので本文修正しました。





 



 
しかし、過去記事を並べてみて思う。

  1. WindowsバッチファイルでYYYYMMDD で日付を文字列にして条件指定とファイル名に使う

  2. この記事の "eventquery.vbs" でイベントログを1日分ダンプする。

  3. Forfilesコマンドで古いログを自動で削除 する


アラ、これは便利なものができたかもしれない。ログローテーションバッチ。
普段使ってるのはVBScriptで書いてるけど、この流れならソラで書ける。
セキュリティ認証とかのため、とりあえずでよいからログの保管、というポリシーが必要な場合に片手間で仕込めますね。
 
 

丸々1日分のログをとる場合、日付が変わってからVBScriptなどで前日の文字列作成するのが普通なのかもしれないしそんなに手間でもないが、バッチでも次の方法でいけるかな?
 
タスクスケジューラで「毎日23:59」にバッチ開始、日付文字列を変数に格納してログファイル名やらをまず作成。
eventqueryの直前に、リソースキットだったかサポートツールだったかについてくる、
sleep 60」 で。
 

2008年7月24日木曜日

WindowsバッチファイルでYYYYMMDD

YYYYMMDD(hhmm)。
バッチファイル内でログファイルを出力するなら「これ+プリフィックス」をファイル名にするのが理想ではないでしょうか。
 
ちょっとバッチファイルで組み立てましょう、下記をテキストファイルに入力して拡張子をbatにします。
@echo off
set tmpDate10=%date:~-10%
set YYYYMMDD=%tmpDate10:/=%
echo %YYYYMMDD%

set tmpTime5=%time:~0,5%
set tmpTime4=%tmpTime5::=%
set HHMM=%tmpTime4: =0%
echo %HHMM%

echo %YYYYMMDD%%HHMM%
pause

 
変数"YYYYMMDD"は年月日、"HHMM"を時分として組み立てています。
実行すると下記、
20080723
2230
200807232230
続行するには何かキーを押してください . . .

この変数を使ってファイル名なり何なりを定義してしまえばいいのですが、
何でこんなにややこしくなってしまうのでしょうか。
一応続きで解説しておきます。

Windowsのバッチファイル、.bat, .cmd どっちを使うか

WindowsServerの運用管理においてバッチファイルは欠かせません。
集計、バックアップ、ファイルの転送やメール送信など手動でやるととても大変です。
 
さてバッチファイル、拡張子が".cmd"でも".bat"でもそれぞれ全く同じ動作をします。
それぞれ「Windows NT コマンド スクリプト」「MS-DOS バッチ ファイル」と定義されており、どう使い分ければよいのか。
結論から言うと…どっちでもよいようです。
 


[caption id="attachment_273" align="alignnone" width="150" caption="図:cmdファイルのプロパティ
クリックで拡大"]図:cmdファイルのプロパティ[/caption]

[caption id="attachment_276" align="alignnone" width="150" caption="図:batファイルのプロパティ
クリックで拡大"]図:batファイルのプロパティ[/caption]



 
cmdはWindowsNTで使い始めたらしいので昔は用途を分けるつもりでもあったのでしょうか、
しかし今日では全く区別されてないようです。
私は折角なので、バッチファイル群を自分が分かりやすくする為に使い分けています。