Private/Kinds/Memory.ps1
|
# The Memory Kind. # # Get-MemoryData talks to the Target Machine and decides nothing. # ConvertTo-MemoryFinding is pure: data and parameters in, Findings out. Every threshold # lives there as a named parameter, defaulted to the value the Gutcheck script used. # How many readings the Memory Check averages across. The wait between them is shared # with every other Kind - see Private/Sampling.ps1. $script:MemorySampleCount = 3 function Get-MemoryData { [CmdletBinding()] [OutputType([psobject])] param([hashtable]$Parameters = @{}) # The first read of a formatted-performance class is primed with zeroes; discard it. [void](Get-CimInstance Win32_PerfFormattedData_PerfOS_Memory -ErrorAction SilentlyContinue) $samples = @(1..$script:MemorySampleCount | ForEach-Object { Write-CheckProgress -Status ((Get-Text 'Console.Progress.Sample') -f $_, $script:MemorySampleCount) ` -Step ($_ - 1) -Of $script:MemorySampleCount Wait-Sample Get-CimInstance Win32_PerfFormattedData_PerfOS_Memory -ErrorAction SilentlyContinue }) $last = $samples | Select-Object -Last 1 $os = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue $pageFiles = @(Get-CimInstance Win32_PageFileUsage -ErrorAction SilentlyContinue | ForEach-Object { [pscustomobject]@{ Name = $_.Name AllocatedBaseSizeMB = $_.AllocatedBaseSize PeakUsageMB = $_.PeakUsage } }) $top = @(Get-Process -ErrorAction SilentlyContinue | Sort-Object PrivateMemorySize64 -Descending | Select-Object -First 12 | ForEach-Object { [pscustomobject]@{ Name = $_.Name Id = $_.Id PrivateMB = [math]::Round($_.PrivateMemorySize64 / 1MB) WorkingSetMB = [math]::Round($_.WorkingSet64 / 1MB) Handles = $_.HandleCount } }) [pscustomobject]@{ PSTypeName = 'Gutcheck.Data.Memory' FreePhysicalMemoryKB = $os.FreePhysicalMemory TotalVisibleMemoryKB = $os.TotalVisibleMemorySize PercentCommittedBytesInUse = $last.PercentCommittedBytesInUse PagesInputPerSecond = @($samples | ForEach-Object { $_.PagesInputPersec }) PageFiles = $pageFiles TopProcessesByMemory = $top } } function ConvertTo-MemoryFinding { [CmdletBinding()] [OutputType([psobject])] param( [AllowNull()]$Data, [hashtable]$Parameters = @{} ) New-RamInUseFinding -Data $Data -Parameters $Parameters New-CommitChargeFinding -Data $Data -Parameters $Parameters New-PageFaultFinding -Data $Data -Parameters $Parameters New-PageFileFinding -Data $Data -Parameters $Parameters } function ConvertTo-MemorySection { [CmdletBinding()] [OutputType([psobject])] param([AllowNull()]$Data) New-Section -Title (Get-Text 'Title.Memory.TopProcessesByMemory') -Row (Get-DataProperty $Data 'TopProcessesByMemory') } function New-RamInUseFinding { [CmdletBinding()] param([AllowNull()]$Data, [hashtable]$Parameters) $warn = Get-Parameter $Parameters 'RamInUseWarnPercent' 80 $fail = Get-Parameter $Parameters 'RamInUseFailPercent' 90 $free = ConvertTo-Number (Get-DataProperty $Data 'FreePhysicalMemoryKB') $total = ConvertTo-Number (Get-DataProperty $Data 'TotalVisibleMemoryKB') if ($null -eq $free -or $null -eq $total -or $total -le 0) { return New-UnavailableFinding -Category Memory -Check (Get-Text 'Check.Memory.RAMInUse') ` -Hint (Get-Text 'Hint.Memory.TheOperatingSystemDidNot') } $usedPercent = 100 - ($free / $total * 100) New-Finding -Category Memory -Check (Get-Text 'Check.Memory.RAMInUse') -Severity (Get-Severity $usedPercent $warn $fail) ` -Value ((Get-Text 'Value.Memory.PercentWithFree') -f $usedPercent, ($free / 1MB)) ` -Hint (Get-Text 'Hint.Memory.RAMFullConstantPagingSluggish') } function New-CommitChargeFinding { [CmdletBinding()] param([AllowNull()]$Data, [hashtable]$Parameters) $warn = Get-Parameter $Parameters 'CommitWarnPercent' 80 $fail = Get-Parameter $Parameters 'CommitFailPercent' 90 $committed = ConvertTo-Number (Get-DataProperty $Data 'PercentCommittedBytesInUse') if ($null -eq $committed) { return New-UnavailableFinding -Category Memory -Check (Get-Text 'Check.Memory.CommitCharge') ` -Hint (Get-Text 'Hint.Memory.TheMemoryPerformanceCountersDid') } New-Finding -Category Memory -Check (Get-Text 'Check.Memory.CommitCharge') -Severity (Get-Severity $committed $warn $fail) ` -Value ((Get-Text 'Value.Memory.PercentOfLimit') -f $committed) ` -Hint (Get-Text 'Hint.Memory.NearTheCommitLimitPrograms') } function New-PageFaultFinding { [CmdletBinding()] param([AllowNull()]$Data, [hashtable]$Parameters) $warn = Get-Parameter $Parameters 'HardPageFaultsWarnPerSecond' 100 $fail = Get-Parameter $Parameters 'HardPageFaultsFailPerSecond' 300 # Judged as the average across the sample window: one spike is not sustained pressure. $average = Get-SampleAverage (Get-DataProperty $Data 'PagesInputPerSecond') if ($null -eq $average) { return New-UnavailableFinding -Category Memory -Check (Get-Text 'Check.Memory.HardPageFaultsPages') ` -Hint (Get-Text 'Hint.Memory.TheMemoryPerformanceCountersDid2') } New-Finding -Category Memory -Check (Get-Text 'Check.Memory.HardPageFaultsPages') ` -Severity (Get-Severity $average $warn $fail) -Value ('{0:N0}' -f $average) ` -Hint (Get-Text 'Hint.Memory.SustainedHighValuesNotEnough') } function New-PageFileFinding { [CmdletBinding()] param([AllowNull()]$Data, [hashtable]$Parameters) $pageFiles = (Get-DataCollection $Data 'PageFiles') if (-not $pageFiles.Count) { return New-Finding -Category Memory -Check (Get-Text 'Check.Memory.PageFile') -Value (Get-Text 'Value.Shared.None') -Severity WARN ` -Hint (Get-Text 'Hint.Memory.NoPageFileProgramsCrash') } $described = $pageFiles | ForEach-Object { '{0} {1} MB (peak {2} MB)' -f $_.Name, $_.AllocatedBaseSizeMB, $_.PeakUsageMB } New-Finding -Category Memory -Check (Get-Text 'Check.Memory.PageFile') -Value ($described -join ', ') -Severity INFO } |