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

2009年6月12日金曜日

Windows PowerShell でイベントログをリアルタイム監視

The PowerShell Guy が教えてくれた、WindowsServerでイベントログをリアルタイムで監視する方法。
 
 


.Net FrameWorkで最新のイベントログをキャッチ


.Net FrameWork を使えるPowerShellなら、色々楽勝...といっても結局はWMIに問い合わせるみたい、某所で使っているイベントログ監視スクリプトはVBSで作ってあるけど、あれもWMIだったな。
 

ただ、system.management.ManagementEventWatcher クラスをいきなり使えるということでだいぶ違うように見える。
実はクラスとかあまり理解してないが、なんとも便利になったと思う。
 
 

PowerShellプロンプトでやってみる


イベントを待つには3行ですっきりOK、表示用にもう一行。
手っ取り早く効果を試せるので、下記をPSのプロンプトに張り付けてみる。

[sourcecode language='sh']$ew = new-object system.management.ManagementEventWatcher
$ew.query = "Select * From __InstanceCreationEvent Where TargetInstance ISA 'Win32_NTLogEvent'"
$e = $ew.WaitForNextEvent()
$e[/sourcecode]

ManagementEventWatcher パブリック メソッド の WaitForNextEvent() を使っている、張り付けたスクリプトはいったんここで止まる。
 

PS C:\>$ew = new-object system.management.ManagementEventWatcher
PS C:\>$ew.query = "Select * From __InstanceCreationEvent Where TargetInstance ISA 'Win32_NTLogEvent'"
PS C:\>$e = $ew.WaitForNextEvent()
PS C:\>$e
_←点滅カーソル


何かイベントが発生するまで待機するので、他のシェルからテスト用に eventcreate コマンドでイベントログを書き込み。
 

C:\>EVENTCREATE /T ERROR /ID 1000 /L APPLICATION /D "wait test"
 
成功: 種類が 'ERROR' のイベントが、'APPLICATION' ログ内に、'EventCreate' をソースとして作成されました。

 
すると、 $e に発生したイベントのオブジェクトが代入され、 直後で指定しているので $e が表示される
 

はい出た。
__GENUS : 2
__CLASS : __InstanceCreationEvent
__SUPERCLASS : __InstanceOperationEvent
__DYNASTY : __SystemClass
__RELPATH :
__PROPERTY_COUNT : 3
__DERIVATION : {__InstanceOperationEvent, __Event, __IndicationRelated, __SystemClass}
__SERVER :
__NAMESPACE :
__PATH :
SECURITY_DESCRIPTOR : {1, 0, 20, 128...}
TargetInstance : System.Management.ManagementBaseObject
TIME_CREATED : 128892011594751253

 

が、えらくメタな情報だな。
 
 

今回目的のイベントログは TargetInstance ってプロパティに格納されているので表示する、この辺はWMI。
PS C:\> $e.targetinstance
 
 
__GENUS : 2
__CLASS : Win32_NTLogEvent
__SUPERCLASS :
__DYNASTY : Win32_NTLogEvent
__RELPATH : Win32_NTLogEvent.Logfile="Application",RecordNumber=13539
__PROPERTY_COUNT : 16
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
Category : 0
CategoryString :
ComputerName : ********
Data :
EventCode : 1000
EventIdentifier : 1000
EventType : 1
InsertionStrings : {wait test}
Logfile : Application
Message : wait test
RecordNumber : 13539
SourceName : EventCreate
TimeGenerated : 20090********.000000-000
TimeWritten : 20090********.000000-000
Type : エラー
User : ********\sawano

 
OK、イベントソース、コードなど、おなじみのものが表示されている。
 
 



監視をループさせる


それではイベントログをリアルタイムで監視させる。
特に芸も無く、ループで回すだけだ。
[sourcecode language='sh']$a = 0

$ew = new-object system.management.ManagementEventWatcher
$ew.query = "Select * From __InstanceCreationEvent Where TargetInstance ISA 'Win32_NTLogEvent'"

do
{
$e = $ew.WaitForNextEvent()
$e.TargetInstance
}
while ($a -ne 1)
[/sourcecode]

While にずっと達成できない条件を指定して、ずっと回ってもらう。
 
これをPSプロンプトに流すと、Whlieの後で、カーソル点滅。 最後はDoの>>が消えるまでEnterの入力が必要。
 

--snip--
>> $e.TargetInstance
>> }
>> while ($a -ne 1)
>>
_←点滅カーソル

 

さて、この状況でほっといてみよう、EventCreateで試してもいい。
Vistaでやっていたら、意外と色々ログが上がって来て面白かった。
 
 

おわりに


さて、これをやってどうするか。
イベントをキャッチして、mixi や wassr に投稿するBotも捨てがたいが、通常は警告(Warning)、エラー(Error)もしくは特定のイベント発生を管理者に通知したい。
手段として妥当なところでは、メールだろうか。
 

今度はメール通知部分をくっつけてみよう、起動はタスクマネージャからだな。
 

2009年5月8日金曜日

PowerShellでDDNSサービスを更新(3)

PowerShellでDDNSサービスを更新(1)PowerShellでDDNSサービスを更新(2) 、の続き。
ddo.jp に対してPowerShell で更新をかけようというもの。
 
 

HTTPでクエリストリング付きのGETを送る


PowerShell から WebClient クラスを使ってクエリ文字列をくっつけたGETはどうすればいいのか。
 

単純にくっつけてみる



[sourcecode language='sh']# 引数格納、URL形式
param([string]$url)


# 途中で例外を吐いたらここに飛び、抜ける
trap [Exception] {
echo $error[0].exception
break
}


# クエリ文字列を作成
$query = "?dn=hoge.example.jp&pw=piyopiyo"


# .NetFramework の WebClient クラスを拝借
$webCli = New-Object System.Net.WebClient

# コンテンツを取得、無理やりくっつけてみる
$body = $webCli.DownloadString($url + $query)
[/sourcecode]

で、実行してHTTPで送られている内容をキャプチャ。※テストなのでhostヘッダが "sawano.members.icraft.jp"
GET /index.html?dn=hoge.example.jp&pw=piyopiyo HTTP/1.1
 
Host: sawano.members.icraft.jp
Connection: Keep-Alive


あら、これでも送れてるのね。
しかし釈然としない、WebClient クラスには QueryString とかいうプロパティがあるみたいので、それを使うのが普通っぽい。
 
 


WebClient.QueryString で


はて、QueryString を設定するにはどうしたらいいのかね。
連想配列で突っ込んでみたら、案の定怒られた。
[sourcecode language='sh']# 連想配列でクエリの内容を設定してみる
$query = @{dn = "hoge.example.jp";pw = "piyopiyo"}
$query

# .NetFramework の WebClient クラスを拝借
$webCli = New-Object System.Net.WebClient
$webCli.QueryString = $query[/sourcecode]
 

Name Value
---- -----
dn hoge.example.jp
pw piyopiyo
"QueryString" の設定中に例外が発生しました:
""System.Collections.Hashtable" を
"System.Collections.Specialized.NameValueCollection" に変換できません。"

 

ほう、左様か。NameValueCollection ってのを使えばいいの?
 

[sourcecode language='sh']# 引数格納、URL形式
param([string]$url)


# 途中で例外を吐いたらここに飛び、抜ける
trap [Exception] {
echo $error[0].exception
break
}

# NameValueCollection をマニュアル通り定義してみる
$query = New-Object System.Collections.Specialized.NameValueCollection

$query.add( "dn", "hoge.example.jp" )
$query.add( "pw", "piyopiyo" )


# .NetFramework の WebClient クラスを拝借
$webCli = New-Object System.Net.WebClient

# WebClient の QueryString プロパティを設定
$webCli.QueryString = $query

# コンテンツを取得
$body = $webCli.DownloadString($url)[/sourcecode]


で、実行とHTTPキャプチャ。
GET /index.html?dn=hoge.example.jp&pw=piyopiyo HTTP/1.1
 
Host: sawano.members.icraft.jp
Connection: Keep-Alive


できたようだ。
 
 
 

これでややこしそうなところは一通り準備がそろった。イベントログ書き出し・メールくらいは如何様にでもなろう。
 

終わりにしようかどうしようか。

2009年5月7日木曜日

PowerShellでDDNSサービスを更新(2)

PowerShellでDDNSサービスを更新(1) の続き。
ddo.jp に対してPowerShell で更新をかけようというもの。
 

IPアドレスが更新されているかチェック


毎回更新していると相手さんに負荷がかかるので、IPアドレスが登録時のものと変わっているかチェックする。
 
IPアドレスをゲットして、ローカルにおいたテキストに保存しつつ更新というシナリオ。
 

"get_ipandtest.ps1" というスクリプトを作成。
[sourcecode language='sh']# 引数格納、URL形式
param([string]$url)

# IPアドレスの書式を正規表現で定義しておく
$IPFmt = "^(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9]\.){3}(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])$"


# 途中で例外を吐いたらここに飛び、抜ける
trap [Exception] {
echo $error[0].exception
break
}

# テキストファイルに保存していたIPアドレスを取得
# なかったら0.0.0.0 などを突っ込む
if (Test-Path myAdd.txt) {
$testIP = Get-Content myAdd.txt -TotalCount 1 -encoding UTF8
} else {
$testIP = "0.0.0.0"
}

# テストIPのチェック用
echo $testIP

# .NetFramework の WebClient クラスを拝借
$webCli = New-Object System.Net.WebClient

# コンテンツを取得
$body = $webCli.DownloadString($url)

# 改行を消しちゃう
$body = $body -replace "`n", ""

# コロン区切りで配列に格納、DDOでは2つ目がIPアドレス
$ip = $body.split(":")



# IPアドレスの書式をチェック
if ($ip[1] -match $IPFmt) {
echo "IPアドレス ゲット成功デース"
} else {
Write-Output "ゲットシタモノハ IPアドレスデハ アリマセーン"
break
}

echo $ip[1]


# グローバルIPアドレスが変わったかどうかチェック
if ($ip[1] -eq $testIP) {
echo "IPアドレスハ カワッテマセーン"
} else {
Write-Output "IPアドレス カワッテマス、テキスト更新シマース"
$ip[1] | Out-File myAdd.txt -encoding UTF8
}
[/sourcecode]

echo と Write-Output が混ざっているのには特に意味はなく、両方できるんだなーというのを試している。
 
 

動作させてみる


初回動作では myAdd.txt がないので、0.0.0.0 を相手に比較。
 
 

PS > ./get_ipandtest.ps1 http://info.ddo.jp/remote_addr.php
0.0.0.0
IPアドレス ゲット成功デース
125.4.***.***
IPアドレス カワッテマス、テキスト更新シマース

 

2回目の動作では、myAdd.txt があるのでそれと比較してグローバルIPが変わっているかチェックさせる。
PS > ./get_ipandtest.ps1 http://info.ddo.jp/remote_addr.php
125.4.***.***
IPアドレス ゲット成功デース
125.4.***.***
IPアドレスハ カワッテマセーン

 

あとは クエリストリングつけて、HTTP で GET をするだけだ。
さらにつづく。

2009年5月1日金曜日

PowerShellでDDNSサービスを更新(1)

自宅に WindowsでWebサーバを立てる羽目 になりそうだが、ドメインもってません。
 

ダイナミックDNSサービスでも使うかと思うので、使い方を調べるため昔の同僚が使っていた、 ddo.jp を参照、HTTPでGETすれば更新できるとわかった。
ここをつかうならDiCE とか頼る必要ないな、手作りしてみよう。
 

仕組みを考えとく



  • 自分のとこのIPが変わってるか調べる

  • 変わってたらDDNS更新をかける

  • 更新の成功失敗はイベントログに書き込む

  • 更新成功時はメールも投げちゃう


と、こんな感じか。
 
 

とりあえず自分のIPゲット


DDO使うとしたらば、そこが提供しているIP確認のURLを使えばサービスの死活監視もできていいかも知れない。
 

PowerShellで指定したURLのコンテンツを出力してみる、エラーは全部止めちゃえばいいや。
# 引数格納、URL形式
param([string]$url)
 
# 途中で例外を吐いたらここに飛び、抜ける
trap [Exception] {
echo $error[0].exception
break
}
 
# .NetFramework の WebClient クラスを拝借
$webCli = New-Object System.Net.WebClient
 
# コンテンツを取得
$body = $webCli.DownloadString($url)
 
# コンテンツ出力
echo $body

と、こんなもん?実行してみる。
 

PS > ./get_ip.ps1 http://info.ddo.jp/remote_addr.php
 
 REMOTE_ADDR:125.4.***.***


うーむ微妙な出力...
ちょっと調整しよう。
 

# 引数格納、URL形式
param([string]$url)
 
# 途中で例外を吐いたらここに飛び、抜ける
trap [Exception] {
echo $error[0].exception
break
}
 
# .NetFramework の WebClient クラスを拝借
$webCli = New-Object System.Net.WebClient
 
# コンテンツを取得
$body = $webCli.DownloadString($url)
 
# コンテンツ出力
# echo $body
 
# 改行を消しちゃう
$body = $body -replace "`n", ""
 
# コロン区切りで配列に突っ込む
$ip = $body.split(":")
 
# 出力して確認
echo $ip[0]
echo $ip[1]

IPアドレス部分だけ切り出すように、文字列の操作をちょっと入れてみた。
 

PS > ./get_ip.ps1 http://info.ddo.jp/remote_addr.php
 REMOTE_ADDR
125.4.***.***


これで "$ip[1]" にIPアドレスが綺麗に入った。
ローカルにテキストで保管して、数時間おきに比較しよう。
 
 

つづく。

2008年7月24日木曜日

Windows、PowerShellでYYYYMMDD

YYYYMMDD(hhmm)。シリーズ。
ログファイルを出力するなら「これ+プリフィックス」をファイル名にするのが理想ではないでしょうか。
のPowerShell編。
 
PowerShellのプロンプトで、"Get-Date"コマンドを試してみます。
PS > Get-Date -format yyyyMMddHHmm
200807232230
終わってしまいましたね。
 
PS1(PowerShellのスクリプトファイル)で組み立ててみます、とりあえず下記を"yyyymmdd.ps1"で保存。$yyyymmdd = Get-Date -Format yyyyMMddHHmm
Write-Output $yyyymmdd
PS > .\yyyymmdd.ps1
200807232230
やっぱりこれで終わり、楽ですね。
特に解説する必要もなさそうです、まあLinuxでやると元々こんなもんですし。
 
 
"Get-Date"のヘルプを見ると、これでもかと言うくらい色々な形式を指定できます。
.NETフレームワークのライブラリ拝借、UNIX形式の組み込みと、後発なのをいいことにやりたい放題ですが、ちょっと不満が…
それはまた別の話で。2.0で解消されるかもしれないし。