Generate HTML/PDF Summary of App Crash/Hangs via PowerShell

This script can be pointed at a list of servers in a text file, and the Event logs are scanned for application hang/crash events. The Windows Application hang event only occurs when an app hangs and user terminates the program. Also if werfault.exe is prevented from running, these event logs won’t be generated. (Windows Error Reporting disabled is OK, I am referring to actually preventing the EXE from running)

Example PDF report: https://onedrive.live.com/redir?resid=E1A3C870740A073D!19859&authkey=!AMDWrh0d5EidnkI&ithint=file%2cpdf

Script can be downloaded here: https://onedrive.live.com/redir?resid=E1A3C870740A073D!23156&authkey=!AGQdN-cPbNXJs2A&ithint=file%2czip

This script requires:

The parameters:

customer – Specify a customer name or description

reportFolder – Path to save HTML/PDF to

NumberOfDays – How many days back to report (default 30)

serverList – If blank will be local computer. Otherwise a text file with list of computers, or a CSV file with

two columns if you want to add a description of computer in 2nd column

reportFormat – default is PDF. Anything else will export in HTML

timeToLiveSeconds – The ping time to wait before skipping computer. Default 1 second

eventLogTimeOutSeconds – The time to wait for remote event log to respond before skipping computer

cleanUpImages – Default is TRUE. Deletes the PNG chart images created.

Note: The PIE charts don’t show items <5% this can be changed by modifying [“CollectedThreshold”]=5

<# .Synopsis Generates a PDF or HTML report of application hangs/crashes in event logs. .Notes AUTHOR: chentiangemalc LASTEDIT: Sept. 11, 2014 KEYWORDS: App Crash HTML Reporting .Link http://chentiangemalc.wordpress.com #Requires -Version 3.0 #> [CmdletBinding()] Param( [string]$customer = “”, [Parameter(Mandatory=$true)] [string]$reportFolder, [int]$NumberOfDays = 30, [string]$serverList =“”, [string]$reportFormat=PDF, [int]$TimeToLiveSeconds=1, [int]$EventLogTimeOutSeconds=1, [switch]$cleanUpImages = $true ) # Load .NET Chart Controls http://www.microsoft.com/en-us/download/details.aspx?id=14422 [void][Reflection.Assembly]::LoadWithPartialName(System.Windows.Forms.DataVisualization) # reporting time period $timespan = NewObject System.TimeSpan($NumberOfDays,0,0,0) # current directory – used later to launch PDF generator $curDir=SplitPath Parent $MyInvocation.MyCommand.Definition # build our report name if (![String]::IsNullOrEmpty($customer)) { $reportName = [String]::Format($customer-AppCrash-{0:yyyy-MM-dd_hh-mm-ss-tt},[DateTime]::Now) } else { $reportName = [String]::Format(AppCrash-{0:yyyy-MM-dd_hh-mm-ss-tt},[DateTime]::Now) } # Built our XPath format Event Log Queries # We will later replace milliseconds field with how far back we want to go $xpath_hang = @‘ <QueryList> <Query Id=0 Path=Application> <Select Path=Application> *[System[Provider[@Name=‘Application Hang’] and (EventID=1002) and TimeCreated[timediff(@SystemTime) &lt;= milliseconds ]]] </Select> </Query> </QueryList>@ $xpath_crash = @‘ <QueryList> <Query Id=0 Path=Application> <Select Path=Application> *[System[Provider[@Name=‘Application Error’] and (EventID=1000) and TimeCreated[timediff(@SystemTime) &lt;= milliseconds]]] </Select> </Query> </QueryList>@ $xpath_reboot = @‘ <QueryList> <Query Id=0 Path=System> <Select Path=System> *[System[(EventID=6005) and TimeCreated[timediff(@SystemTime) &lt;= milliseconds]]] </Select> </Query> </QueryList>@ $xpath_critical = @‘ <QueryList> <Query Id=0 Path=System> <Select Path=System>*[System[(Level=1 ) and TimeCreated[timediff(@SystemTime) &lt;= milliseconds]]]</Select> </Query> </QueryList>@ $cssStyle= @‘ <style type=text/css> * { margin: 0; padding: 0; } body { font: 14px/1.4 Calibri; } #page-wrap { margin: 50px; } p { margin: 20px 0; } H1 { fontsize:36px; margintop:5px; marginbottom:15px; } H2 { fontsize:18px; margintop:20px; marginbottom:10px; } H3 { fontsize:14px; margintop:1px; marginbottom:5px; } /* Generic Styling, for Desktops/Laptops */ table { width: 100%; bordercollapse: collapse; } /* Zebra striping */ tr:nthoftype(odd) { background: #eee; } th { background: #333; color: white; fontweight: bold; } td, th { padding: 6px; border: 1px solid #ccc; textalign: left; verticalalign: top; } </style>@ $xpath_hang = $xpath_hang.Replace(milliseconds,$timespan.TotalMilliseconds) $xpath_crash = $xpath_crash.Replace(milliseconds,$timespan.TotalMilliseconds) $xpath_reboot = $xpath_crash.Replace(milliseconds,$timespan.TotalMilliseconds) $xpath_critical = $xpath_critical.Replace(milliseconds,$timespan.TotalMilliseconds) $total_crash=@() $total_hang=@() $total_reboot=@() $total_critical=@() $computers =@() $table = NewObject System.Data.DataTable $table.Columns.Add(Computer) $table.Columns.Add(Description) $table.Columns.Add(OS) $table.Columns.Add(Crash Count) $table.Columns.Add(Hang Count) $table.Columns.Add(Reboot History) $table.Columns.Add(Uptime) $failedmachines=@{} $uptime=@{} $csvdata=$null if ([String]::IsNullOrEmpty($serverList)) { $computers+=$env:COMPUTERNAME } else { if ($serverList.EndsWith(.csv)) { $csvdata=ImportCsv $serverList ForEach ($line in $csvdata) { $computers+=$line.Computer } } else { $sr=NewObject System.IO.StreamReader($serverList) while (!$sr.EndOfStream) { $computers+=$sr.ReadLine().Trim() } } } $day=[System.DateTime]::Now.AddDays($timespan.TotalDays) $start_date=[System.DateTime]::Now.AddDays($timespan.TotalDays) $yesterday=[System.DateTime]::Now.AddDays(1).Date $daily_crash=@{} $daily_hang=@{} $server_crash=@{} $server_hang=@{} $category_crash=@{} $category_hang=@{} $category_yesterdaycrash=@{} $category_yesterdayhang=@{} $process_crash=@{} $process_hang=@{} $total_criticalPerServer=@{} $category_server_crash=@{} $category_server_hang=@{} $missing_events=@{} $hour_crash=@{} $hour_hang=@{} $day_crash=@{} $day_hang=@{} $operatingSystem=@{} $rebootList=@{} $shortstart=$start_date.ToString(dd/MM/yyyy) $shortend = [System.DateTime]::Now.AddDays(1).ToString(dd/MM/yyyy) while ($day -lt [System.DateTime]::Now) { $day=$day.AddDays(1) $short_date=$day.ToString(dd/MM/yyyy) $daily_crash[$short_date]=0 $daily_hang[$short_date]=0 } [System.DateTime]::Now.DayOfWeek $hour_crash=@{} $hour_hang=@{} for ($i=0; $i -lt 24; $i++) { $time=[System.DateTime]::Today.AddHours($i).ToString(hh:mm tt) $hour_crash[$time]=0 $hour_hang[$time]=0 } $currentCulture=[System.Globalization.CultureInfo]::CurrentCulture ForEach ($day in $currentCulture.DateTimeFormat.DayNames) { $day_crash[$day]=0 $day_hang[$day]=0 } ForEach ($computer in $computers) { Checking if $computer is online… if(TestConnection Cn $computer BufferSize 16 TimeToLive $TimeToLiveSeconds Count 1 Quiet) { try { $computer is online # launch process first to make sure connecting to event log doesn’t hang # this is because if a machine is online but Windows can’t connect to event log # and also doesn’t get back error (like Access Denied) Get-WinEvent will hang entire script $psi=NewObject System.Diagnostics.ProcessStartInfo(PowerShell.exe,Get-WinEvent -ComputerName $computer -LogName Application -Oldest -MaxEvents 1) $psi.UseShellExecute=$false $p=[System.Diagnostics.Process]::Start($psi) if ($p.WaitForExit($EventLogTimeOutSeconds * 1000)) { $oldestEvent=GetWinEvent ComputerName $computer LogName Application Oldest MaxEvents 1 [String]::Format(Oldest event is {0},$oldestEvent.TimeCreated.ToString(F)) } else { $p.Kill() $failedmachines[$computer]=Couldn’t connect to event log within $eventLogResponse sec } } catch { $failedmachines[$computer] = $_.Exception.Message } if ($oldestEvent -ne $null) { if ($oldestEvent.TimeCreated -gt $start_date) { $missing_events[$computer]=$oldestEvent.TimeCreated.ToString(F) } try { try { $os=GetWmiObject Win32_OperatingSystem ComputerName $computer $operatingSystem[$computer]=$os.Caption $timespan = $os.ConvertToDateTime($os.LocalDateTime)$os.ConvertToDateTime($os.LastBootUpTime) $uptime[$computer] = $($timespan.Days) days $($timespan.Hours) hrs } catch { Unable to query remote OS Error : $($_.Exception.Message) } Processing Application Crashes from $computer $total_crash+=GetWinEvent ComputerName $computer LogName Application FilterXPath $xpath_crash Oldest ErrorAction SilentlyContinue Processing Application Hangs from $computer $total_hang+=GetWinEvent ComputerName $computer LogName Application FilterXPath $xpath_hang Oldest ErrorAction SilentlyContinue Processing Reboots from $computer $total_reboot+=GetWinEvent ComputerName $computer LogName System FilterXPath $xpath_reboot Oldest ErrorAction SilentlyContinue Critical Events $total_critical+=GetWinEvent ComputerName $computer LogName System FilterXPath $xpath_critical Oldest ErrorAction SilentlyContinue } catch { $failedmachines[$computer] = $_.Exception.Message } } } else { $failedmachines[$computer]=Machine is offline } } ForEach ($event in $total_critical) { $computer=$event.MachineName if (![String]::IsNullOrEmpty($computer)) { try { if ($computer.Contains(.)) { $computer=$computer.Substring(0,$computer.IndexOf(.)) } if ($total_criticalPerServer[$computer] -eq $null) { $total_criticalPerServer[$computer]=@{} } $total_criticalPerServer[$computer][$event.Message]++ } catch { $_ } } } ForEach ($event in $total_reboot) { $computer=$event.MachineName if (![String]::IsNullOrEmpty($computer)) { try { if ($computer.Contains(.)) { $computer=$computer.Substring(0,$computer.IndexOf(.)) } if ($rebootList[$computer] -eq $null) { $rebootList[$computer]=@() } $rebootList[$computer]+=$event.TimeCreated.ToString(F) } catch { $_ } } } ForEach ($event in $total_crash) { $computer=$event.MachineName $computer=$event.MachineName if (![String]::IsNullOrEmpty($computer)) { try { if ($computer.Contains(.)) { $computer=$computer.Substring(0,$computer.IndexOf(.)) } # crashes per day $short_date=$event.TimeCreated.ToString(dd/MM/yyyy) $time=[System.DateTime]::Today.AddHours($event.TimeCreated.Hour).ToString(hh:mm tt) $hour_crash[$time]++ $day = $event.TimeCreated.DayOfWeek.ToString() $day_crash[$day]++ $daily_crash[$short_date]++ # crashes per server $server_crash[$computer]++ # crashes per type $app=$event.Properties[0].Value $ver=$event.Properties[1].Value $module=$event.Properties[3].Value $modulever=$event.Properties[4].Value $exp=$event.Properties[6].Value $bucketID=$app v$ver fault in $module v$modulever Exception $exp) $category_crash[$bucketID]++ if ($category_server_crash[$computer] -eq $null) { $category_server_crash[$computer]=@{} } if ($event.TimeCreated -ge $yesterday) { $category_yesterdaycrash[$bucketID]++ } $category_server_crash[$computer][$bucketID]++ $process_crash[$app]++ } catch { $_ } } } ForEach ($event in $total_hang) { $computer=$event.MachineName if ($computer.Contains(.)) { $computer=$computer.Substring(0,$computer.IndexOf(.)) } # crashes per day $short_date=$event.TimeCreated.ToString(dd/MM/yyyy) $daily_hang[$short_date]++ $time=[System.DateTime]::Today.AddHours($event.TimeCreated.Hour).ToString(hh:mm tt) $hour_hang[$time]++ $day = $event.TimeCreated.DayOfWeek.ToString() $day_hang[$day]++ $daily_crash[$short_date]++ # crashes per server $server_hang[$computer]++ # crashes per type $app=$event.Properties[0].Value $ver=$event.Properties[1].Value $bucketID=$app v$ver $category_hang[$bucketID]++ $bucketID if ($category_server_hang[$computer] -eq $null) { $category_server_hang[$computer]=@{} } if ($event.TimeCreated -ge $yesterday) { $category_yesterdayhang[$bucketID]++ } $category_server_hang[$computer][$bucketID]++ $process_hang[$app]++ } # build report # crashes since yesterday $html_yesterday=<h2>Crashes Since Yesterday</h2> if ($category_yesterdaycrash.Count -gt 0) { $html_yesterday+=$category_yesterdaycrash.GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment } else { $html_yesterday+=<p>None</p> } $html_yesterday+=<h2>Hangs Since Yesterday</h2> if ($category_yesterdayhang.Count -gt 0) { $html_yesterday+=$category_yesterdayhang.GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment } else { $html_yesterday+=<p>None</p> } # per server Crash per server $html_server_crash =<h2>Crashes Per Server</h2> $html_server_crash+= $server_crash.GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment $html_server_Hang = <h2>Hangs Per Server</h2> $html_server_Hang += $server_hang.GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment # per type Crashes By Category $html_category_crash =<h2>Crashes By Category</h2> $html_category_crash+=$category_crash.GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment “” # per type Hangs by Application $html_category_hang =<h2>Hangs by Application</h2> $html_category_hang+=$category_hang.GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment “” Crashes Category Per Server $html_server = <h2>Crashes Category Per Server</h2> ForEach ($server in $server_crash | SortObject Value Descending) { Crash Breakdown for $($server.Keys) if ($category_server_crash[$($server.Keys)].Count -gt 0) { $html_server+= <h3>$($server.Keys)</h3> $html_server+=$category_server_crash[$($server.Keys)].GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment } else { $html_server+= <h3>$($server.Keys)</h3><p>None</p> } } Hang Category Per Server $html_server += <h2>Hung Process Per Server</h2> ForEach ($server in $server_hang | SortObject Value Descending) { Crash Breakdown for $($server.Keys) if ($category_server_hang[$($server.Keys)].Count -gt 0) { $html_server+= <h3>$($server.Keys)</h3> $html_server+=$category_server_hang[$($server.Keys)].GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment } else { $html_server+= <h3>$($server.Keys)</h3><p>None</p> } } Critical Events Per Server $html_server+=<h2>Critical Events Per Server</h2> if ($total_criticalPerServer.Count -eq 0) { $html_server+=<p>None</p> } else { ForEach ($item in $total_criticalPerServer) { if ($item.Values.Count -gt 0) { $html_server+= <h3>$($item.Keys)</h3> $html_server+=$total_criticalPerServer[$($item.Keys)].GetEnumerator() | SortObject Value Descending | SelectObject Name,Value | ConvertToHtml Fragment } } } Missing Events Per Server if ($missing_events.Count -gt 0) { $html_server+=<h2>Events Missing From Server</h2> $html_server+=<p>These servers oldest event logs are newer than start date of report.</p> $html_server+=$missing_events.GetEnumerator() | SelectObject Name,Value | ConvertToHtml Fragment } if ($failedmachines.Count -gt 0) { $html_server+=<h2>Errors Connecting To Servers</h2> $html_server+=$failedmachines.GetEnumerator() | SelectObject Name,Value | ConvertToHtml Fragment } # build chart # build chart $page1ChartHeight = 660 $otherPagesChartHeight = 690 # *** DAILY CRASH TREND CHART = CHART1 $dailyCrashTrendChart = Newobject System.Windows.Forms.DataVisualization.Charting.Chart $dailyCrashTrendChart.Width = 1024 $dailyCrashTrendChart.Height = $page1ChartHeight $dailyCrashTrendChart.BackColor = [System.Drawing.Color]::White [void]$dailyCrashTrendChart.Titles.Add(Daily Crash Trend) $dailyCrashTrendChart.Titles[0].Font = Arial,13pt $dailyCrashTrendChart.Titles[0].Alignment = topLeft $chartarea = NewObject System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.Name = ChartArea1 $chartarea.AxisY.Title = Crash Count $chartarea.AxisX.Title = Date $chartarea.AxisY.Interval =($daily_crash.GetEnumerator() | SortObject Value Descending)[0].Value $chartarea.AxisX.Interval = 1 $dailyCrashTrendChart.ChartAreas.Add($chartarea) [void]$dailyCrashTrendChart.Series.Add(CrashCount) $dailyCrashTrendChart.Series[CrashCount].ChartType = Line $dailyCrashTrendChart.Series[CrashCount].BorderWidth = 3 $dailyCrashTrendChart.Series[CrashCount].IsVisibleInLegend = $true $dailyCrashTrendChart.Series[CrashCount].chartarea = ChartArea1 $dailyCrashTrendChart.Series[CrashCount].color = #62B5CC $day=$start_date while ($day -lt [System.DateTime]::Now) { $day=$day.AddDays(1) $short_date=$day.ToString(dd/MM/yyyy) Process crash chart for $day if ($daily_crash[$short_date] -ne $null) { [Void]$dailyCrashTrendChart.Series[CrashCount].Points.addxy( $short_date , $daily_crash[$short_date]) } } $dailyCrashTrendChartfilename=[System.IO.Path]::Combine($reportFolder,$reportName-Chart1.png) $dailyCrashTrendChart.SaveImage($dailyCrashTrendChartfilename,png) # build chart # build chart $dailyHangTrendChart = Newobject System.Windows.Forms.DataVisualization.Charting.Chart $dailyHangTrendChart.Width = 1024 $dailyHangTrendChart.Height = $page1ChartHeight $dailyHangTrendChart.BackColor = [System.Drawing.Color]::White [void]$dailyHangTrendChart.Titles.Add(Daily Hang Trend) $dailyHangTrendChart.Titles[0].Font = Arial,13pt $dailyHangTrendChart.Titles[0].Alignment = topLeft $chartarea = NewObject System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.Name = ChartArea1 $chartarea.AxisY.Title = Hang Count $chartarea.AxisX.Title = Date $chartarea.AxisY.Interval =($daily_hang.GetEnumerator() | SortObject Value Descending)[0].Value $chartarea.AxisX.Interval = 1 $dailyHangTrendChart.ChartAreas.Add($chartarea) [void]$dailyHangTrendChart.Series.Add(CrashCount) $dailyHangTrendChart.Series[CrashCount].ChartType = Line $dailyHangTrendChart.Series[CrashCount].BorderWidth = 3 $dailyHangTrendChart.Series[CrashCount].IsVisibleInLegend = $true $dailyHangTrendChart.Series[CrashCount].chartarea = ChartArea1 $dailyHangTrendChart.Series[CrashCount].color = #62B5CC $day=$start_date while ($day -lt [System.DateTime]::Now) { $day=$day.AddDays(1) $short_date=$day.ToString(dd/MM/yyyy) if ($daily_hang[$short_date] -ne $null) { [Void]$dailyHangTrendChart.Series[CrashCount].Points.addxy( $short_date , $daily_hang[$short_date]) } } $dailyHangTrendChartfilename=[System.IO.Path]::Combine($reportFolder,$reportName-chart3.png) $dailyHangTrendChart.SaveImage($dailyHangTrendChartfilename,png) $processCrashChart = NewObject System.Windows.Forms.DataVisualization.Charting.Chart $processCrashChart.Width = 1024 $processCrashChart.Height =$otherPagesChartHeight $processCrashChart.BackColor = [System.Drawing.Color]::White [void]$processCrashChart.Titles.Add(Crash by Process) $processCrashChart.Titles[0].Font = Arial,13pt $processCrashChart.Titles[0].Alignment = topLeft $chartarea = NewObject System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.Name = ChartArea1 $chartarea.AxisY.Title = Process $chartarea.AxisX.Title = Data #$chartarea.AxisY.Interval =($daily_hang.GetEnumerator() | Sort-Object Value -Descending)[0].Value #$chartarea.AxisX.Interval = 1 $processCrashChart.ChartAreas.Add($chartarea) [void]$processCrashChart.Series.Add(Process) $processCrashChart.Series[Process].ChartType = Pie $processCrashChart.Series[Process][PieLabelStyle]=Outside $processCrashChart.Series[Process][CollectedThreshold]=5 $processCrashChart.Series[Process][CollectedThresholdUsePercent]=$true $processCrashChart.Series[Process].BorderWidth = 1 $processCrashChart.Series[Process].BorderColor = [System.Drawing.Color]::FromArgb(26, 59, 105); $processCrashChart.Series[Process].IsVisibleInLegend = $true $processCrashChart.Series[Process].chartarea = ChartArea1 $processCrashChart.Series[Process].color = #62B5CC ForEach ($process in $process_crash.GetEnumerator()) { $processCrashChart.Series[Process].Points.addxy( $process.Key, $process.Value) } $processCrashChartfilename=[System.IO.Path]::Combine($reportFolder,$reportName-Chart2.png) $processCrashChart.SaveImage($processCrashChartfilename,png) $processHangChart = NewObject System.Windows.Forms.DataVisualization.Charting.Chart $processHangChart.Width = 1024 $processHangChart.Height = $otherPagesChartHeight $processHangChart.BackColor = [System.Drawing.Color]::White [void]$processHangChart.Titles.Add(Hang by Process) $processHangChart.Titles[0].Font = Arial,13pt $processHangChart.Titles[0].Alignment = topLeft $chartarea = NewObject System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.Name = ChartArea1 $chartarea.AxisY.Title = Process $chartarea.AxisX.Title = Date $chartarea.AxisY.Interval =($daily_crash.GetEnumerator() | SortObject Value Descending)[0].Value $chartarea.AxisX.Interval = 1 $processHangChart.ChartAreas.Add($chartarea) [void]$processHangChart.Series.Add(Process) $processHangChart.Series[Process].ChartType = Pie $processHangChart.Series[Process][PieLabelStyle]=Outside $processHangChart.Series[Process][CollectedThreshold]=5 $processHangChart.Series[Process][CollectedThresholdUsePercent]=$true $processHangChart.Series[Process].BorderWidth = 1 $processHangChart.Series[Process].BorderColor = [System.Drawing.Color]::FromArgb(26, 59, 105); $processHangChart.Series[Process].IsVisibleInLegend = $true $processHangChart.Series[Process].chartarea = ChartArea1 $processHangChart.Series[Process].color = #62B5CC ForEach ($process in $process_hang.GetEnumerator()) { $processHangChart.Series[Process].Points.addxy( $process.Key, $process.Value) } $processHangChartfilename=[System.IO.Path]::Combine($reportFolder,$reportName-Chart4.png) $processHangChart.SaveImage($processHangChartfilename,png) # *** DAILY CRASH TREND CHART = CHART1 $hourlyCrashTrendChart = Newobject System.Windows.Forms.DataVisualization.Charting.Chart $hourlyCrashTrendChart.Width = 1024 $hourlyCrashTrendChart.Height = $otherPagesChartHeight $hourlyCrashTrendChart.BackColor = [System.Drawing.Color]::White [void]$hourlyCrashTrendChart.Titles.Add(Hourly Crash Trend) $hourlyCrashTrendChart.Titles[0].Font = Arial,13pt $hourlyCrashTrendChart.Titles[0].Alignment = topLeft $chartarea = NewObject System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.Name = ChartArea1 $chartarea.AxisY.Title = Crash Count $chartarea.AxisX.Title = Date $chartarea.AxisY.Interval =($hour_crash.GetEnumerator() | SortObject Value Descending)[0].Value $chartarea.AxisX.Interval = 1 $hourlyCrashTrendChart.ChartAreas.Add($chartarea) [void]$hourlyCrashTrendChart.Series.Add(CrashCount) $hourlyCrashTrendChart.Series[CrashCount].ChartType = Line $hourlyCrashTrendChart.Series[CrashCount].BorderWidth = 3 $hourlyCrashTrendChart.Series[CrashCount].IsVisibleInLegend = $true $hourlyCrashTrendChart.Series[CrashCount].chartarea = ChartArea1 $hourlyCrashTrendChart.Series[CrashCount].color = #62B5CC for ($i=0; $i -lt 24 ; $i++) { $time=[System.DateTime]::Today.AddHours($i).ToString(hh:mm tt) [Void]$hourlyCrashTrendChart.Series[CrashCount].Points.addxy( $time , $hour_crash[$time]) } $hourlyCrashTrendChartfilename=[System.IO.Path]::Combine($reportFolder,$reportName-HourlyCrashTrend.png) $hourlyCrashTrendChart.SaveImage($hourlyCrashTrendChartfilename,png) $day_crashTrendChart = Newobject System.Windows.Forms.DataVisualization.Charting.Chart $day_crashTrendChart.Width = 1024 $day_crashTrendChart.Height = $otherPagesChartHeight $day_crashTrendChart.BackColor = [System.Drawing.Color]::White [void]$day_crashTrendChart.Titles.Add(Day Of Week Crash Trend) $day_crashTrendChart.Titles[0].Font = Arial,13pt $day_crashTrendChart.Titles[0].Alignment = topLeft $chartarea = NewObject System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.Name = ChartArea1 $chartarea.AxisY.Title = Crash Count $chartarea.AxisX.Title = Date $chartarea.AxisY.Interval =($hour_crash.GetEnumerator() | SortObject Value Descending)[0].Value $chartarea.AxisX.Interval = 1 $day_crashTrendChart.ChartAreas.Add($chartarea) [void]$day_crashTrendChart.Series.Add(CrashCount) $day_crashTrendChart.Series[CrashCount].ChartType = Line $day_crashTrendChart.Series[CrashCount].BorderWidth = 3 $day_crashTrendChart.Series[CrashCount].IsVisibleInLegend = $true $day_crashTrendChart.Series[CrashCount].chartarea = ChartArea1 $day_crashTrendChart.Series[CrashCount].color = #62B5CC ForEach ($day in $currentCulture.DateTimeFormat.DayNames) { [Void]$day_crashTrendChart.Series[CrashCount].Points.addxy( $day , $day_crash[$day]) } $day_crashTrendChartfilename=[System.IO.Path]::Combine($reportFolder,$reportName-dayofweekCrashTrend.png) $day_crashTrendChart.SaveImage($day_crashTrendChartfilename,png) # *** DAILY Hang TREND CHART = CHART1 $hourlyHangTrendChart = Newobject System.Windows.Forms.DataVisualization.Charting.Chart $hourlyHangTrendChart.Width = 1024 $hourlyHangTrendChart.Height = $otherPagesChartHeight $hourlyHangTrendChart.BackColor = [System.Drawing.Color]::White [void]$hourlyHangTrendChart.Titles.Add(Hourly Hang Trend) $hourlyHangTrendChart.Titles[0].Font = Arial,13pt $hourlyHangTrendChart.Titles[0].Alignment = topLeft $chartarea = NewObject System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.Name = ChartArea1 $chartarea.AxisY.Title = Hang Count $chartarea.AxisX.Title = Date $chartarea.AxisY.Interval =($hour_hang.GetEnumerator() | SortObject Value Descending)[0].Value $chartarea.AxisX.Interval = 1 $hourlyHangTrendChart.ChartAreas.Add($chartarea) [void]$hourlyHangTrendChart.Series.Add(HangCount) $hourlyHangTrendChart.Series[HangCount].ChartType = Line $hourlyHangTrendChart.Series[HangCount].BorderWidth = 3 $hourlyHangTrendChart.Series[HangCount].IsVisibleInLegend = $true $hourlyHangTrendChart.Series[HangCount].chartarea = ChartArea1 $hourlyHangTrendChart.Series[HangCount].color = #62B5CC for ($i=0; $i -lt 24 ; $i++) { $time=[System.DateTime]::Today.AddHours($i).ToString(hh:mm tt) [Void]$hourlyHangTrendChart.Series[HangCount].Points.addxy( $time , $hour_hang[$time]) } $hourlyHangTrendChartfilename=[System.IO.Path]::Combine($reportFolder,$reportName-HourlyHangTrend.png) $hourlyHangTrendChart.SaveImage($hourlyHangTrendChartfilename,png) $day_hangTrendChart = Newobject System.Windows.Forms.DataVisualization.Charting.Chart $day_hangTrendChart.Width = 1024 $day_hangTrendChart.Height = $otherPagesChartHeight $day_hangTrendChart.BackColor = [System.Drawing.Color]::White [void]$day_hangTrendChart.Titles.Add(Day of Week Hang Trend) $day_hangTrendChart.Titles[0].Font = Arial,13pt $day_hangTrendChart.Titles[0].Alignment = topLeft $chartarea = NewObject System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.Name = ChartArea1 $chartarea.AxisY.Title = Hang Count $chartarea.AxisX.Title = Date $chartarea.AxisY.Interval =($hour_hang.GetEnumerator() | SortObject Value Descending)[0].Value $chartarea.AxisX.Interval = 1 $day_hangTrendChart.ChartAreas.Add($chartarea) [void]$day_hangTrendChart.Series.Add(HangCount) $day_hangTrendChart.Series[HangCount].ChartType = Line $day_hangTrendChart.Series[HangCount].BorderWidth = 3 $day_hangTrendChart.Series[HangCount].IsVisibleInLegend = $true $day_hangTrendChart.Series[HangCount].chartarea = ChartArea1 $day_hangTrendChart.Series[HangCount].color = #62B5CC ForEach ($day in $currentCulture.DateTimeFormat.DayNames) { [Void]$day_hangTrendChart.Series[HangCount].Points.addxy( $day , $day_hang[$day]) } $day_hangTrendChartfilename=[System.IO.Path]::Combine($reportFolder,$reportName-dayofweekHangTrend.png) $day_hangTrendChart.SaveImage($day_hangTrendChartfilename,png) $charts = <h2>Total Application Crashes Per Day</h2> $charts+=[String]::Format(‘<img src={0}-Chart1.png>‘,[System.IO.Path]::Combine($reportFolder,$reportName)) $charts+=<h2>Total Application Hangs Per Day</h2> $charts+=[String]::Format(‘<img src={0}-Chart3.png>‘,[System.IO.Path]::Combine($reportFolder,$reportName)) $charts+=<h2>Total Application Crashes Per Hour</h2> $charts+=[String]::Format(‘<img src={0}>‘,$hourlyCrashTrendChartfilename) $charts+=<h2>Total Application Hang Per Hour</h2> $charts+=[String]::Format(‘<img src={0}>‘,$hourlyHangTrendChartfilename) $charts+=<h2>Total Application Crashes Per Day of Week</h2> $charts+=[String]::Format(‘<img src={0}>‘,$day_crashTrendChartfilename) $charts+=<h2>Total Application Hangs Per Day of Week</h2> $charts+=[String]::Format(‘<img src={0}>‘,$day_hangTrendChartfilename) $charts+=<h2>Process Crash Breakdown</h2> $charts+=[String]::Format(‘<img src={0}-Chart2.png>‘,[System.IO.Path]::Combine($reportFolder,$reportName)) $charts+=<h2>Process Hang Breakdown</h2> $charts+=[String]::Format(‘<img src={0}-Chart4.png>‘,[System.IO.Path]::Combine($reportFolder,$reportName)) ForEach ($computer in $computers) { $computer=$computer.ToUpper() $desc=“” if ($csvdata -ne $null) { $desc=($csvdata | WhereObject {$_.Computer -eq $computer })[0].Description } $reboots=“” $computerReboots=$rebootList[$computer] if ($computerReboots.Count -gt 0) { ForEach ($reboot in $computerReboots) { $reboots+=$($reboot)`r`n } } else { $reboots=None } $table.Rows.Add( $computer, $desc, $operatingSystem[$computer], $server_crash[$computer], $server_hang[$computer], $reboots, $uptime[$computer]) } $html_server +=<h2>Server Summary</h2> if ($csvdata -eq $null) { $html_table=$table | SelectObject Computer,OS,Crash Count,Hang Count,Reboot History,Uptime | ConvertToHtml Fragment } else { $html_table=$table | SelectObject Computer,Description,OS,Crash Count,Hang Count,Reboot History,Uptime | ConvertToHtml Fragment } $html_table=$html_table.Replace(`r`n,<br>) $html_server += $html_table $htmlFilename=[System.String]::Format({0}.html,[System.IO.Path]::Combine($reportFolder,$reportName)) $pdfFilename=[System.String]::Format({0}.pdf,[System.IO.Path]::Combine($reportFolder,$reportName)) if (![String]::IsNullOrEmpty($customer)) { $title = <h1>Event Log Summary for $customer from $shortstart to $shortend </h1> } else { $title = <h1>Event Log Summary from $shortstart to $shortend </h1> } ConvertToHtml Head $cssStyle Body $title $charts $html_yesterday $html_category_crash $html_category_hang $html_server_crash $html_server_Hang $html_server Title App Stability Report for $customer | Out-File $htmlFilename if ($reportFormat -eq PDF) { $argumentList=@() $argumentList+=$htmlFilename $argumentList+=$pdfFilename StartProcess FilePath $curDir\wkhtmltopdf.exe ArgumentList $argumentList Wait RemoveItem $htmlFilename WriteOutput Report located at ‘$($pdfFilename)’ } else { WriteOutput Report located at ‘$($htmlFilename)’ } if ($cleanUpImages) { RemoveItem $dailyCrashTrendChartfilename RemoveItem $processCrashChartfilename RemoveItem $dailyHangTrendChartfilename RemoveItem $processHangChartfilename RemoveItem $hourlyCrashTrendChartfilename RemoveItem $hourlyHangTrendChartfilename RemoveItem $day_crashTrendChartfilename RemoveItem $day_hangTrendChartfilename }

About chentiangemalc

specializes in end-user computing technologies. disclaimer 1) use at your own risk. test any solution in your environment. if you do not understand the impact/consequences of what you're doing please stop, and ask advice from somebody who does. 2) views are my own at the time of posting and do not necessarily represent my current view or the view of my employer and family members/relatives. 3) over the years Microsoft/Citrix/VMWare have given me a few free shirts, pens, paper notebooks/etc. despite these gifts i will try to remain unbiased.
This entry was posted in .NET, Debugging, PowerShell and tagged . Bookmark the permalink.

Leave a comment