Public/network/Get-NetworkStatistic.ps1

#Requires -Version 5.1

function Get-NetworkStatistic {
    <#
        .SYNOPSIS
            Retrieves network connection statistics grouped by process
 
        .DESCRIPTION
            Aggregates TCP and UDP connection data by process, providing a summary view
            of how many connections each process holds in each state. Internally calls
            Get-NetworkConnection to collect raw connection data, then groups and counts
            by process name and connection state.
 
            This function is ideal for identifying which processes consume the most
            network connections or hold stale connections.
 
        .PARAMETER ComputerName
            One or more computer names to query. Accepts pipeline input by value and
            by property name. Defaults to the local machine ($env:COMPUTERNAME).
 
        .PARAMETER Credential
            Optional PSCredential for authenticating to remote machines. Ignored for
            local machine queries.
 
        .PARAMETER Protocol
            Filter by protocol before aggregation. Valid values: TCP, UDP.
            By default both are included.
 
        .PARAMETER State
            Filter TCP connections by state before aggregation (e.g. Established, Listen).
            Ignored for UDP endpoints.
 
        .PARAMETER ProcessName
            Filter by owning process name before aggregation. Supports wildcards.
 
        .EXAMPLE
            Get-NetworkStatistic
 
            Returns connection count summary grouped by process on the local machine.
 
        .EXAMPLE
            Get-NetworkStatistic -ComputerName 'SRV01' -Protocol TCP
 
            Returns TCP connection statistics grouped by process on SRV01.
 
        .EXAMPLE
            'SRV01', 'SRV02' | Get-NetworkStatistic
 
            Aggregates connection statistics by process across two remote servers.
 
        .EXAMPLE
            Get-NetworkStatistic -ProcessName 'w3wp'
 
            Shows connection breakdown for the IIS worker process only.
 
        .OUTPUTS
            PSWinOps.NetworkStatistic
            Summary of network connections per process including counts by state.
 
        .NOTES
            Author: Franck SALLET
            Version: 3.0.0
            Last Modified: 2026-03-23
            Requires: PowerShell 5.1+ / Windows only
            Permissions: No admin required for basic queries
            Remote: Requires WinRM / WS-Man enabled on target machines
 
        .LINK
            https://github.com/k9fr4n/PSWinOps
 
        .LINK
            https://learn.microsoft.com/en-us/powershell/module/nettcpip/get-nettcpconnection
    #>

    [CmdletBinding()]
    [OutputType('PSWinOps.NetworkStatistic')]
    param(
        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [Alias('CN', 'Name', 'DNSHostName')]
        [string[]]$ComputerName = $env:COMPUTERNAME,

        [Parameter(Mandatory = $false)]
        [PSCredential]$Credential,

        [Parameter(Mandatory = $false)]
        [ValidateSet('TCP', 'UDP')]
        [string[]]$Protocol = @('TCP', 'UDP'),

        [Parameter(Mandatory = $false)]
        [ValidateSet('Bound', 'Closed', 'CloseWait', 'Closing', 'DeleteTCB',
            'Established', 'FinWait1', 'FinWait2', 'LastAck', 'Listen',
            'SynReceived', 'SynSent', 'TimeWait')]
        [string[]]$State,

        [Parameter(Mandatory = $false)]
        [SupportsWildcards()]
        [string]$ProcessName
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand)] Starting network statistics aggregation"
    }

    process {
        foreach ($targetComputer in $ComputerName) {
            try {
                $timestamp = Get-Date -Format 'o'

                Write-Verbose "[$($MyInvocation.MyCommand)] Aggregating connections on '$targetComputer'"

                # Build splat for Get-NetworkConnection
                $connParams = @{
                    ComputerName = $targetComputer
                    ErrorAction  = 'Stop'
                }
                if ($PSBoundParameters.ContainsKey('Credential'))  { $connParams['Credential']  = $Credential }
                if ($PSBoundParameters.ContainsKey('Protocol'))    { $connParams['Protocol']    = $Protocol }
                if ($PSBoundParameters.ContainsKey('State'))       { $connParams['State']       = $State }
                if ($PSBoundParameters.ContainsKey('ProcessName')) { $connParams['ProcessName'] = $ProcessName }

                $connections = @(Get-NetworkConnection @connParams)

                if ($connections.Count -eq 0) {
                    Write-Verbose "[$($MyInvocation.MyCommand)] No connections found on '$targetComputer'"
                    continue
                }

                # Group by ProcessName + ProcessId
                $grouped = $connections | Group-Object -Property ProcessName, ProcessId

                foreach ($group in $grouped) {
                    $items = $group.Group
                    $firstItem = $items[0]

                    [PSCustomObject]@{
                        PSTypeName       = 'PSWinOps.NetworkStatistic'
                        ComputerName     = $targetComputer
                        ProcessName      = $firstItem.ProcessName
                        ProcessId        = $firstItem.ProcessId
                        TcpEstablished   = @($items | Where-Object { $_.Protocol -eq 'TCP' -and $_.State -eq 'Established' }).Count
                        TcpListening     = @($items | Where-Object { $_.Protocol -eq 'TCP' -and $_.State -eq 'Listen' }).Count
                        TcpTimeWait      = @($items | Where-Object { $_.Protocol -eq 'TCP' -and $_.State -eq 'TimeWait' }).Count
                        TcpCloseWait     = @($items | Where-Object { $_.Protocol -eq 'TCP' -and $_.State -eq 'CloseWait' }).Count
                        TcpOther         = @($items | Where-Object { $_.Protocol -eq 'TCP' -and $_.State -notin @('Established', 'Listen', 'TimeWait', 'CloseWait') }).Count
                        UdpEndpoints     = @($items | Where-Object { $_.Protocol -eq 'UDP' }).Count
                        TotalConnections = $items.Count
                        Timestamp        = $timestamp
                    }
                }
            } catch {
                Write-Error "[$($MyInvocation.MyCommand)] Failed on '$targetComputer': $_"
            }
        }
    }

    end {
        Write-Verbose "[$($MyInvocation.MyCommand)] Completed network statistics aggregation"
    }
}