Private/System/Invoke-MemoryMonitoring.ps1

#Requires -Version 5.1

<#
.SYNOPSIS
    Memory Monitoring and Threshold Management Module for Find-UnknownSID Enterprise Solution
 
.DESCRIPTION
    Provides focused memory monitoring and threshold checking functionality including:
    - Memory usage monitoring and checks
    - Threshold testing and evaluation
    - Automated monitoring triggers
    - Enterprise-grade correlation tracking
 
    This module follows the single-responsibility principle by focusing exclusively
    on memory monitoring and threshold management operations.
 
.NOTES
    Author: Jeffrey Stuhr
    Blog: https://www.techbyjeff.net
    LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/
 
    TROUBLESHOOTING:
    - For monitoring issues: .\Troubleshooting\Performance\Memory-Monitoring.md
    - For threshold problems: .\Troubleshooting\Performance\Memory-Thresholds.md
    - For performance: .\Troubleshooting\Performance\Performance-Tuning.md
 
.COMPONENT
    Find-UnknownSID Memory Monitoring System
 
.FUNCTIONALITY
    - Memory usage monitoring
    - Threshold testing and evaluation
    - Automated monitoring triggers
    - Memory pressure detection
#>


function Get-SystemGCTotalMemory {
    <#
    .SYNOPSIS
        Wrapper for System.GC.GetTotalMemory to enable mocking in tests
     
    .DESCRIPTION
        Provides a mockable wrapper around the static .NET method
        System.GC.GetTotalMemory for testing purposes.
     
    .PARAMETER ForceFullCollection
        Forces a full garbage collection before measuring memory
    #>

    param([bool]$ForceFullCollection = $false)
    
    return [System.GC]::GetTotalMemory($ForceFullCollection)
}

function Get-SystemGCCollectionCount {
    <#
    .SYNOPSIS
        Wrapper for System.GC.CollectionCount to enable mocking in tests
     
    .DESCRIPTION
        Provides a mockable wrapper around the static .NET method
        System.GC.CollectionCount for testing purposes.
     
    .PARAMETER Generation
        The generation number (0, 1, 2)
    #>

    param([int]$Generation)
    
    return [System.GC]::CollectionCount($Generation)
}

function Invoke-MemoryCheck {
    <#
    .SYNOPSIS
        Performs memory usage check and triggers cleanup if needed
 
    .DESCRIPTION
        Checks current memory usage against configured thresholds and
        triggers appropriate cleanup actions. Provides detailed logging
        and correlation tracking for enterprise troubleshooting.
 
    .PARAMETER MemoryManager
        MemoryManager instance to perform check on
 
    .PARAMETER CorrelationId
        Correlation identifier for tracking operations
 
    .PARAMETER Force
        Forces memory check regardless of interval counter
 
    .EXAMPLE
        PS> Invoke-MemoryCheck -MemoryManager $memoryManager
 
        Performs standard memory check based on configured interval
 
    .EXAMPLE
        PS> Invoke-MemoryCheck -MemoryManager $memoryManager -Force
 
        Forces immediate memory check and cleanup if needed
 
    .NOTES
        BUSINESS CONTEXT:
        Critical for maintaining system stability during long-running
        operations in enterprise environments with large datasets.
 
        PERFORMANCE IMPACT:
        - Minimal overhead during normal operations
        - Automatic cleanup prevents memory exhaustion
        - Detailed logging supports troubleshooting
 
        WHATIF BEHAVIOR:
        - Memory checking and cleanup operations ALWAYS execute regardless of -WhatIf
        - Only detailed logging operations respect -WhatIf
        - This ensures system health is maintained during simulations
    #>


    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [ValidateNotNull()]
        [MemoryManager]$MemoryManager,

        [Parameter()]
        [string]$CorrelationId = [System.Guid]::NewGuid().ToString(),

        [Parameter()]
        [switch]$Force
    )

    process {
        try {
            # Use MemoryManager CorrelationId if none provided
            if (-not $PSBoundParameters.ContainsKey('CorrelationId') -or -not $CorrelationId.Trim()) {
                $CorrelationId = $MemoryManager.CorrelationId
            }

            # Memory checks always execute - critical for system stability
            # Only logging respects ShouldProcess
            if ($PSCmdlet.ShouldProcess("Memory", "Check usage and cleanup if needed")) {
                Write-StructuredLog "Performing memory check..." -Level Debug -Component 'MemoryManagement' -CorrelationId $CorrelationId
            } else {
                Write-Verbose "WhatIf: Would check memory usage and cleanup if needed"
            }

            # ALWAYS perform memory operations - essential for system health
            if ($Force) {
                # Reset counter to force check
                $MemoryManager.CheckCounter = $MemoryManager.CheckInterval
            }

            # Get current memory usage for analysis
            $currentMemory = [math]::Round((Get-SystemGCTotalMemory) / 1MB, 2)
            
            $MemoryManager.CheckMemoryUsage()
            
            # Return comprehensive monitoring results
            $usagePercent = [Math]::Round(($currentMemory / $MemoryManager.MaxMemoryMB) * 100, 1)
            $memoryStatus = if ($usagePercent -gt 90) { 'Critical' } 
                           elseif ($usagePercent -gt 75) { 'High' } 
                           else { 'Normal' }
            
            $thresholdExceeded = $currentMemory -gt $MemoryManager.MaxMemoryMB
            $recommendations = @()
            
            if ($memoryStatus -eq 'High') {
                $recommendations += 'Consider running garbage collection'
            } elseif ($memoryStatus -eq 'Critical') {
                $recommendations += 'Immediate action required: Stop processing and run garbage collection'
                $recommendations += 'Consider LOH compaction for large object cleanup'
            }
            
            if ($thresholdExceeded) {
                $recommendations += 'Consider adjusting memory threshold settings'
            }

            return [PSCustomObject]@{
                CurrentMemoryMB = $currentMemory
                MaxMemoryMB = $MemoryManager.MaxMemoryMB
                ThresholdExceeded = $thresholdExceeded
                MemoryUsagePercent = [math]::Round($usagePercent, 0)
                MemoryStatus = $memoryStatus
                Recommendations = $recommendations
                MonitoringTime = Get-Date
                SystemMemoryTotal = Get-SystemGCTotalMemory
                MemoryToThresholdRatio = [math]::Round($currentMemory / $MemoryManager.MaxMemoryMB, 1)
                Gen0Collections = Get-SystemGCCollectionCount -Generation 0
                Gen1Collections = Get-SystemGCCollectionCount -Generation 1
                Gen2Collections = Get-SystemGCCollectionCount -Generation 2
                WhatIfMode = $WhatIfPreference
                CorrelationId = $CorrelationId
            }
        }
        catch {
            Write-StructuredLog "Memory check operation failed: $($_.Exception.Message)" -Level Warning -Component 'MemoryManagement' -CorrelationId $CorrelationId
            throw
        }
    }
}


function Test-MemoryThreshold {
    <#
    .SYNOPSIS
        Tests if current memory usage exceeds specified threshold
 
    .DESCRIPTION
        Evaluates current memory usage against threshold values and
        returns detailed analysis for automated decision making in
        enterprise memory management scenarios.
 
    .PARAMETER ThresholdMB
        Memory threshold in megabytes to test against
 
    .PARAMETER ThresholdType
        Type of threshold test (Warning, Critical, Emergency)
 
    .EXAMPLE
        PS> Test-MemoryThreshold -ThresholdMB 1024
 
        Tests if current memory exceeds 1024 MB
 
    .EXAMPLE
        PS> Test-MemoryThreshold -ThresholdMB 2048 -ThresholdType Critical
 
        Tests critical threshold with enhanced analysis
 
    .OUTPUTS
        [PSCustomObject] Threshold test results with recommendations
 
    .NOTES
        AUTOMATION SUPPORT:
        Enables automated memory management decisions
        based on enterprise threshold policies.
    #>


    [CmdletBinding()]
    [OutputType('MemoryThresholdResult')]
    param(
        [Parameter(Mandatory)]
        [ValidateRange(128, 32768)]
        [int]$ThresholdMB,

        [Parameter()]
        [ValidateSet('Warning', 'Critical', 'Emergency')]
        [string]$ThresholdType = 'Warning'
    )

    try {
        $currentUsage = Get-CurrentMemoryUsage
        $exceeded = $currentUsage.WorkingSetMB -gt $ThresholdMB
        $utilizationPercent = [Math]::Round(($currentUsage.WorkingSetMB / $ThresholdMB) * 100, 1)

        $result = [PSCustomObject]@{
            PSTypeName = 'MemoryThresholdResult'
            Timestamp = Get-Date
            ThresholdMB = $ThresholdMB
            ThresholdType = $ThresholdType
            CurrentMemoryMB = $currentUsage.WorkingSetMB
            ThresholdExceeded = $exceeded
            UtilizationPercent = $utilizationPercent
            Severity = if ($exceeded) {
                switch ($ThresholdType) {
                    'Warning' { 'Medium' }
                    'Critical' { 'High' }
                    'Emergency' { 'Critical' }
                }
            } else { 'Low' }
            RecommendedAction = if ($exceeded) {
                switch ($ThresholdType) {
                    'Warning' { 'Monitor and consider cleanup' }
                    'Critical' { 'Immediate garbage collection recommended' }
                    'Emergency' { 'Cleanup required immediately' }
                }
            } else { 'No action required' }
        }

        return $result
    }
    catch {
        Write-Error "Memory threshold test failed: $($_.Exception.Message)" -ErrorAction Stop
    }
}

# Functions are automatically available when dot-sourced
# Note: Export-ModuleMember is only valid in .psm1 module files