Private/Kinds/BootPerformance.ps1
|
# The BootPerformance Kind: how long this machine takes to become usable. # # The number a Customer actually complains about, and the one Windows already measures for # itself and never shows anyone. The list of what slowed the last boots down comes with it, # because the duration alone tells a Technician there is a problem and not which one. $script:BootPerformanceNeedsAdmin = $true $script:BootPerformanceLog = 'Microsoft-Windows-Diagnostics-Performance/Operational' $script:BootPerformanceBootEventId = 100 $script:BootPerformanceDegradationIds = @(101, 102, 103, 104, 105, 106, 107, 108, 109, 110) # How many recent boots to average. One boot after a feature update is not this machine's # normal, and a single reading would report it as though it were. $script:BootPerformanceSampleCount = 5 function Get-BootPerformanceData { [CmdletBinding()] [OutputType([psobject])] param([hashtable]$Parameters = @{}) $days = [int](Get-Parameter $Parameters 'Days' 30) $since = (Get-Date).AddDays(-$days) $unreadable = @{} $boots = @(Get-StabilityEvent -Log $script:BootPerformanceLog -Provider @() ` -Id @($script:BootPerformanceBootEventId) -Since $since -Unreadable $unreadable | Sort-Object TimeCreated -Descending | Select-Object -First $script:BootPerformanceSampleCount | ForEach-Object { [pscustomobject]@{ Time = $_.TimeCreated BootMilliseconds = Get-EventPayload -LogEntry $_ -Index 0 } }) $degradations = @(Get-StabilityEvent -Log $script:BootPerformanceLog -Provider @() ` -Id $script:BootPerformanceDegradationIds -Since $since -Unreadable $unreadable | ForEach-Object { $name = Get-EventPayload -LogEntry $_ -Index 0 [pscustomobject]@{ Time = $_.TimeCreated; Item = $name } }) [pscustomobject]@{ PSTypeName = 'Gutcheck.Data.BootPerformance' Days = $days Boots = $boots Degradations = $degradations LogUnreadable = $unreadable.ContainsKey($script:BootPerformanceLog) } } function ConvertTo-BootPerformanceFinding { [CmdletBinding()] [OutputType([psobject])] param( [AllowNull()]$Data, [hashtable]$Parameters = @{} ) $warn = Get-Parameter $Parameters 'BootDurationWarnAboveSeconds' 90 $fail = Get-Parameter $Parameters 'BootDurationFailAboveSeconds' 180 if (Get-DataProperty $Data 'LogUnreadable') { return New-Finding -Category System -Check (Get-Text 'Check.BootPerformance.BootDurationAvgLast') -Severity INFO ` -Value (Get-Text 'Value.Shared.NeedsAdmin') ` -Hint (Get-Text 'Hint.BootPerformance.RerunAndAllowTheAdmin') } $durations = @((Get-DataCollection $Data 'Boots') | ForEach-Object { ConvertTo-Number $_.BootMilliseconds } | Where-Object { $null -ne $_ -and $_ -gt 0 }) if (-not $durations.Count) { # A machine that has not been restarted in the period, or one whose diagnostics # task has never run. Neither is a slow boot. return New-UnavailableFinding -Category System -Check (Get-Text 'Check.BootPerformance.BootDurationAvgLast') ` -Hint (Get-Text 'Hint.BootPerformance.WindowsHasRecordedNoBoot') } $seconds = ($durations | Measure-Object -Average).Average / 1000 New-Finding -Category System -Check (Get-Text 'Check.BootPerformance.BootDurationAvgLast') ` -Severity (Get-Severity $seconds $warn $fail) -Value ('{0:N0} s' -f $seconds) ` -Hint (Get-Text 'Hint.BootPerformance.SlowBootCheckStartupPrograms') } function ConvertTo-BootPerformanceSection { [CmdletBinding()] [OutputType([psobject])] param([AllowNull()]$Data) $degradations = Get-DataCollection $Data 'Degradations' if (-not $degradations.Count) { return } New-Section -Title (Get-Text 'Title.BootPerformance.ItemsThatSlowedDown') -Row @( $degradations | Where-Object { $_.Item } | Group-Object Item | Sort-Object Count -Descending | Select-Object -First 15 Count, Name ) } |