PowerShell Advent Calendar 2011の第二回っす。
元ネタ:PowerShellでれっつログオン監査
システム間で連携を行うとき、いろいろな技術はありますが常々感じるのは、いまだに
「CSV最強伝説継続中!!」。
CSVの良さは、とりあえずテキストファイルで読めるし大概のシステムで読める、ということだと思います。
しかし、開発者は置いておいて、保守管理の人に言わせれば「CSVなんて大っ嫌い」という方も多いと思います。
ともかく、CSVはデータの羅列を各自が勝手に判断するため、以下のような特徴があります
・並び順が重要
・各列がなんのデータが分かりにくい
・データ形式によってはうまく取り込めない
誰かが勝手にデータデータを追加してたり、列の形式を変更してしまったらもうお手上げです。
CSVファイル自身にも先頭をタイトル行として何のデータかを管理したりするのですが、コレの手入れとメンテナンスはとても面倒です。
そこで、PowerShellのオブジェクトが大活躍します!!!
昔のバッチ風に書いてみましょう
---PS-Test1.ps1
Write-Host ID,Name -Separator ","
Write-Host 1,なかさん -Separator ","
Write-Host 2,ちゅき -Separator ","
---
これをリダイレクトしてCSVを作れます……(なんも良くないじゃないか!!!)
では、オブジェクトを作ってみましょう
--PS-Test2.ps2
$objArray = New-Object System.Collections.ArrayList
$objUsers = New-Object PSObject | Select-Object ID,Name
$objUsers.ID = 1
$objUsers.Name = "なかさん"
[void]$objArray.Add($objUsers)
$objUsers = New-Object PSObject | Select-Object ID,Name
$objUsers.ID = 2
$objUsers.Name = "ちゅき"
[void]$objArray.Add($objUsers)
$objArray
---
>PS-Test2.ps1
ID Name
-- ----
1 なかさん
2 ちゅき
----
で、これがどうしたいう話なのですが以下のように突っ込むと、そのままオブジェととして渡せて、しかもタイトル行のついたCSVをはいてくれるのですごい楽なんです。
CSVを作って中身を見てみる
そのまま、オブジェクトとして渡せたり出来る素晴らしさ!!!
_________________________
PS > $obj = .\PS-TEST2.ps1
_________________________
PS C:\Documents and Settings\manabe.COMTEST\デスクトップ> $obj | Export-Csv .\test.csv -Encoding UTF8
_________________________
PS C:\Documents and Settings\manabe.COMTEST\デスクトップ> Get-Content .\test.csv
#TYPE Selected.System.Management.Automation.PSCustomObject
"ID","Name"
"1","なかさん"
"2","ちゅき"
そして、このままCSVで列の名前を付けたままインポートを行うことができます。
CSVをインポートする
これはスゲー便利^^(なんったて、利用の時いちいち仕様書にらめっこしなくても、とりあえず読んでGet-Memberすれば何かわかる幸せ
_________________________
PS C:\Documents and Settings\manabe.COMTEST\デスクトップ> $objImportArray = Import-Csv -Path .\test.csv
_________________________
PS C:\Documents and Settings\manabe.COMTEST\デスクトップ> $objImportArray
ID Name
-- ----
1 なかさん
2 ちゅき
さて、これを一体何に使うのか…
で、これを一体何に使うかということですが、この前の監査ポイやつをこんな風にしておくと、後々楽だったりします
----PS-Test3.ps1
#保存用の配列
$objArray = New-Object System.Collections.ArrayList
#イベント取り込み
$objSecLog =Get-WinEvent -FilterXPath `
"Event[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] `
and (EventID='4624' or EventID='4634')] `
and EventData[(Data[@Name='LogonType']='2' or Data[@Name='LogonType']='10')]]"
#取り込んだだけループ
foreach($objEvent in $objSecLog ){
#保存したいデータを入れておくオブジェクト
$objEventItem = New-Object PSObject | Select-Object LogTime,EventID,IpAddress,DomainName,UserName,Message
#各イベントで共通の値を代入
$objEventItem.LogTime = $objEvent.TimeCreated
$objEventItem.EventID = $objEvent.id
#そのまま取り込めないため、XMLでゴニョゴニョ
$objXML = [xml]$objEvent.ToXML()
switch($objEventItem.EventID){
"4624"{
$objEventItem.IpAddress = (([xml]$objXML).Event.EventData.Data | ?{$_.Name -eq 'IpAddress'}).get_innerXML()
$objEventItem.DomainName = (([xml]$objXML).Event.EventData.Data | ?{$_.Name -eq 'TargetDomainName'}).get_innerXML()
$objEventItem.UserName = (([xml]$objXML).Event.EventData.Data | ?{$_.Name -eq 'TargetUserName'}).get_innerXML()
$objEventItem.Message = "ログオン"
}
"4634"{
$objEventItem.IpAddress = ""
$objEventItem.DomainName = (([xml]$objXML).Event.EventData.Data | ?{$_.Name -eq 'TargetDomainName'}).get_innerXML()
$objEventItem.UserName = (([xml]$objXML).Event.EventData.Data | ?{$_.Name -eq 'TargetUserName'}).get_innerXML()
$objEventItem.Message = "ログオフ"
}
}#EndSwitch
$objArray.Add($objEventItem)
}#Next
$objArray
----
ともかく、タイトル行とデータがずれないのだけでもすごく助かります。ともかく、エクスポートしたものをインポートできるという安心感は保守や管理者の大きな味方になってくれるはずです。