Windows/IIS/PowerShell LIMS Debugging Scripts

Additional troubleshooting tools for LIMS environments

#region Windows Event Log Analysis

1. LIMS-specific Windows Event Log analyzer


function Get-LIMSWindowsEvents {
    param(
        [int]$Hours = 24,
        [string[]]$LogNames = @("Application", "System", "Security"),
        [string[]]$Sources = @("ASP.NET", "IIS", "W3SVC", "WAS"),
        [string]$OutputPath = "C:\temp\lims_events.txt"
    )
    
    $startTime = (Get-Date).AddHours(-$Hours)
    $allEvents = @()
    
    Write-Host "Analyzing Windows Event Logs for LIMS issues..." -ForegroundColor Yellow
    
    foreach ($logName in $LogNames) {
        try {
            $events = Get-WinEvent -FilterHashtable @{
                LogName = $logName
                StartTime = $startTime
                Level = @(1,2,3,4)  # Critical, Error, Warning, Information
            } -ErrorAction SilentlyContinue
            
            # Filter for LIMS-related events
            $limsEvents = $events | Where-Object {
                $_.Message -match "IIS|ASP\.NET|w3wp|application pool|SQL|Oracle|LIMS|timeout|error|fail" -or
                $_.ProviderName -in $Sources -or
                $_.Id -in @(1000, 1001, 1002, 1309, 2001, 2002, 5011, 5186, 7034, 7035, 7036)
            }
            
            $allEvents += $limsEvents
        }
        catch {
            Write-Warning "Could not read $logName log: $($_.Exception.Message)"
        }
    }
    
    # Analyze and categorize events
    $categorizedEvents = $allEvents | ForEach-Object {
        $category = "Other"
        $severity = switch ($_.LevelDisplayName) {
            "Critical" { "CRITICAL" }
            "Error" { "ERROR" }
            "Warning" { "WARNING" }
            default { "INFO" }
        }
        
        # Categorize by content
        if ($_.Message -match "pool|w3wp|worker process") { $category = "Application Pool" }
        elseif ($_.Message -match "SQL|Oracle|database|connection") { $category = "Database" }
        elseif ($_.Message -match "authentication|login|logon|401|403") { $category = "Authentication" }
        elseif ($_.Message -match "memory|out of memory") { $category = "Memory" }
        elseif ($_.Message -match "timeout|slow|performance") { $category = "Performance" }
        elseif ($_.Message -match "certificate|SSL|TLS") { $category = "Security" }
        
        [PSCustomObject]@{
            Timestamp = $_.TimeCreated
            Severity = $severity
            Category = $category
            Source = $_.ProviderName
            EventID = $_.Id
            Message = $_.Message.Substring(0, [Math]::Min(200, $_.Message.Length))
            FullMessage = $_.Message
        }
    }
    
    # Generate report
    $report = @"
LIMS Windows Event Analysis - Last $Hours Hours
Generated: $(Get-Date)
================================================

SUMMARY BY SEVERITY:
"@
    
    $categorizedEvents | Group-Object Severity | Sort-Object Name | ForEach-Object {
        $report += "`n$($_.Name): $($_.Count) events"
    }
    
    $report += "`n`nSUMMARY BY CATEGORY:"
    $categorizedEvents | Group-Object Category | Sort-Object Count -Descending | ForEach-Object {
        $report += "`n$($_.Name): $($_.Count) events"
    }
    
    $report += "`n`nCRITICAL AND ERROR EVENTS:`n"
    $categorizedEvents | Where-Object { $_.Severity -in @("CRITICAL", "ERROR") } | 
        Sort-Object Timestamp -Descending | ForEach-Object {
        $report += "$($_.Timestamp) [$($_.Severity)] $($_.Category) - $($_.Message)`n"
    }
    
    $report | Out-File $OutputPath
    Write-Host "Event analysis saved to: $OutputPath" -ForegroundColor Green
    
    return $categorizedEvents
}

2. Process monitoring for memory leaks


function Monitor-LIMSProcessMemory {
    param(
        [string[]]$ProcessNames = @("w3wp", "sqlservr", "oracle"),
        [int]$DurationMinutes = 60,
        [int]$SampleIntervalSeconds = 60,
        [string]$OutputPath = "C:\temp\lims_memory_trend.csv"
    )
    
    $endTime = (Get-Date).AddMinutes($DurationMinutes)
    $results = @()
    
    Write-Host "Monitoring LIMS process memory for $DurationMinutes minutes..." -ForegroundColor Yellow
    Write-Host "Sample interval: $SampleIntervalSeconds seconds" -ForegroundColor Cyan
    
    while ((Get-Date) -lt $endTime) {
        foreach ($processName in $ProcessNames) {
            $processes = Get-Process -Name $processName -ErrorAction SilentlyContinue
            
            foreach ($process in $processes) {
                try {
                    $result = [PSCustomObject]@{
                        Timestamp = Get-Date
                        ProcessName = $process.Name
                        ProcessId = $process.Id
                        WorkingSetMB = [math]::Round($process.WorkingSet64 / 1MB, 2)
                        PrivateMemoryMB = [math]::Round($process.PrivateMemorySize64 / 1MB, 2)
                        VirtualMemoryMB = [math]::Round($process.VirtualMemorySize64 / 1MB, 2)
                        PagedMemoryMB = [math]::Round($process.PagedMemorySize64 / 1MB, 2)
                        HandleCount = $process.Handles
                        ThreadCount = $process.Threads.Count
                        CPUTime = $process.TotalProcessorTime.TotalSeconds
                        StartTime = $process.StartTime
                    }
                    
                    $results += $result
                    Write-Host "$(Get-Date -Format 'HH:mm:ss') - $($process.Name)($($process.Id)): $($result.WorkingSetMB)MB" -ForegroundColor Gray
                }
                catch {
                    Write-Warning "Could not get details for $($process.Name): $($_.Exception.Message)"
                }
            }
        }
        
        Start-Sleep $SampleIntervalSeconds
    }
    
    # Save results and analyze trends
    $results | Export-Csv $OutputPath -NoTypeInformation
    
    Write-Host "`nMemory trend analysis:" -ForegroundColor Yellow
    $results | Group-Object ProcessName | ForEach-Object {
        $processData = $_.Group | Sort-Object Timestamp
        $first = $processData | Select-Object -First 1
        $last = $processData | Select-Object -Last 1
        $growth = $last.WorkingSetMB - $first.WorkingSetMB
        
        Write-Host "$($_.Name): Started at $($first.WorkingSetMB)MB, ended at $($last.WorkingSetMB)MB (Growth: $([math]::Round($growth,2))MB)" -ForegroundColor Cyan
        
        if ($growth -gt 100) {
            Write-Host "  WARNING: Significant memory growth detected!" -ForegroundColor Red
        }
    }
    
    Write-Host "Detailed data saved to: $OutputPath" -ForegroundColor Green
    return $results
}

#endregion

#region IIS Configuration Analysis

3. IIS configuration validator for LIMS


function Test-LIMSIISConfiguration {
    param(
        [string]$SiteName = "Default Web Site",
        [string]$AppPoolName,
        [string[]]$CriticalPaths = @("C:\inetpub\wwwroot\uploads", "C:\inetpub\wwwroot\temp")
    )
    
    Import-Module WebAdministration -ErrorAction SilentlyContinue
    
    $issues = @()
    $recommendations = @()
    
    Write-Host "Validating IIS configuration for LIMS..." -ForegroundColor Yellow
    
    try {
        # Check application pool settings
        if ($AppPoolName) {
            $appPool = Get-IISAppPool -Name $AppPoolName -ErrorAction SilentlyContinue
            if ($appPool) {
                # Check critical app pool settings
                if ($appPool.ProcessModel.IdleTimeout.TotalMinutes -gt 0) {
                    $issues += "App pool idle timeout is set to $($appPool.ProcessModel.IdleTimeout.TotalMinutes) minutes"
                    $recommendations += "Set idle timeout to 0 for LIMS (always-on application)"
                }
                
                if ($appPool.Recycling.PeriodicRestart.Time.TotalHours -lt 24) {
                    $issues += "App pool recycles every $($appPool.Recycling.PeriodicRestart.Time.TotalHours) hours"
                    $recommendations += "Consider increasing recycle time for LIMS stability"
                }
                
                if ($appPool.ProcessModel.MaxProcesses -ne 1) {
                    $issues += "App pool max processes is $($appPool.ProcessModel.MaxProcesses)"
                    $recommendations += "LIMS typically works best with MaxProcesses = 1"
                }
            }
        }
        
        # Check site configuration
        $site = Get-IISSite -Name $SiteName -ErrorAction SilentlyContinue
        if ($site) {
            # Check request limits
            $config = Get-WebConfiguration -Filter "system.webserver/security/requestFiltering/requestLimits" -PSPath "IIS:\Sites\$SiteName"
            if ($config.maxAllowedContentLength -lt 52428800) {  # 50MB
                $issues += "Max upload size is only $([math]::Round($config.maxAllowedContentLength/1MB,1))MB"
                $recommendations += "Increase maxAllowedContentLength for LIMS file uploads"
            }
            
            # Check timeout settings
            $httpRuntime = Get-WebConfiguration -Filter "system.web/httpRuntime" -PSPath "IIS:\Sites\$SiteName" -ErrorAction SilentlyContinue
            if ($httpRuntime -and $httpRuntime.executionTimeout.TotalSeconds -lt 900) {  # 15 minutes
                $issues += "Execution timeout is only $($httpRuntime.executionTimeout.TotalSeconds) seconds"
                $recommendations += "Increase execution timeout for long-running LIMS operations"
            }
        }
        
        # Check critical directories
        foreach ($path in $CriticalPaths) {
            if (-not (Test-Path $path)) {
                $issues += "Critical directory missing: $path"
                $recommendations += "Create directory: $path"
            } else {
                # Check permissions
                $acl = Get-Acl $path
                $hasIISAccess = $acl.Access | Where-Object { 
                    $_.IdentityReference -like "*IIS_IUSRS*" -or 
                    $_.IdentityReference -like "*IUSR*" 
                }
                if (-not $hasIISAccess) {
                    $issues += "IIS may not have access to: $path"
                    $recommendations += "Grant IIS_IUSRS modify permissions to: $path"
                }
            }
        }
        
        # Check .NET version
        $aspNetVersion = Get-WebConfiguration -Filter "system.webserver/aspNetCore" -PSPath "IIS:\Sites\$SiteName" -ErrorAction SilentlyContinue
        if (-not $aspNetVersion) {
            $frameworkVersion = Get-WebConfiguration -Filter "system.web/compilation" -PSPath "IIS:\Sites\$SiteName" -ErrorAction SilentlyContinue
            if ($frameworkVersion -and $frameworkVersion.targetFramework -lt "4.7") {
                $issues += ".NET Framework version is $($frameworkVersion.targetFramework)"
                $recommendations += "Consider upgrading to .NET Framework 4.7+ for better performance"
            }
        }
        
        # Results
        $result = [PSCustomObject]@{
            SiteName = $SiteName
            AppPoolName = $AppPoolName
            IssuesFound = $issues.Count
            Issues = $issues
            Recommendations = $recommendations
            Timestamp = Get-Date
        }
        
        # Display results
        Write-Host "`nIIS Configuration Analysis Results:" -ForegroundColor Green
        if ($issues.Count -eq 0) {
            Write-Host "✓ No configuration issues found" -ForegroundColor Green
        } else {
            Write-Host "⚠ Found $($issues.Count) configuration issues:" -ForegroundColor Yellow
            $issues | ForEach-Object { Write-Host "  - $_" -ForegroundColor Red }
            
            Write-Host "`nRecommendations:" -ForegroundColor Cyan
            $recommendations | ForEach-Object { Write-Host "  + $_" -ForegroundColor Green }
        }
        
        return $result
    }
    catch {
        Write-Error "Failed to analyze IIS configuration: $($_.Exception.Message)"
    }
}

4. IIS log analysis for specific error patterns

log path is a placeholder

need site id and drive F: or C: etc

the error patterns is not exhaustive


function Find-LIMSSpecificErrors {
    param(
        [string]$LogPath = "<F:\inetpub\logs\LogFiles\W3SVC1>",
        [int]$Hours = 24,
        [hashtable]$ErrorPatterns = @{
            "File_Upload_Errors" = @("413", "Request Entity Too Large", "maxAllowedContentLength")
            "Database_Errors" = @("timeout", "deadlock", "connection", "pool")
            "Authentication_Errors" = @("401", "403", "authentication", "login")
            "Session_Errors" = @("session", "viewstate", "timeout")
            "Memory_Errors" = @("out.*memory", "heap", "gc")
            "Integration_Errors" = @("instrument", "external", "api", "service")
        }
    )
    
    $startTime = (Get-Date).AddHours(-$Hours)
    $findings = @{}
    
    Write-Host "Analyzing IIS logs for LIMS-specific error patterns..." -ForegroundColor Yellow
    
    foreach ($pattern in $ErrorPatterns.GetEnumerator()) {
        $findings[$pattern.Key] = @()
    }
    
    Get-ChildItem "$LogPath\*.log" | Where-Object { $_.LastWriteTime -ge $startTime } | ForEach-Object {
        $content = Get-Content $_.FullName
        $fields = ($content | Where-Object { $_ -like "#Fields:*" } | Select-Object -First 1) -replace "#Fields: ", "" -split " "
        
        $content | Where-Object { $_ -notlike "#*" -and $_ -ne "" } | ForEach-Object {
            $line = $_
            $values = $_ -split " "
            
            if ($values.Length -ge $fields.Length) {
                $entry = @{}
                for ($i = 0; $i -lt $fields.Length; $i++) {
                    $entry[$fields[$i]] = $values[$i]
                }
                
                foreach ($patternGroup in $ErrorPatterns.GetEnumerator()) {
                    foreach ($pattern in $patternGroup.Value) {
                        if ($line -match $pattern) {
                            $findings[$patternGroup.Key] += [PSCustomObject]@{
                                Timestamp = "$($entry['date']) $($entry['time'])"
                                URL = $entry['cs-uri-stem']
                                Status = $entry['sc-status']
                                ClientIP = $entry['c-ip']
                                UserAgent = $entry['cs(User-Agent)']
                                TimeTaken = $entry['time-taken']
                                Pattern = $pattern
                                FullLine = $line
                            }
                            break
                        }
                    }
                }
            }
        }
    }
    
    # Report findings
    Write-Host "`nLIMS Error Pattern Analysis:" -ForegroundColor Green
    foreach ($finding in $findings.GetEnumerator()) {
        if ($finding.Value.Count -gt 0) {
            Write-Host "`n$($finding.Key): $($finding.Value.Count) occurrences" -ForegroundColor Yellow
            $finding.Value | Group-Object Pattern | ForEach-Object {
                Write-Host "  $($_.Name): $($_.Count) times" -ForegroundColor Cyan
            }
            
            # Show recent examples
            $recent = $finding.Value | Sort-Object Timestamp -Descending | Select-Object -First 3
            $recent | ForEach-Object {
                Write-Host "    $($_.Timestamp) - $($_.URL) - $($_.Status)" -ForegroundColor Gray
            }
        }
    }
    
    return $findings
}

#endregion

#region Network and Connectivity

5. LIMS network dependency checker


function Test-LIMSConnectivity {
    param(
        [hashtable]$Endpoints = @{
            "Database_Server" = @{ Server = "localhost"; Port = 1521; Type = "Oracle" }
            "File_Server" = @{ Server = "fileserver"; Port = 445; Type = "SMB" }
            "Email_Server" = @{ Server = "mailserver"; Port = 25; Type = "SMTP" }
            "Web_Service" = @{ Server = "api.vendor.com"; Port = 443; Type = "HTTPS" }
        },
        [int]$TimeoutSeconds = 10
    )
    
    $results = @()
    
    Write-Host "Testing LIMS network connectivity..." -ForegroundColor Yellow
    
    foreach ($endpoint in $Endpoints.GetEnumerator()) {
        $name = $endpoint.Key
        $config = $endpoint.Value
        
        Write-Host "Testing $name ($($config.Server):$($config.Port))..." -ForegroundColor Cyan
        
        try {
            $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
            
            switch ($config.Type) {
                "Oracle" {
                    $tcpTest = Test-NetConnection -ComputerName $config.Server -Port $config.Port -WarningAction SilentlyContinue
                    $status = if ($tcpTest.TcpTestSucceeded) { "Connected" } else { "Failed" }
                    $detail = if ($tcpTest.TcpTestSucceeded) { "TCP connection successful" } else { "TCP connection failed" }
                }
                "SMB" {
                    $tcpTest = Test-NetConnection -ComputerName $config.Server -Port $config.Port -WarningAction SilentlyContinue
                    $status = if ($tcpTest.TcpTestSucceeded) { "Connected" } else { "Failed" }
                    $detail = if ($tcpTest.TcpTestSucceeded) { "SMB port accessible" } else { "SMB port blocked" }
                }
                "SMTP" {
                    $tcpTest = Test-NetConnection -ComputerName $config.Server -Port $config.Port -WarningAction SilentlyContinue
                    $status = if ($tcpTest.TcpTestSucceeded) { "Connected" } else { "Failed" }
                    $detail = if ($tcpTest.TcpTestSucceeded) { "SMTP port accessible" } else { "SMTP port blocked" }
                }
                "HTTPS" {
                    try {
                        $response = Invoke-WebRequest "https://$($config.Server)" -UseBasicParsing -TimeoutSec $TimeoutSeconds
                        $status = "Connected"
                        $detail = "HTTP $($response.StatusCode) - $($response.StatusDescription)"
                    }
                    catch {
                        $status = "Failed"
                        $detail = $_.Exception.Message
                    }
                }
                default {
                    $tcpTest = Test-NetConnection -ComputerName $config.Server -Port $config.Port -WarningAction SilentlyContinue
                    $status = if ($tcpTest.TcpTestSucceeded) { "Connected" } else { "Failed" }
                    $detail = "Generic TCP test"
                }
            }
            
            $stopwatch.Stop()
            
            $result = [PSCustomObject]@{
                Endpoint = $name
                Server = $config.Server
                Port = $config.Port
                Type = $config.Type
                Status = $status
                ResponseTime = $stopwatch.ElapsedMilliseconds
                Detail = $detail
                Timestamp = Get-Date
            }
            
            $results += $result
            
            $color = if ($status -eq "Connected") { "Green" } else { "Red" }
            Write-Host "  $status - $($stopwatch.ElapsedMilliseconds)ms - $detail" -ForegroundColor $color
        }
        catch {
            $result = [PSCustomObject]@{
                Endpoint = $name
                Server = $config.Server
                Port = $config.Port
                Type = $config.Type
                Status = "Error"
                ResponseTime = -1
                Detail = $_.Exception.Message
                Timestamp = Get-Date
            }
            
            $results += $result
            Write-Host "  Error - $($_.Exception.Message)" -ForegroundColor Red
        }
    }
    
    # Summary
    $connected = ($results | Where-Object { $_.Status -eq "Connected" }).Count
    $total = $results.Count
    
    Write-Host "`nConnectivity Summary: $connected/$total endpoints accessible" -ForegroundColor $(if ($connected -eq $total) { "Green" } else { "Yellow" })
    
    return $results
}

6. Certificate expiration checker


function Test-LIMSCertificates {
    param(
        [string[]]$Hostnames = @("localhost", "lims.domain.com"),
        [int]$WarningDays = 30
    )
    
    $results = @()
    
    Write-Host "Checking SSL certificates for LIMS..." -ForegroundColor Yellow
    
    foreach ($hostname in $Hostnames) {
        try {
            Write-Host "Checking certificate for $hostname..." -ForegroundColor Cyan
            
            $tcpClient = New-Object System.Net.Sockets.TcpClient
            $tcpClient.Connect($hostname, 443)
            
            $sslStream = New-Object System.Net.Security.SslStream($tcpClient.GetStream())
            $sslStream.AuthenticateAsClient($hostname)
            
            $cert = $sslStream.RemoteCertificate
            $x509cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($cert)
            
            $daysUntilExpiry = ($x509cert.NotAfter - (Get-Date)).Days
            $status = if ($daysUntilExpiry -le 0) { "Expired" } 
                     elseif ($daysUntilExpiry -le $WarningDays) { "Warning" } 
                     else { "OK" }
            
            $result = [PSCustomObject]@{
                Hostname = $hostname
                Subject = $x509cert.Subject
                Issuer = $x509cert.Issuer
                NotBefore = $x509cert.NotBefore
                NotAfter = $x509cert.NotAfter
                DaysUntilExpiry = $daysUntilExpiry
                Status = $status
                Thumbprint = $x509cert.Thumbprint
            }
            
            $results += $result
            
            $color = switch ($status) {
                "OK" { "Green" }
                "Warning" { "Yellow" }
                "Expired" { "Red" }
            }
            
            Write-Host "  $status - Expires in $daysUntilExpiry days ($($x509cert.NotAfter))" -ForegroundColor $color
            
            $sslStream.Close()
            $tcpClient.Close()
        }
        catch {
            Write-Host "  Failed to check certificate: $($_.Exception.Message)" -ForegroundColor Red
            
            $result = [PSCustomObject]@{
                Hostname = $hostname
                Subject = "N/A"
                Issuer = "N/A"
                NotBefore = $null
                NotAfter = $null
                DaysUntilExpiry = -999
                Status = "Error"
                Thumbprint = "N/A"
                Error = $_.Exception.Message
            }
            
            $results += $result
        }
    }
    
    return $results
}

#endregion

#region System Resource Monitoring

7. System resource checker for LIMS


function Get-LIMSSystemResources {
    param(
        [string[]]$Drives = @("C:", "D:", "F:"),
        [int]$MemoryWarningPercent = 85,
        [int]$DiskWarningPercent = 80
    )
    
    Write-Host "Checking LIMS system resources..." -ForegroundColor Yellow
    
    $results = @{
        Memory = $null
        Drives = @()
        CPU = $null
        Network = @()
        Timestamp = Get-Date
    }
    
    # Memory check
    $memory = Get-CimInstance -ClassName Win32_OperatingSystem
    $totalMemoryGB = [math]::Round($memory.TotalVisibleMemorySize / 1MB, 2)
    $freeMemoryGB = [math]::Round($memory.FreePhysicalMemory / 1MB, 2)
    $usedMemoryGB = $totalMemoryGB - $freeMemoryGB
    $memoryPercent = [math]::Round(($usedMemoryGB / $totalMemoryGB) * 100, 1)
    
    $results.Memory = [PSCustomObject]@{
        TotalGB = $totalMemoryGB
        UsedGB = $usedMemoryGB
        FreeGB = $freeMemoryGB
        UsedPercent = $memoryPercent
        Status = if ($memoryPercent -gt $MemoryWarningPercent) { "Warning" } else { "OK" }
    }
    
    Write-Host "Memory: $usedMemoryGB/$totalMemoryGB GB ($memoryPercent%)" -ForegroundColor $(if ($memoryPercent -gt $MemoryWarningPercent) { "Yellow" } else { "Green" })
    
    # Disk space check
    foreach ($drive in $Drives) {
        try {
            $disk = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $drive }
            if ($disk) {
                $totalGB = [math]::Round($disk.Size / 1GB, 2)
                $freeGB = [math]::Round($disk.FreeSpace / 1GB, 2)
                $usedGB = $totalGB - $freeGB
                $usedPercent = [math]::Round(($usedGB / $totalGB) * 100, 1)
                
                $driveResult = [PSCustomObject]@{
                    Drive = $drive
                    TotalGB = $totalGB
                    UsedGB = $usedGB
                    FreeGB = $freeGB
                    UsedPercent = $usedPercent
                    Status = if ($usedPercent -gt $DiskWarningPercent) { "Warning" } else { "OK" }
                }
                
                $results.Drives += $driveResult
                
                Write-Host "Drive $drive`: $usedGB/$totalGB GB ($usedPercent%)" -ForegroundColor $(if ($usedPercent -gt $DiskWarningPercent) { "Yellow" } else { "Green" })
            }
        }
        catch {
            Write-Warning "Could not check drive $drive`: $($_.Exception.Message)"
        }
    }
    
    # CPU check (average over 5 seconds)
    $cpu = Get-CimInstance -ClassName Win32_Processor | Measure-Object -Property LoadPercentage -Average
    $cpuPercent = [math]::Round($cpu.Average, 1)
    
    $results.CPU = [PSCustomObject]@{
        UsedPercent = $cpuPercent
        Status = if ($cpuPercent -gt 80) { "High" } elseif ($cpuPercent -gt 60) { "Medium" } else { "Normal" }
    }
    
    Write-Host "CPU: $cpuPercent%" -ForegroundColor $(if ($cpuPercent -gt 80) { "Red" } elseif ($cpuPercent -gt 60) { "Yellow" } else { "Green" })
    
    # Network adapters
    $adapters = Get-NetAdapter | Where-Object { $_.Status -eq "Up" -and $_.MediaType -eq "802.3" }
    foreach ($adapter in $adapters) {
        $results.Network += [PSCustomObject]@{
            Name = $adapter.Name
            LinkSpeed = $adapter.LinkSpeed
            Status = $adapter.Status
        }
    }
    
    return $results
}

#endregion

Usage examples and quick commands

Write-Host @"

ADDITIONAL LIMS DEBUGGING COMMANDS:

===================================

1. Windows Event Analysis:

Get-LIMSWindowsEvents -Hours 12

2. Memory Leak Detection:

Monitor-LIMSProcessMemory -DurationMinutes 30

3. IIS Configuration Check:

Test-LIMSIISConfiguration -SiteName "Default Web Site" -AppPoolName "LIMSAppPool"

4. Specific Error Pattern Analysis:

Find-LIMSSpecificErrors -Hours 6

5. Network Connectivity Test:

Test-LIMSConnectivity

6. Certificate Expiration Check:

Test-LIMSCertificates -Hostnames @("lims.company.com", "api.company.com")

7. System Resource Check:

Get-LIMSSystemResources

"@ -ForegroundColor Green

PowerShell LIMS Functions - Placeholder Guide

Function 1: `Get-LIMSWindowsEvents`

Placeholder 1: Output Path


[string]$OutputPath = "C:\temp\lims_events.txt"

How to find/choose:

Method 1: Check if C:\temp exists


dir C:\temp

If it doesn't exist: mkdir C:\temp or use different path

Method 2: Use your user profile temp


$env:TEMP\lims_events.txt
# Usually: C:\Users\YourName\AppData\Local\Temp\lims_events.txt

Method 3: Check where you have write permissions


Test-Path "C:\temp" -PathType Container
Test-Path "D:\logs" -PathType Container  

Access needed: Write permissions to chosen directory

---

Placeholder 2: Event Sources


[string[]]$Sources = @("ASP.NET", "IIS", "W3SVC", "WAS")

How to find Oracle-specific sources:

Method 1: Check what Oracle sources exist in Event Viewer


Get-WinEvent -ListProvider * | Where-Object {$_.Name -like "*Oracle*"}

Method 2: Look at recent Oracle events


Get-WinEvent -FilterHashtable @{LogName="Application"} | 
  Where-Object {$_.ProviderName -like "*Oracle*"} | 
  Select-Object ProviderName -Unique

Method 3: Check Event Viewer GUI

Examples you might find:


@("OracleServiceORCL", "OracleDBConsoleorcl", "Oracle.DataAccess", "TNSListener")

Access needed: Read access to Event Logs (usually default)

---

Placeholder 3: Search Pattern


$_.Message -match "IIS|ASP\.NET|w3wp|application pool|SQL|Oracle|LIMS|timeout|error|fail"

How to find Oracle-specific terms:

Method 1: Search existing logs for Oracle errors


Get-WinEvent -FilterHashtable @{LogName="Application"; StartTime=(Get-Date).AddDays(-1)} | 
  Where-Object {$_.Message -like "*Oracle*"} | 
  Select-Object -First 5 -Property Message

Method 2: Check Oracle documentation for common error terms

Method 3: Check your LIMS application logs


findstr /i "oracle error fail" "C:\path\to\lims\logs\*.log"

Better pattern for Oracle:


"Oracle|ORA-|TNS-|listener|tablespace|archive|deadlock|LIMS|timeout|error|fail"

Access needed: Read access to application log directories

---

Placeholder 4: Event IDs


$_.Id -in @(1000, 1001, 1002, 1309, 2001, 2002, 5011, 5186, 7034, 7035, 7036)

How to find Oracle-specific Event IDs:

Method 1: Check recent Oracle events for common IDs


Get-WinEvent -FilterHashtable @{LogName="Application"; StartTime=(Get-Date).AddDays(-7)} | 
  Where-Object {$_.ProviderName -like "*Oracle*"} | 
  Group-Object Id | Sort-Object Count -Descending

Method 2: Look up Oracle Windows Event IDs online

Method 3: Check Event Viewer for patterns

Oracle-specific IDs you might add:


@(600, 601, 1000, 1001, 1002, 1309, 2001, 2002, 5011, 5186, 7034, 7035, 7036)

Access needed: Read access to Event Logs

---

Customized Function 1 for Oracle

Example usage:


Get-LIMSWindowsEvents -Hours 12 `
  -Sources @("OracleServiceORCL", "OracleDBConsoleorcl", "TNSListener") `
  -OutputPath "$env:TEMP\oracle_lims_events.txt"

Most critical to customize: Output path and Sources array. The search pattern and Event IDs can stay generic initially.

---

Function 2: `Monitor-LIMSProcessMemory`

Placeholder 1: Process Names


[string[]]$ProcessNames = @("w3wp", "sqlservr", "oracle")

How to find Oracle process names:

Method 1: Check running Oracle processes


Get-Process | Where-Object {$_.Name -like "*oracle*"}

Method 2: Check Windows Services


Get-Service | Where-Object {$_.Name -like "*oracle*"} | Select-Object Name, DisplayName

Method 3: Task Manager

Common Oracle process names:


@("oracle", "tnslsnr", "oracleoradb19home1tnslistener", "w3wp")

Access needed: Read access to process information (usually default)

---

Placeholder 2: Output Path


[string]$OutputPath = "C:\temp\lims_memory_trend.csv"

How to find/choose:

Method 1: Use temp directory


"$env:TEMP\oracle_memory_trend.csv"

Method 2: Check writable locations


Test-Path "C:\temp" -PathType Container
Test-Path "C:\logs" -PathType Container

Method 3: Use current directory


".\oracle_memory_trend.csv"

Access needed: Write permissions to chosen directory

---

Placeholder 3: Duration and Interval


[int]$DurationMinutes = 60,
[int]$SampleIntervalSeconds = 60

How to choose appropriate values:

Method 1: For troubleshooting active issues


-DurationMinutes 30 -SampleIntervalSeconds 30

Method 2: For trend analysis


-DurationMinutes 240 -SampleIntervalSeconds 120  # 4 hours, 2-minute samples

Method 3: For memory leak detection


-DurationMinutes 480 -SampleIntervalSeconds 300  # 8 hours, 5-minute samples

Access needed: None, these are just timing preferences

---

Function 3: `Test-LIMSIISConfiguration`

Placeholder 1: Site Name


[string]$SiteName = "Default Web Site"

How to find your IIS site name:

Method 1: PowerShell (if WebAdministration module available)


Import-Module WebAdministration
Get-IISSite | Select-Object Name, State

Method 2: IIS Manager GUI

Method 3: Command line


%windir%\system32\inetsrv\appcmd list site

Common site names:


"Default Web Site"
"Oracle LIMS"
"LIMS Application"

Access needed: IIS read permissions, Administrative rights preferred

---

Placeholder 2: Application Pool Name


[string]$AppPoolName

How to find application pool name:

Method 1: PowerShell


Get-IISAppPool | Select-Object Name, State

Method 2: IIS Manager

Method 3: Check site configuration


Get-IISSite -Name "YourSiteName" | Select-Object Applications

Common pool names:


"DefaultAppPool"
"LIMSAppPool" 
"OracleLIMSPool"

Access needed: IIS configuration read access

---

Placeholder 3: Critical Paths


[string[]]$CriticalPaths = @("C:\inetpub\wwwroot\uploads", "C:\inetpub\wwwroot\temp")

How to find your application paths:

Method 1: Check IIS site physical path


Get-IISSite -Name "YourSiteName" | Select-Object PhysicalPath

Method 2: Look in web.config


<!-- Look for paths like: -->
<add key="UploadPath" value="C:\LIMS\uploads" />
<add key="TempPath" value="C:\LIMS\temp" />

Method 3: Check application directories


dir "C:\inetpub\wwwroot"
dir "C:\Program Files\LIMS"

Access needed: File system read access to web directories

---

Function 4: `Find-LIMSSpecificErrors`

Placeholder 1: Log Path


[string]$LogPath = "C:\inetpub\logs\LogFiles\W3SVC1"

How to find IIS log location:

Method 1: Check IIS site logging settings


Get-IISSite -Name "YourSiteName" | Get-WebConfiguration -Filter "system.webServer/httpLogging"

Method 2: IIS Manager

Method 3: Default locations to check


dir "C:\inetpub\logs\LogFiles"
dir "C:\Windows\System32\LogFiles"

Common log paths:


C:\inetpub\logs\LogFiles\W3SVC1
C:\inetpub\logs\LogFiles\W3SVC2

Access needed: Read access to IIS log directory

---

Placeholder 2: Error Patterns


[hashtable]$ErrorPatterns = @{
    "File_Upload_Errors" = @("413", "Request Entity Too Large", "maxAllowedContentLength")
    "Database_Errors" = @("timeout", "deadlock", "connection", "pool")
    # ... more patterns
}

How to customize for Oracle:

Method 1: Add Oracle-specific patterns


"Oracle_Errors" = @("ORA-", "TNS-", "Oracle", "listener")
"LIMS_Errors" = @("LIMS", "sample", "result", "instrument")

Method 2: Check existing logs for common errors


Select-String -Path "C:\inetpub\logs\LogFiles\W3SVC1\*.log" -Pattern "error|fail|exception" | Select-Object -First 10

Method 3: Review application-specific errors

Access needed: Read access to log files

---

Function 5: `Test-LIMSConnectivity`

Placeholder 1: Endpoints Configuration


[hashtable]$Endpoints = @{
    "Database_Server" = @{ Server = "localhost"; Port = 1521; Type = "Oracle" }
    "File_Server" = @{ Server = "fileserver"; Port = 445; Type = "SMB" }
    # ... more endpoints
}

How to find your Oracle connection details:

Method 1: Check LIMS configuration files


findstr /i "server\|host\|port" "C:\Program Files\LIMS\*.config"
findstr /i "server\|host\|port" "C:\inetpub\wwwroot\LIMS\*.config"

Method 2: Check TNS names file


type "%ORACLE_HOME%\network\admin\tnsnames.ora"

Method 3: Check connection strings in web.config


<connectionStrings>
  <add name="Oracle" connectionString="Data Source=oracleserver:1521/ORCL;..." />
</connectionStrings>

Real example:


@{
    "Oracle_LIMS_DB" = @{ Server = "oraprod01.company.com"; Port = 1521; Type = "Oracle" }
    "Oracle_Backup" = @{ Server = "192.168.1.55"; Port = 1521; Type = "Oracle" }
    "File_Share" = @{ Server = "fileserver01"; Port = 445; Type = "SMB" }
}

Access needed: Read access to configuration files, or ask DBA for connection details

---

Function 6: `Test-LIMSCertificates`

Placeholder 1: Hostnames


[string[]]$Hostnames = @("localhost", "lims.domain.com")

How to find your LIMS hostnames:

Method 1: Check IIS site bindings


Get-IISSite | Get-IISBinding | Where-Object {$_.Protocol -eq "https"}

Method 2: Check your LIMS URL

Method 3: Check configuration files


findstr /i "https\|ssl" "C:\Program Files\LIMS\*.config"

Examples:


@("lims.yourcompany.com", "oraclelims.internal.com", "api.lims.com")

Access needed: Read access to IIS configuration

---

Function 7: `Get-LIMSSystemResources`

Placeholder 1: Drive Letters


[string[]]$Drives = @("C:", "D:", "F:")

How to find your system drives:

Method 1: PowerShell


Get-PSDrive -PSProvider FileSystem | Select-Object Name, Used, Free

Method 2: Command prompt


wmic logicaldisk get deviceid,size,freespace

Method 3: File Explorer

Access needed: Basic file system access (usually default)

---

Placeholder 2: Warning Thresholds


[int]$MemoryWarningPercent = 85,
[int]$DiskWarningPercent = 80

How to choose appropriate thresholds:

Method 1: Check current usage


Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object @{Name="MemoryUsage";Expression={[math]::Round(($_.TotalVisibleMemorySize - $_.FreePhysicalMemory) / $_.TotalVisibleMemorySize * 100, 1)}}

Method 2: Oracle recommendations

Method 3: Environment-specific

Access needed: System performance counters (usually default)