【Powershell】(サーバ保守)PingをPowershellでリスト化した端末へ実行する(Test-Connection)

【ツールの概要】
Powershellで、スクリプト内に記載したIPリストに疎通確認をします。
・参考サイトのソースや解説が非常に参考になります!←

【環境(使っている環境)】
Windows 10
Powershell ver5.1

【ソース(pingcheck.ps1)】

 #IPアドレスをリストで記載
[String[]]$addressAp = @"
xxx.xxx.xxx.xxx
xxx.xxx.xxx.xxx
"@ -split "`r`n"

$pingAlive = @(Test-Connection -ComputerName $addressAp -Count 1 -Quiet)

for($i = 0; $i -lt $pingAlive.Count; $i++) {
   if ($pingAlive[$i] -eq $True) {
       Write-Host ('Ping OK : '+ $addressAp[$i])
   } else {
       Write-Host ('Ping NG : '+ $addressAp[$i])
   }
}


【使用方法】
・上記のスクリプトに、疎通確認するIPをリスト的に記載します。
powershellで実行します。

【説明】
・Test-Connectionコマンドレットで各IPアドレス先の機器に疎通確認(PING)し、結果を画面出力します。

【総評】
1ファイルで完結するのはうれしいですが、powershellのTest-Connectionのレスポンスは必ずしも早くないです。
まあでもCount 1オプションを加えたことで許容範囲にもなってるかと思います。
リストを外部ファイルから読み込んで配列化して・・・なんてのも案外簡単そうです。
ですがそもそもそんなに管理する機器が多い組織なら運用管理システムくらい入れろっていう・・・←

【参考サイト】
社内SEの徒然なる日記 powerShellでpingを打ってみた
PowerShellでコード内に書いた複数行のテキストを手っ取り早く配列にする - Qiita
Test-NetConnection

【Powershell】(サーバ保守)フォルダ内ファイル内キーワード検索+圧縮+メール送信

【ツールの概要】
Powershellだけで、指定フォルダ内のファイルの中身(テキストファイル想定)を検索して、該当するファイルを圧縮してメール送信します。
Powershellで完結することを意識しています()

【環境(使っている環境)】
Windows Server2008
Powershell ver5.1以降(必須、Compress-archiveが効かない)

【ソース(WordCheck.ps1)】

Param( $targetcfgfile )

# ■■■■■ログfunction $MSG{INF,WRN,ERR,CRT etc..}■■■■■
function logwrite($MSG, $INFO, $NAME, $outoputfile) {
    $NOW = Get-Date -Format G
    Write-Output "[ $NOW ][ $MSG ][ $NAME ] $INFO" | Out-File -Append $outoputfile -encoding Default
}

# ■■■■■変数設定■■■■■
$CWD = Split-Path $MyInvocation.MyCommand.Path -parent
$WDCHKLOG = $CWD + "\log\WordCheck.log"
logwrite "INF" "This script start." "_________" $WDCHKLOG

# ■■■■■メール送信function読込(SendmailbyPS.ps1)■■■■■
$MAILPRG = $CWD + "\SendmailbyPS.ps1"
If (Test-Path $MAILPRG) {} else {
    logwrite "CRT" "SendmailbyPS.ps1 not existed." "_________" $WDCHKLOG
    exit -1
}
. ($MAILPRG)

# ■■■■■設定XML読込(引数パス)■■■■■
foreach ($pathdata in $([xml](Get-Content $targetcfgfile)).config.pathdata) {}
$logpattern = $pathdata.name
logwrite "INF" "xmlfile loaded.[$targetcfgfile]" $logpattern $WDCHKLOG

# ■■■■■検索対象フォルダファイルリスト作成■■■■■
$tarfilelist = $pathdata.tmpfilelist
Write-Output "" | Out-File $tarfilelist -encoding String
$nowArray = Get-ChildItem $pathdata.path -Name
Get-ChildItem $pathdata.path | Sort-Object { $_.LastWriteTime } | ForEach-Object -Begin {$array = @()} -Process { $array += $_.Name + "`t" + $_.LastWriteTime} -End { Write-Output $array | Out-File -Append $tarfilelist -encoding String}

# ■■■■■キーワードを含むログ抽出、コピー退避、配列格納処理■■■■■
$arrWDF = @()
for ($i = 0; $i -lt $nowArray.Length; $i++) {
    $tarfile = $pathdata.path + $nowArray[$i]
    $WRDFCount = (Select-String -path $tarfile -pattern $pathdata.keyword).Count
    if ($WRDFCount -gt 0) {
        # 退避フォルダにない場合の処理(新規ファイル)。$existcheckにはコピー先ファイルのフルパスが入る。
        $existcheck = $pathdata.sendfol + $nowArray[$i]
        If (Test-Path $existcheck) {} else {
            Copy-Item $tarfile -Destination $existcheck
            logwrite "INF" "File copied. This file contains `"$($pathdata.keyword)`" . File=$existcheck" $logpattern $WDCHKLOG
            $arrWDF += $existcheck
        }
    }
}

# ■■■■■異常ログzip圧縮・メール送信処理■■■■■
if ($arrWDF.Length -gt 0) {
    # ■■■■■(XML指定)zipparentpath直下のforCompressフォルダに対象ログをコピー■■■■■
    $forLocalCopy = $pathdata.zipinsidepath
    for ($i = 0; $i -lt $arrWDF.Length; $i++) {
        $localfname = $forLocalCopy + $(Get-ChildItem $arrWDF[$i]).Name
        Copy-Item $arrWDF[$i] -Destination $localfname
    }

    # ■■■■■ファイルをすべてzip化する■■■■■
    $zipfname = $pathdata.zipparentpath + $(Get-Date -UFormat "%Y%m%d%H%M") + $pathdata.keyword + '.zip'
    If (Test-Path $zipfname) {
        logwrite "CRT" "ZIPFile already existed. Machine Time was crasehd? Path=$zipfname" $logpattern $WDCHKLOG
    }
    else {
        $tarCmpFile = $forLocalCopy + $pathdata.filetype
        try {
            compress-archive -Path $tarCmpFile -DestinationPath $zipfname
        }
        catch {
            logwrite "CRT" "Files-compress Failed." $logpattern $WDCHKLOG
            $CompressResult = 'error'
        }
    }
    if ($CompressResult -eq 'error') {
        # ■■■■■メール送信処理(圧縮エラー時)■■■■■
        $Body = $pathdata.errbody
        $sendresult = SendmailbyPS $pathdata.address $pathdata.cc $pathdata.fromaddress $pathdata.subject $Body $tarfilelist $pathdata.mailxmlpath
        if ($sendresult -eq 'OK' ) {
            logwrite "INF" "Mail was sended. Attachmentfile=$tarfilelist" $logpattern $WDCHKLOG
        }
        else {
            logwrite "CRT" "Mail couldnot send. Errormessage=$sendresult" $logpattern $WDCHKLOG
        }
    }
    else {
        # ■■■■■メール送信処理(正常、キーワードファイル存在時)■■■■■
        $Body = $pathdata.body1 + $arrWDF.Length + $pathdata.body2
        $sendresult = SendmailbyPS $pathdata.address $pathdata.cc $pathdata.fromaddress $pathdata.subject $Body $zipfname $pathdata.mailxmlpath
        if ($sendresult -eq 'OK' ) {
            logwrite "INF" "Mail was sended. Attachmentfile=$zipfname" $logpattern $WDCHKLOG
        }
        else {
            logwrite "CRT" "Mail could not send. Errormessage=$sendresult" $logpattern $WDCHKLOG
        }
        # ■■■■■送信済ファイル削除(tmpフォルダのため)■■■■■
        del $tarCmpFile 
    }
}
else {
    logwrite "INF" "Target file contain taregt word is not existed." $logpattern $WDCHKLOG
}

logwrite "INF" "This script ended." $logpattern $WDCHKLOG

【ソース(SendmailbyPS.ps1)】

function SendmailbyPS($address, $Cc, $Fromaddress, $Subject, $Body, $attachment, $mailcfgpath) {
    $Mailconf_info = [xml](Get-Content $mailcfgpath)
    foreach ($data in $Mailconf_info.config.data) {}
    $MailSv = $data.MailSv
    $Port = $data.Port
    $Encode = $data.Encode
    $uid = $data.uid
    $pwd = $data.pwd
    $MailSv = $data.MailSv

    #Credential
    $pwd = $pwd | ConvertTo-SecureString -AsPlainText -Force
    $cred = New-Object System.Management.Automation.PSCredential $uid, $pwd

    #Send Mail
    try {
        Send-MailMessage `
            -To $address `
            -Cc $cc `
            -From $Fromaddress `
            -SmtpServer $MailSv `
            -Credential $cred `
            -UseSsl `
            -Encoding $Encode `
            -Port $Port `
            -Subject $Subject `
            -Body $Body `
            -Attachments $attachment
        $result = 'OK'
    }
    catch {
        $ErrorMessage = $_.Exception_Message
        $result = $ErrorMessage + $LASTEXITCODE
    }
    finally {
        echo $LASTEXITCODE
    }
    return $result
}

【設定ファイル(~~.xml)】

<?xml version="1.0"?>
<config>
  <pathdata>
    <name>ログ用の名前</name>
    <keyword>MAILER-DAEMON</keyword>
    <path>\\対象フォルダパス\</path>
    <sendfol>\\抽出ファイル格納パス\</sendfol>
    <tmpfilelist>D:\ローカルどこか\WordSearch\tmp\MDchecklist.txt</tmpfilelist> ←該当ファイルリスト出力用
    <zipparentpath>D:\ローカルどこか\WordSearch\tmp\</zipparentpath>  ←zipが吐かれてたまっていく場所です。
    <zipinsidepath>D:\ローカルどこか\WordSearch\tmp\forCompress\</zipinsidepath> ←zipにするために一時的にコピーされる場所です。
    <mailxmlpath>D:\ローカルどこか\WordSearch\etc\mailcfg.xml</mailxmlpath> ←SendmailbyPSのための設定ファイルの場所です。
    <filetype>*.txt</filetype> ←メールで送るファイルの種類です
    <address>メールTo</address>
    <cc>メールCc</cc>
    <fromaddress>メールFromt</fromaddress>
    <subject>メール件名</subject>
    <body1>なんちゃら's mail was recieved because the sent e-mail was something wrong. There are </body1> ←メール本文1です(文法気にしないで)
    <body2> mails found as alert mails.</body2>
    <errbody>Compress error</errbody>
  </pathdata>
</config>

【使用方法】
・上記のスクリプトおよび設定ファイルは、MAILER-DAEMONを検索するために作られたので、そんな感じになっています。
・ps1ファイルは2つ同じ場所におき、powershell.exe -Command (フルパス)WordCheck.ps1 (フルパス)設定xmlでタスクに登録したりします。

【説明】
・ログは一つです。
・初心者にはちょっと厳しいです。また、よくないところもあるかと思います。(変数の多用とか命名とか)

【総評】
このスクリプトはあるフォルダ内にはテキストファイルがたまに吐かれるけれども、そのファイルの中身でアラートを発したいというのがきっかけでした。
質問などは適当にしてくださったら適当に答えると思います!ちなみに一番頑張ったのはこ↑こ↓
Get-ChildItem $pathdata.path | Sort-Object { $_.LastWriteTime } | ForEach-Object -Begin {$array = @()} -Process { $array += $_.Name + "`t" + $_.LastWriteTime} -End { Write-Output $array | Out-File -Append $tarfilelist -encoding String}

【PowerShell】(サーバ保守)イベントログのログオン履歴抽出②(Get-WinEvent)

【ツールの概要】
・イベントログを項目指定して抽出CSVに書き出すスクリプトその②
・内容をもう少し精査しました。


【環境(使っている環境)】
Windows server 2016(各文献には2008R2以降と書いてあるっぽい)
Powershell ver2.0以降?(公式が見当たらないけどおそらく)


【ソース(get_eventlog_ver2.ps1)】

$MESSAGES = get-winevent  `
    -logname security  `
    -FilterXPath  `
        "Event [ `
            System [ `
                Provider [@Name='Microsoft-Windows-Security-Auditing'] `
                and ( `
                    EventID='4624'  `
                    or EventID='4625' `
                    or EventID='4634'  `
                    or EventID='4648'  `
                ) `
            ] `
        ]"

$MESSAGES | ForEach {
    if ( $_.id -eq "4624" ) { 
        $_ | Select-Object timecreated, Id, `
        @{Name = "TargetLogonId"; Expression = {$_.properties[5].value}}, `
        @{Name = "TargetDomainName"; Expression = {$_.properties[6].value}}, `
        @{Name = "TargetUserSid"; Expression = {$_.properties[4].value}}, `
        @{Name = "IpAddress"; Expression = {$_.properties[18].value}}, `
        @{Name = "Message"; Expression = {$_.Message.Substring(0,18)}} 
    }
    elseif ( $_.id -eq "4625" ) {
        $_ | Select-Object timecreated, Id, `
        @{Name = "TargetLogonId"; Expression = {$_.properties[5].value}}, `
        @{Name = "TargetDomainName"; Expression = {$_.properties[6].value}}, `
        @{Name = "TargetUserSid"; Expression = {$_.properties[4].value}}, `
        @{Name = "IpAddress"; Expression = {$_.properties[19].value}}, `
        @{Name = "Message"; Expression = {$_.Message.Substring(0,18)}}        
    }
    elseif ( $_.id -eq "4634" ) {
        $_ | Select-Object timecreated, Id, `
        @{Name = "TargetLogonId"; Expression = {$_.properties[1].value}}, `
        @{Name = "TargetDomainName"; Expression = {$_.properties[2].value}}, `
        @{Name = "TargetUserSid"; Expression = {$_.properties[0].value}} , `
        @{Name = "IpAddress"; Expression = "-" }, `
        @{Name = "Message"; Expression = {$_.Message.Substring(0,15)}} 
    }
    elseif ( $_.id -eq "4648" ) {
        $_ | Select-Object timecreated, Id, `
        @{Name = "TargetLogonId"; Expression = {$_.properties[5].value}}, `
        @{Name = "TargetDomainName"; Expression = {$_.properties[6].value}}, `
        @{Name = "TargetUserSid"; Expression = {$_.properties[4].value}} , `
        @{Name = "IpAddress"; Expression = "-" }, `
        @{Name = "Message"; Expression = {$_.Message.Substring(0,26)}} 
    }
} | Export-Csv -Encoding UTF8 -path c:\syslog.csv

 

【使用方法】
・ソースをメモ帳なりで記述し拡張子を「.ps1」にして保存します。
・管理者権限でpowershellにて実行します。(イベントログSecurityカテゴリには管理者権限要)


【説明】
パート1と比べて・・
・取得するイベントIDを増やしました。(明示的な云々~(イベントID4648)を追加)
・出力内容を少し便利にしました。(domainname、SID、IP、メッセージ内容を追加)
あと、イベントIDごとに、取得するメッセージの長さを地味に調整しています。

 
【総評】
FilterXPathのところで期間をとれるようにすれば、タスクで実行できそうですね。
まあ頻度を細かくするならイベント設定しろよ的な話になるので、あくまで統計用ですかね。
 

【参考リンク】
パート①を参照してください。
【PowerShell】(サーバ保守)イベントログのログオン履歴抽出、CSV化(Get-WinEvent) - うまく動けばいいな!

【bat、Powershell】(サーバ保守)ディスク容量監視、メール送信

【ツールの概要】
・batとPowerShellでサーバの容量を定時チェックしてメールで内容を見ようというもの。
・bat内でJavaScriptを利用しています。(参考ページの記事に感謝!)

【環境(使っている環境)】
・Windows10Pro or Windows Server2012
Powershell ver2.0以降


【ソース(CapChStart.bat)】

@echo off 
cd /d %~dp0

SET WKFOL=%~dp0
SET LOGFILE=%WKFOL%GetCapMail.log
SET OUTPUT=%WKFOL%GetCap.txt
SET GETPRG=%WKFOL%CapCheck.bat
SET PSFILE=%WKFOL%CapacitySendMail.ps1

REM 出力ファイル確認
If not exist %LOGFILE% ( echo. > %LOGFILE% )
If not exist %OUTPUT% ( echo. > %OUTPUT% )

Call %GETPRG% > %OUTPUT%

Timeout /T 2

echo %ERRORLEVEL% >> %LOGFILE%
REM 出力結果をPowershellで読込み送信する
powershell -ExecutionPolicy RemoteSigned -Command "%PSFILE% %OUTPUT%"

 
【ソース(CapacitySendMail.ps1)】

#param
Param($Bodyfilepath)
$scriptPath = $MyInvocation.MyCommand.Path
$To = "~宛先~"
$From = "~ふろむ~"
$Cc = "~しーしー~"
$Body=(Get-Content -Path $Bodyfilepath) -join "`r`f"

$todayymd=Get-Date -Format "yyyyMMdd"
$Subject = [string]::Concat("[SERVER03] Disk Capacity Report ", $todayymd)
$MailSv = "~SMTPサーバパス~"
$Port = 2525 #これも例
$userId = "~SMTPサーバID~"
$pwd = "~SMTPサーバパスワード~" | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential $userId,$pwd
$Encode = [System.Text.Encoding]::UTF8
$scriptfol = Split-Path $MyInvocation.MyCommand.Path -Parent
$logfile = $scriptfol+ "\SendCapMail.log"

try{
#Send Mail
Send-MailMessage `
    -To $To `
    -From $From `
    -Cc $Cc `
    -SmtpServer $MailSv `
    -Credential $cred `
    -UseSsl `
    -Encoding $Encode `
    -Port $Port `
    -Subject $Subject `
    -Body $Body `
    -ErrorAction stop

$Now=Get-Date -Format "yyyy/MM/dd_HH:mm:ss"
echo `r`nDate`t$Now,Body`t$Body | Add-Content $logfile -Encoding UTF8

}catch{
$Now=Get-Date -Format "yyyy/MM/dd_HH:mm:ss"
echo `r`nDate`t$Now | Add-Content $logfile -Encoding UTF8
$error[0] | Out-String | Add-Content $logfile -Encoding UTF8
}

【使用方法】
・CapCheck.batを上記二つのほかに作成し、下記参考リンク先のbat本文を丸々保存します。
・3つのスクリプトを全て同じフォルダに置き、CapChStart.batを引数なしで実行します。

【説明】
・それぞれログが吐かれます。一番必要な情報はSendCapMail.logに吐かれていると思います。
・あとはこれをタスクスケジューラに登録すると。
Powershellのコードは以前より使っているモノのアレンジです。

【総評】
サーバ(簡易的なファイルサーバ)の容量監視は中々これといったものがない。
有料ツールとか使えば、閾値超えたらメールとかできるのですが、なかなか政治的に難しかったり。
また以下コマンドでもそれぞれの容量は取れなくはないです。うまく使えばjavascriptに頼らなくていいかも?でも素晴らしいコードがあったのでつい←感謝

wmic logicaldisk list brief 

【参考リンク】
Windowsでディスク使用率等の一覧を出力するバッチファイルを書いた - hogehoge @teramako

【PowerShell】(PCメンテナンス用)メール送信②

【ツールの概要】
・メールを送信するPowerShellスクリプトその②。
 1はこれ↓
 【PowerShell】(PCメンテナンス用)メール送信 - うまく動けばいいな!
・より汎用的にしました。


【環境(使っている環境)】
・Windows10Pro
Powershell ver2.0以降
 ※他のWindowsでも動くか→7以降なら動くと思われる。


【ソース(sendmailtest.ps1)】

#param
Param($fromaddress,$Totemp,$Cctemp,$Bcctemp,$MailSv,$Port,$userId,$pwd,$Subject,$Bodyfilepath)
$scriptPath = $MyInvocation.MyCommand.Path
$To = $Totemp -split ","
$Cc = $Cctemp -split ","
$Bcc = $Bcctemp -split ","

#本文整形
$Body=(Get-Content -Path $Bodyfilepath) -join "`r`f"

$pwd = $pwd | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential $userId,$pwd
$Encode = [System.Text.Encoding]::UTF8

Send-MailMessage `
    -To $To `
    -From $fromaddress `
    -Cc $Cc `
    -Bcc $Bcc `
    -SmtpServer $MailSv `
    -Credential $cred `
    -UseSsl `
    -Encoding $Encode `
    -Port $Port `
    -Subject $Subject `
    -Body $Body 

$scriptfol = Split-Path $MyInvocation.MyCommand.Path -Parent
$logfile = $scriptfol+ "\SendmailPS.log"
$Now=Get-Date -Format "yyyy/MM/dd_HH:mm:ss"

#要素数取得(一つの場合文字列長取得)
$fromlen=$fromaddress.Length
$Tolen=$To.Length
$Cclen=$Cc.Length
$Bcclen=$Bcc.Length

#ログ出力
echo `r`nDate`t$Now,from`t$fromlen`t$fromaddress,To`t$Tolen`t$To,Cc`t$Cclen`t$Cc,Bcc`t$Bcclen`t$Bcc,MSV`t$MailSv,Port`t$Port,Sub`t$Subject,Body`t$Body | Add-Content $logfile -Encoding UTF8

 

【使用方法】
・paramを参考に送信に必要な設定をすべて引数で指定します。
・本文は$Bodyfilepathにファイルを置きその中に記載します。
・ログもどきがスクリプトと同じ場所に出力します。
・from、to、cc、bcc、を複数指定するときはダブルクォーテションで括り、カンマで区切ります。
 カンマ区切りをスクリプト内で配列に変換(Split)します。


【説明】
・本文を外部ファイル化することで動的に。改行にも対応します。
・複数宛先の指定も「使用方法」のとおり簡単です。
・Portやサーバが固定ならそれも外部ファイル化できます。
・Bodyfilepathと同じ要領で添付ファイル($attachment)も追加できます。
 

【総評】
他のプログラムなどから柔軟に呼び出せるようにしました。
powershellwshから呼び出せるので便利。
例えばこんな感じですね(VBA。変数命名については勘弁してください←)。

'引数を指定(内容は察してください、f_path以外は変数そのまま送るイメージ)
strmailP = fromadd & " " & toadd & " " & ccadd & " """ & strBccAdd & """ " & smtpSV & " " & port & " " & UserID & " " & Password & " '" & mailtitle & "' '" & f_path & "'" & " 0"
Set Wsh = CreateObject("Wscript.shell")
strPath = ThisWorkbook.Path & "\mailsend.ps1"
wrunexec = Wsh.Run("powershell -ExecutionPolicy RemoteSigned " & strPath & " " & strmailP, 0, True)

・・・横に長い。

【PowerShell】(サーバ保守)イベントログのログオン履歴抽出、CSV化(Get-WinEvent)

【ツールの概要】
・イベントログを項目指定して抽出CSVに書き出すスクリプト
・イベントログのプロパティとGet-Wineventコマンドレットに闇が多すぎて理解しきれてないので、この記事は半分メモを兼ねています。


【環境(使っている環境)】
Windows server 2016(各文献には2008R2以降と書いてあるっぽい)
Powershell ver2.0以降?(公式が見当たらないけどおそらく)


【ソース(get_eventlog.ps1)】

$MESSAGES = Get-WinEvent  `
    -logname security  `
    -FilterXPath  `
        "Event [ `
            System [ `
                Provider [ `
                    @Name='Microsoft-Windows-Security-Auditing' `
                ] `
                and ( `
                    EventID='4624'  `
                    or EventID='4625' `
                    or EventID='4634'  `
                ) `
            ] `
        ]"

$MESSAGES | foreach {
    if ( $_.id -eq "4624" ) {
        $_ | select timecreated,Id,@{Name="TargetLogonId";Expression={$_.properties[5].value}}
    } elseif ( $_.id -eq "4625" )  {
        $_ | select timecreated,Id,@{Name="TargetLogonId";Expression={$_.properties[5].value}}
    } elseif ( $_.id -eq "4634" )  {
        $_ | select timecreated,Id,@{Name="TargetLogonId";Expression={$_.properties[4].value}}
    }
} | Export-Csv -Encoding UTF8 -path c:\syslog.csv

 

【使用方法】
・ソースをメモ帳なりで記述しhoge.ps1で保存します。
・管理者権限でpowershellにて実行します。(イベントログSecurityカテゴリには管理者権限要)


【説明】
・前半のget-wineventでイベントを抽出しMESSAGEに格納しています。
Microsoft-Windows-Security-Auditingイベントデータをand条件(ここではEventID)で抽出します。他の条件を足すときはandで追加。
・後半のforeachからは変数を展開しています。ここではEventIDでログオンユーザ名のプロパティ位置が変わるため、ifで分岐しています。
・パイプでExportCSVで指定の場所に出力します。(「ConvertTo-Json」とか指定なしで画面出力とかも出来るっぽいです。)
Windowsイベントログは、イベントビューアの詳細-XMLで確認できる通り大きく2つの項目に分かれていて、
 後者「EventData」を取得したい場合は取りたい項目が何番目かを把握していないといけないっぽいですね。
 取りたい項目が多い場合は一度全部XMLで取得してから処理なんてのもよいかもです。。
 

【総評】
参ったのが、これが必要になったけども急ぎの用であまり凝る時間がなかったため、出力されるデータとしてはそっけなくなてしまった点です。
おそらくイベントログのデータはあらかた取れると思うので、例えばログオン試行されたIPアドレスとかも抽出できそうですね。
Windowsのイベントログは通知機能なども付いているので、カスタマイズしたいときとかに使うと吉。
 

【参考リンク】
Get-WinEvent

Get-wineventで抽出したログから、IDによって参照するフィールドを分けて表示させる方法

[PowerShell] HEY YOU WHAT’S YOUR NAME?アクセスしてるのはお前さBABY!アカウント名をセキュリティログから取るぜ! – 管理者は見た!~AD と ILM 一家の秘密~

PowerShell でイベントログを JSON 出力する - Qiita

WindowsのEventLogをいろいろ取得してみる(EventLog→Syslogサーバ その2) - Qiita

Powershellによるログオンとログオフ情報のcsvファイル出力 - My Tracking

【bat】PSEXECを利用して特定セグメントのPING応答のあったIPへarpコマンドを実行させる。

【コマンド、ツールの概要】
・bat内で設定した変数をもとに対象セグメント(もどき。IPv4アドレス第4オクテットを探索)に対しpingを投げまくり、
 応答のあったIPアドレスにPSEXECで接続しarp-aを打たせることでネットワーク内のMACアドレスを確認しよう、というスクリプト
・bat内変数で処理の設定を行うため、読める人が管理して実行することが推奨←


【環境(使っている環境)】
条件は過去記事参照。


【コマンド例】

SETLOCAL ENABLEDELAYEDEXPANSION

SET TARSEG=192.168.60.
SET STARTIP=2
SET ENDIP=253
SET WAITTIME=30
SET COUNT=0
SET SEGNO=%TARSEG:~8,-1%
SET PINGRES=c:\temp\pingarp_seg%SEGNO%.txt
SET ARPRES=c:\temp\arp_result_seg%SEGNO%.txt

SET PSEUSER=[管理ユーザ名を括弧閉じとかせずに記載]
SET PSEPASS=[管理ユーザのパスワードを括弧閉じとかせずに記載]

ECHO.
ECHO 処理中は本画面をクリック等しないでください。
ECHO (万が一した場合は[ESC]にて復帰してください。その場合結果が出力されないことがあります。)

ECHO.
ECHO 対象セグメント:%TARSEG%
ECHO IP調査中。調査範囲:%STARTIP%%ENDIP% 応答猶予:%WAITTIME%ミリ秒
ECHO. > %PINGRES%
ECHO. > %ARPRES%

REM 疎通可能IPの特定が必要なので、pingを打ってレスポンスを記録
FOR /L %%A IN (%STARTIP%, 1, %ENDIP%) DO CALL :sub %%A

FOR /F "tokens=1-2*" %%a IN (%PINGRES%) DO (
	ECHO %%a%%b%%c | FIND "からの応答" > NUL
	IF !ERRORLEVEL! equ 0 (
		SET /a COUNT=!COUNT!+1
		SET TARGETIP!COUNT!=%%a
	)
)
ECHO.
ECHO 反応したIPは以下の %COUNT%つ です。この後各IPへPSEXECにて接続します。
FOR /L %%A IN (1, 1, %COUNT%) DO ECHO !TARGETIP%%A!
TIMEOUT /T 2

ECHO 反応のあったIP >> %ARPRES% 
FOR /L %%A IN (1, 1, %COUNT%) DO ECHO !TARGETIP%%A! >> %ARPRES%

REM リモートでネットワーク内IP×MAC一覧を取得。ping記録からレスポンスあったIPのうち最後のIPを利用。
FOR /L %%A IN (1, 1, %COUNT%) DO PSEXEC -u !TARGETIP%%A!\%PSEUSER% -p %PSEPASS% \\!TARGETIP%%A! cmd /c "arp -a" >> %ARPRES%

ECHO 出力しました。処理を終了します。
ECHO 出力ファイル:%ARPRES%
TIMEOUT /T 5
EXIT /B

:sub
PING %TARSEG%%1 -n 1 -w %WAITTIME% >> %PINGRES% 2>&1
(SET <NUL /p="%1 ")|

【使用方法】
・(念のため管理者権限で)ローカル実行します。(管理者権限無くても行けると思いますが、、。)
・出力ファイルが「PINGRES」「ARPRES」にそれぞれ出力されます。


【説明】
まずは変数の説明。

TARSEG 調査したいセグメント(第3オクテットまで指定)
STARTIP 調査したいセグメントの開始IP(第4オクテットの開始IP)
ENDIP 調査したいセグメントの開始IP(第4オクテットの終了IP)
WAITTIME PINGの待ち時間指定。250回のPINGをすべてデフォルト(4秒)近く待つと1000秒とかやってらんないので。)
COUNT ループ変数
SEGNO 第3オクテットの切り出し(社内的事情←)
PINGRES PINGの結果ログ
ARPRES PINGレスポンスのあったIP列挙とarpの結果を記載したログ
PSEUSER PSEXECで使う管理ユーザ(一つ)
PSEPASS PSEXECで使う管理ユーザのパスワード

諸々解説。

FOR /L %%A IN (%STARTIP%, 1, %ENDIP%) DO CALL :sub %%A

まずfor文で、指定したIP範囲内IPごとにsubルーチンを呼び出します。

PING %TARSEG%%1 -n 1 -w %WAITTIME% >> %PINGRES% 2>&1
(SET <NUL /p="%1 ")|

pingを対象IPに指定の待ち時間で打ちつつ、ログに出力します。
同時に、SET行で画面に処理中の数値(第4オクテットの番号)を表示します。
これをforで回すことで、プロンプト画面でビジュアル的に処理が進んでいることがわかります。
(画面に「2 3 4 5 ・・・」みたいに数字が並んでいきます)

FOR /F "tokens=1-2*" %%a IN (%PINGRES%) DO (
	ECHO %%a%%b%%c | FIND "からの応答" > NUL
	IF !ERRORLEVEL! equ 0 (
		SET /a COUNT=!COUNT!+1
		SET TARGETIP!COUNT!=%%a
	)
)

for /fを使い、PINGのログファイルをfindで一行ずつ検索します。
応答があったIPをTARGETIP!COUNT!変数に格納します。
要するにTARGETIPは疑似配列?みたいな感じになっています。
(正しく言おうとするならTARGETIP0、TARGETIP1とか個々の変数が作られる。batはここが独特だけど分かれば意外に便利でもある。)

FOR /L %%A IN (1, 1, %COUNT%) DO PSEXEC -u !TARGETIP%%A!\%PSEUSER% -p %PSEPASS% \\!TARGETIP%%A! cmd /c "arp -a" >> %ARPRES%

for文でPSEXECを対象IPに打っていき、結果をarp出力ファイルに出力します。
例えば1番目に192.168.0.2のIPが反応した場合、forループの中で実際は下記コマンドが実行されます。
(FOR /L 1 IN (1, 1, 1) DO )PSEXEC -u 192.168.0.2\[指定ユーザ名] -p [指定ユーザパス] \\192.168.0.2 cmd /c "arp -a" >> c:\temp\arp_result_seg0txt


【総評】
個人的にfor文のいい勉強になりました(ぇ
ENABLEDELAYEDEXPANSIONが有効活用されていますね←
pingログの出力が不要ならメモリ展開して2番目の処理とかが早くはなりそうですが、微々たるもんでしょう。。
PSEXECのarpの部分をmsgとかにするとか悪いこと考えたらいけませんね()
メモ帳ならログファイルを開いても一瞬しか権限奪わないと思うので、実行したあとログをみるのが当bat理解への早道かと思います。
 

【参考リンク】
.bat(バッチファイル)のforコマンド解説。 - Qiita