alexsusanu@docs:Windows/IIS/PowerShell LIMS Debugging Scripts $
alexsusanu@docs
:~$ cat Windows/IIS/PowerShell LIMS Debugging Scripts.md

HomeLIMS → Windows/IIS/PowerShell LIMS Debugging Scripts

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
- Open Event Viewer → Windows Logs → Application
- Look for Source column entries like: "OracleServiceORCL", "OracleDBConsoleorcl"

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
- Look for: "ORA-", "TNS-", "listener", "tablespace", "archive"

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
- Search: "Oracle Windows Event ID list"
- Common ones: 600, 601, 1000, 1001 for Oracle services

Method 3: Check Event Viewer for patterns
- Filter by Oracle sources and note frequent Event IDs

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
- Open Task Manager → Details tab
- Look for processes containing "oracle", "tnslsnr"

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
- Open IIS Manager
- Look in left panel under "Sites"

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
- Open IIS Manager → Application Pools
- Note the pool name your site uses

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
- Select your site → Logging → Directory path

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
- Look at your LIMS error documentation
- Check vendor-provided error codes

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
- Look at what URL users access LIMS
- Check SSL certificate in browser

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
- Open This PC and note drive letters

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
- Memory: Oracle typically needs 70-80% available, so 85% warning is appropriate
- Disk: Oracle needs space for logs/backups, so 80% warning is good

Method 3: Environment-specific
- Production: Lower thresholds (75% memory, 75% disk)
- Development: Higher thresholds (90% memory, 85% disk)

Access needed: System performance counters (usually default)

Last updated: 2025-08-26 20:00 UTC