Short question: How do I run through an object array, group them by unique values in properties, then iterate through the array based on those groups (which are nested groups btw) to generate reports? Don’t need a code solution, just some design help.
Long question:Using the following object array of log events, how do I iterate through it to create reports based on both devices and sites? There are multiple log events (objects) per device, and multiple devices per site. Here’s how it was made:
$SyncCompletePattern = "Synchronization Complete" $SyncStartPattern = "Starting to sync" $SyncFailPattern = "Synchronization Failed" $SyncLog = Get-Childitem -Path C:\Users\igarvin\Documents\Logs\*\*\device*.log -Recurse | Select-String -Pattern $SyncCompletePattern, $SyncFailPattern, $SyncStartPattern $data = $(switch -Regex ($SyncLog) { "(?<=\\)Site\d{2}(?=\\)" { $site = $Matches[0] } "(?<=\\)\d{8}(?=\\)" { $device = $Matches[0] } "\d{2}/\d{2} \d{2}:\d{2}:\d{2}:\d{3}" { $timestamp = [datetime]::ParseExact($Matches[0],"MM/dd HH:mm:ss:fff",$null) } "(?<=^.*? \d ).*$" { $message = $Matches[0] } "^.+$" { New-Object PSObject -Property @{ Timestamp = $timestamp Timespan = $timespan Message = $message Device = $device Site = $site } } })
Sample output:
PS C:\Users\igarvin> $data[1..3] Device : 00606049 Timespan : Timestamp : 6/2/2015 4:50:46 PM Site : Site02 Message : Synchronization complete. Device : 00606049 Timespan : Timestamp : 6/26/2015 1:27:09 PM Site : Site02 Message : Starting to sync... Device : 00606049 Timespan : Timestamp : 6/26/2015 1:27:10 PM Site : Site02 Message : Synchronization complete.
I want to:
- Create both device specific reports and site reports, both that cover how many "sync events" occurred (sync starts) and display their results.
- Fill in timespan properties of objects with completion times for syncs
- Add averages of timespans to such reports
I’ve been trying to do it but it’s become an ugly nested loop nightmare, repeating operations several times. Here’s what I have so far:
$SiteList = $data.Site | Get-Unique $DeviceList = $data.Device | Get-Unique foreach ($s in $SiteList) { foreach ($d in $DeviceList) { for ($i=1; $i -lt $data.Length; $i++) { if (($data[$i].Device -eq $d) -and ($data[$i].Site -eq $s)) { if(($data[$i].Message -match "Starting to sync") -and ($data[$i+1].Message -match "Synchronization Complete")) { $y = New-Timespan -Start $data[$i].TimeStamp -End $data[$i+1].TimeStamp $data[$i].TimeSpan = $y $SuccessCount++ } if(($data[$i].Message -match "Starting to sync") -and ($data[$i+1].Message -match "Synchronization failed")) { $data[$i].TimeSpan = "Failed" $FailCount++ } if($data[$i].Message -match $CheckinTimePattern) { $CheckInCount++ } } } $SiteSuccessCount += $SuccessCount $SiteFailCount += $FailCount $SiteCheckinCount += $CheckinCount $DevSyncPath = "C:\Users\igarvin\Documents\Logs\$s\SyncLog$d.csv" #$DevTimespanAvg = ($data | Where-Object {$_.Device -eq $d} | Measure-Object -Property Timespan -Average).Average $data | Where-Object {$_.Device -eq $d} | Export-Csv -Path $DevSyncPath -NoTypeInformation Add-Content -Path $DevSyncPath -Value "`n`n`nCheckins`n$CheckinCount`n`nSync Average`n`n`nSuccesses, Failures`n$SuccessCount, $FailCount" $CheckinCount = $null $SuccessCount = $null $FailCount = $null } $SiteSyncPath = "C:\Users\igarvin\Documents\Logs\SyncLog$s.csv" #$SiteTimeSpanAvg = ($data | Where-Object {$_.Site -eq $s} | Measure-Object -Property Timespan -Average).Average Add-Content -Path $SiteSyncPath -Value "Checkins, Sync Average, Successes, Failures`n$SiteCheckinCount, , $SiteSuccessCount, $SiteFailCount" -Force }
I know where i’m going wrong with this, but I don’t know what the correct solution is in order to loop based on group (nested groups even) and not repeat stuff unnecessarily. I don’t need someone to code a solution but to tell me the direction I need to go to design one.