Private/Invoke-InfraPulseTcpCheck.ps1
|
function Invoke-InfraPulseTcpCheck { [CmdletBinding()] param( [Parameter(Mandatory)] [psobject]$Context, [Parameter(Mandatory)] [System.Collections.IDictionary]$Settings ) $endpoints = @($Settings.Endpoints) if ($endpoints.Count -eq 0) { return New-InfraPulseResult -Status 'Skipped' -CheckName 'Tcp' -Category 'Connectivity' -ComputerName $Context.ComputerName -Target 'TCP endpoints' -Message 'No TCP endpoints are configured.' -Recommendation 'Add required host and port pairs under Checks.Tcp.Endpoints.' } $scriptBlock = { param($CheckSettings) foreach ($endpoint in @($CheckSettings.Endpoints)) { $hostName = [string]$endpoint.Host $port = [int]$endpoint.Port $displayName = if ($endpoint.Contains('Name') -and -not [string]::IsNullOrWhiteSpace([string]$endpoint.Name)) { [string]$endpoint.Name } else { "$hostName`:$port" } $timeout = if ($endpoint.Contains('TimeoutMilliseconds')) { [int]$endpoint.TimeoutMilliseconds } else { [int]$CheckSettings.TimeoutMilliseconds } $timer = [System.Diagnostics.Stopwatch]::StartNew() $client = New-Object System.Net.Sockets.TcpClient $waitHandle = $null try { $asyncResult = $client.BeginConnect($hostName, $port, $null, $null) $waitHandle = $asyncResult.AsyncWaitHandle if (-not $waitHandle.WaitOne($timeout, $false)) { throw "Connection timed out after $timeout ms." } $client.EndConnect($asyncResult) $timer.Stop() [pscustomobject]@{ Name = $displayName Host = $hostName Port = $port Success = $client.Connected DurationMs = [math]::Round($timer.Elapsed.TotalMilliseconds, 2) TimeoutMs = $timeout Error = $null } } catch { $timer.Stop() [pscustomobject]@{ Name = $displayName Host = $hostName Port = $port Success = $false DurationMs = [math]::Round($timer.Elapsed.TotalMilliseconds, 2) TimeoutMs = $timeout Error = $_.Exception.Message } } finally { if ($null -ne $waitHandle) { $waitHandle.Close() } $client.Close() } } } $raw = @(Invoke-InfraPulseCommand -Context $Context -ScriptBlock $scriptBlock -ArgumentList @($Settings)) $results = @() foreach ($endpoint in $raw) { if ([bool]$endpoint.Success) { $status = 'Healthy' $message = "Connected to $($endpoint.Host):$($endpoint.Port) in $($endpoint.DurationMs) ms." $recommendation = '' } else { $status = 'Critical' $message = "TCP connection to $($endpoint.Host):$($endpoint.Port) failed after $($endpoint.DurationMs) ms." $recommendation = 'Validate routing, firewall policy, name resolution, listener state, and service dependencies from the target host.' } $evidence = [ordered]@{ Name = [string]$endpoint.Name Host = [string]$endpoint.Host Port = [int]$endpoint.Port DurationMs = [double]$endpoint.DurationMs TimeoutMs = [int]$endpoint.TimeoutMs Error = [string]$endpoint.Error } $results += New-InfraPulseResult -Status $status -CheckName 'Tcp' -Category 'Connectivity' -ComputerName $Context.ComputerName -Target ([string]$endpoint.Name) -Message $message -ObservedValue ([bool]$endpoint.Success) -WarningThreshold $null -CriticalThreshold 'Connection failure' -Recommendation $recommendation -Evidence $evidence -DurationMs ([double]$endpoint.DurationMs) -ErrorMessage ([string]$endpoint.Error) } return $results } |