SHIMSOFT-NetProcess.psm1

function Get-NetProcess {
    <#
    .SYNOPSIS
    ネットワーク通信などのプロセス名を調べます。
 
    .DESCRIPTION
    ネットワーク通信などのプロセス名を調べます。
 
 
    .EXAMPLE
    Get-NetProcess
 
    ネットワーク通信ポート番号とプロセス情報を列挙します。
 
 
    .EXAMPLE
    $Results = Get-NetProcess
 
    ネットワーク通信ポート番号とプロセス情報を変数に格納します。
 
    $Results
 
    変数に保持した情報のサマリが表示されます。
 
    $Results[0] | fl *
 
    特定行の詳細を確認するには、パイプ接続して Format-List -Property * などで非表示のプロパティ値を確認できます。
    詳細情報には以下の情報も含まれています。
 
    $Results[0].ProcessName = Get-Process で確認できるプロセス名です。例:"spoolsv"
    $Results[0].ServiceName = Get-Service で確認できるサービス名です。例:"Spooler"
    $Results[0].ServiceDisplayName = Get-Service で確認できるサービスの表示名です。 例: "Print Spooler"
 
    $Results[0].Name = サービスの場合は ServiceDisplayName、そうでない場合は ProcessName を返します。
 
    $Results[0].FileName = この通信を利用している実体のファイル名。
 
    サービスの場合は $Results[0].ServiceDescription にどのようなサービス化の説明が含まれます。
 
 
    .EXAMPLE
    Get-NetProcess -LocalPort 8080
    Get-NetProcess -LocalAddress 192.168.10.10
    Get-NetProcess -LocalAddress 192.168.10.10 -LocalPort 8080
 
    指定した条件でフィルターした結果が表示されます。
 
    .EXAMPLE
    Get-NetProcess -RemotePort 443
    Get-NetProcess -RemoteAddress 192.168.10.10
    Get-NetProcess -RemoteAddress 192.168.10.10 -RemotePort 443
 
    指定した条件でフィルターした結果が表示されます。
    暗黙的に -SelectRemote -Protocol TCP オプションが指定された時と同じ挙動になります。
 
    .EXAMPLE
    Get-NetProcess -State Listen
 
    指定したステートの通信情報が表示されます。
    暗黙的に -Protocol TCP オプションが指定された時と同じ挙動になります。
 
    .EXAMPLE
    Get-NetProcess -Protocol TCP
 
    Get-NetProcess -Protocol UDP
 
    それぞれ指定したプロトコルの情報のみ列挙されます。
    既定値は TCP+UDP で両方表示されます。
 
    .EXAMPLE
    Get-NetProcess -RemotePort 443 -CheckPTR
 
    RemoteAddress について Resolve-DnsName で逆引き検索を行います。
    名前解決できない通信先の場合、タイムアウトするまで処理が停止したように見えるようになるため、
    処理完了までに時間を要するようになります。
 
 
    .EXAMPLE
    Get-NetProcess -NoProgress
 
    通常時 netstat コマンドの様に1件ずつ順次表示しますが、このオプションを指定すると
    表示すべき情報が全部そろってから出力します。
 
 
    .EXAMPLE
    Get-NetProcess -Summary
 
    通常時 Local Address + Local Port を組み合わせた "Binding Information" または
     Remote Address + Remote Port を組み合わせた "Remote Information" のいずれかを表示しますが
     -Summary オプションを付けると netstat コマンドの出力のように
     Local Address + Local Port + Remote Address + Remote Port をまとめて表示します。
 
    .EXAMPLE
    Get-NetProcess -Name spooler
    Get-NetProcess -ProcessName spoolsv
    Get-NetProcess -ServiceName spooler
    Get-NetProcess -ServiceName "Print Spooler"
 
    これらはいずれも"Print Spooler" サービスの情報を表示します。
    -Name オプションで指定した場合は、-ProcessName と -ServiceName に同じ値を指定したのと同じ検索を行い
    結果はマージされて一緒に表示されます。
 
    -ProcessName オプションは Get-Process コマンドで確認できる ProcessName と比較されます。
    -ServiceName オプションは Get-Service コマンドで確認できる Name および DisplayName と比較されます。
 
    .EXAMPLE
    Get-NetProcess -Name *cl*
    Get-NetProcess -ProcessName *cl*
    Get-NetProcess -ServiceName *cl*
 
    名前を指定して抽出対象を指定するパラメーターはワイルドカードが使えます。
 
    .PARAMETER LocalAddress
 
    通信元 IPアドレスを指定して下さい。ホスト名や FQDN は指定できません。
    指定した IP アドレスにマッチする情報を列挙します。
 
    .PARAMETER LocalPort
 
    通信元 ポート番号を指定して下さい。"HTTP" や "HTTPS" のようなプロトコル文字列は指定できません。
    ポート番号範囲も指定できません。
    指定したポート場合にマッチする情報を列挙します。
 
    .PARAMETER RemoteAddress
 
    通信先 IPアドレスを指定して下さい。ホスト名や FQDN は指定できません。
    指定した IP アドレスにマッチする情報を列挙します。
    暗黙的に -SelectRemote -Protocol TCP オプション指定時と同じ挙動になります。
 
    .PARAMETER RemotePort
 
    通信先 ポート番号を指定して下さい。"HTTP" や "HTTPS" のようなプロトコル文字列は指定できません。
    ポート番号範囲も指定できません。
    指定したポート場合にマッチする情報を列挙します。
    暗黙的に -SelectRemote -Protocol TCP オプション指定時と同じ挙動になります。
 
    .PARAMETER State
 
    通信ステートを指定して下さい。
    指定したステートにマッチする情報を列挙します。
    暗黙的に -Protocol TCP オプション指定時と同じ挙動になります。
 
    .PARAMETER Protocol
 
    TCP または UDP を指定してください。既定値は TCP+UDP です。
    指定したプロトコルにマッチする情報を列挙します。
 
    .PARAMETER SelectRemote
 
    通常は LocalAddress / LocalPort を基にした "Binding Information" をサマリで表示しますが、
    RemoteAddress / RemotePort を基にした "Remote Information" をサマリで表示するようになります。
 
    .PARAMETER SelectLocal
 
    -RemoteAddress や -RemotePort オプションを指定すると暗黙的に -SelectRemote オプションを指定したのと同じく
    RemoteAddress / RemotePort を基にした "Remote Information" をサマリで表示するようになります。
    これを通常時と同じ LocalAddress / LocalPort を基にした "Binding Information" をサマリで表示に戻すことが出来ます。
 
    .PARAMETER CheckPTR
 
    RemoteAddress 情報がある場合に、Resolve-DnsName を用いて逆引き参照します。
    PTR レコード情報を得られた場合、結果に反映されます。
    逆引き参照ゾーンが準備されていない場合などで逆引き出来ない RemoteAddress の場合タイムアウト待ちとなるので
    処理完了まで時間を要するようになります。
 
    .PARAMETER Summary
 
     -Summary オプションを付けると netstat コマンドの出力のように
     Local Address + Local Port + Remote Address + Remote Port をまとめて表示します。
 
    .PARAMETER NoProgress
 
    通常時は1行ずつ随時結果を表示しますが、このオプションを指定すると
    すべてのデータが揃ってから表示をします。
 
    .PARAMETER Name
 
    ProcesName / ServiceName / ServiceDisplayName いずれかにマッチするものをピックアップします。
    ワイルドカードに対応しています。
 
    .PARAMETER ProcessName
 
    ProcesName にマッチするものをピックアップします。
    ワイルドカードに対応しています。
 
 
    .PARAMETER ServiceName
 
    ServiceName / ServiceDisplayName いずれかにマッチするものをピックアップします。
    ワイルドカードに対応しています。
 
 
    .LINK
 
    .NOTES
 
    .INPUTS
    パイプラインからの入力可能です。
 
    .OUTPUTS
    文字列
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Always multiple results.")]
    param(
        [Parameter(Mandatory=$false,Position=1)]
        [String]$LocalAddress="*",

        [Parameter(Mandatory=$false,Position=2)]
        [String]$LocalPort="*",

        [Parameter(Mandatory=$false,Position=3)]
        [String]$RemoteAddress="*",

        [Parameter(Mandatory=$false,Position=4)]
        [String]$RemotePort="*",

        [Parameter(Mandatory=$false,Position=5)]
            [ValidateSet("Closed","CloseWait","Closing","DeleteTCB","Established","FinWait1","FinWait2","LastAck","Listen","SynReceived","SynSent","TimeWait","*")]
        [String]$State="*",

        [Parameter(Mandatory=$false,Position=6)]
            [ValidateSet("TCP","UDP","TCP+UDP")]
        [String]$Protocol="TCP+UDP",

        [Parameter(Mandatory=$false,Position=7)]
        [Switch]$SelectRemote,

        [Parameter(Mandatory=$false,Position=8)]
        [Switch]$SelectLocal,

        [Parameter(Mandatory=$false,Position=9)]
        [Switch]$Summary,

        [Parameter(Mandatory=$false,Position=10)]
        [Switch]$NoProgress,

        [Parameter(Mandatory=$false,Position=11)]
        [Switch]$CheckPTR,

        [Parameter(Mandatory=$false,Position=12)]
        [String]$Name="*",

        [Parameter(Mandatory=$false,Position=13)]
        [String]$ProcessName="NotDefined",

        [Parameter(Mandatory=$false,Position=12)]
        [String]$ServiceName="NotDefined"

        )

    $Results = @()

    if ($RemoteAddress -ne "*" -or $RemotePort -ne "*" -or $State -ne "*") {
         $Protocol = "TCP"
         if (($RemoteAddress -ne "*" -or $RemotePort -ne "*") -and ($False -eq $SelectLocal)) {
             $SelectRemote = $true
        }
    }

    if ("NotDefined" -eq $ProcessName -and "NotDefined" -eq $ServiceName) { $ProcessName = $Name; $ServiceName = $Name; }


    $ResolvedDns = @()

    $TCP = Get-NetTCPConnection | Where-Object {$_.LocalAddress -like $LocalAddress -and $_.LocalPort -like $LocalPort -and $_.RemoteAddress -like $RemoteAddress -and $_.RemotePort -like $RemotePort -and $_.State -like $State}
    $UDP = Get-NetUDPEndpoint | Where-Object {$_.LocalAddress -like $LocalAddress -and $_.LocalPort -like $LocalPort -and $_.RemoteAddress -like $RemoteAddress -and $_.RemotePort -like $RemotePort -and $_.State -like $State}

    if ($True -eq $SelectRemote) {
        $TCP = $TCP | Sort-Object -Property RemotePort,RemoteAddress
        $UDP = $UDP | Sort-Object -Property RemotePort,RemoteAddress
    } else {
        $TCP = $TCP | Sort-Object -Property LocalPort,LocalAddress
        $UDP = $UDP | Sort-Object -Property LocalPort,LocalAddress
    }

    $OwningProcess = @($TCP.OwningProcess) + @($UDP.OwningProcess)  | Sort-Object -Unique

    $ProcALL = Get-Process
    $SvcALL = Get-CimInstance -ClassName Win32_Service

    $ProcF = $ProcALL | Where-Object {$_.Id -in $OwningProcess -and $_.ProcessName -like $ProcessName}
    $SvcF =  $SvcALL | Where-Object {$_.ProcessId -in $OwningProcess -and ($_.Name -like $ServiceName -or $_.DisplayName -like $ServiceName)}

    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name Id -Value -1
    $Mem | Add-Member -MemberType NoteProperty -Name ProcessId -Value -1


    $Dummys = @($Mem, $Mem)


    $Proc = @($ProcF) + ($ProcALL | Where-Object {$_.Id -in $SvcF.ProcessId}) + $Dummys | Sort-Object -Property Id
    $Svc = @($SvcF) + ($SvcALL | Where-Object {$_.ProcessId -in $ProcF.Id}) + $Dummys  | Sort-Object -Property ProcessId

    $ProcIDs = @($Proc.Id) + @($Svc.ProcessId) | Sort-Object -Unique

    $TCP = $TCP | Where-Object {$_.OwningProcess -in $ProcIds}
    $UDP = $UDP | Where-Object {$_.OwningProcess -in $ProcIds}


    if ($Protocol -like "*TCP*") {
        foreach ($TU in $TCP) {
            $Mem = New-Object PSObject
            $Mem | Add-Member -MemberType NoteProperty -Name Type -Value "Process"
            $Mem | Add-Member -MemberType NoteProperty -Name Protocol -Value "TCP"
            $Mem | Add-Member -MemberType NoteProperty -Name LocalAddress -Value $TU.LocalAddress
            $Mem | Add-Member -MemberType NoteProperty -Name LocalPort -Value $TU.LocalPort

            $Mem | Add-Member -MemberType ScriptProperty -Name "Binding Information" -Value {
                if ($this.LocalAddress.Length -lt 30) {
                    ("{0,-30} TCP:{1,5}" -f $this.LocalAddress,$this.LocalPort)
                } else {
                    ("{0}:{1}" -f $this.LocalAddress,$this.LocalPort)
                }
            }


            $Mem | Add-Member -MemberType NoteProperty -Name RemoteAddress -Value $TU.RemoteAddress
            $Mem | Add-Member -MemberType NoteProperty -Name RemotePort -Value $TU.RemotePort

            $Mem | Add-Member -MemberType ScriptProperty -Name "Remote Information" -Value {
                if ($null -ne $this.RemoteDNS.NameHost) {
                    ("{0,-30} :{1,5}" -f $this.RemoteDns.NameHost, $this.RemotePort)
                } else {
                    if ($this.RemoteAddress.Length -lt 30) {
                        ("{0,-30} TCP:{1,5}" -f $this.RemoteAddress, $this.RemotePort)
                    } else {
                        ("{0}:{1}" -f $this.RemoteAddress, $this.RemotePort)
                    }
                }
            }

### Summary
# "TCP Local Address Port Remote Address Port"
# "TCP 123456789012345678901234567890 12345 123456789012345678901234567890 12345"
# "TCP {0,-30} {1,5} {2,-30} {3,5}"

            $Mem | Add-Member -MemberType ScriptProperty -Name "TCP Local Address Port Remote Address Port" -Value {
                if ($null -ne $this.RemoteDNS.NameHost) {
                    ("TCP {0,-30} {1,5} {2,-30} {3,5}" -f $this.LocalAddress, $this.LocalPort, $this.RemoteDns.NameHost, $this.RemotePort)
                } else {
                    ("TCP {0,-30} {1,5} {2,-30} {3,5}" -f $this.LocalAddress, $this.LocalPort, $this.RemoteAddress, $this.RemotePort)
                }
            }


            $Mem | Add-Member -MemberType NoteProperty -Name forDisplay -Value $forDisplay

            if ($True -eq $CheckPTR) {

                if ($null -ne $TU.RemoteAddress) {
                    if (0 -eq $ResolvedDns.Count) {
                        # 逆引き結果をキャッシュへ格納
                        $RA = New-Object PSObject
                        $RA | Add-Member -MemberType NoteProperty -Name Remote -Value $TU.RemoteAddress
                        $RA | Add-Member -MemberType NoteProperty -Name RemoteDNS -Value (Resolve-DnsName -Name $TU.RemoteAddress -ErrorAction SilentlyContinue)
                        $ResolvedDns += $RA
                        $Mem | Add-Member -MemberType NoteProperty -Name RemoteDNS -Value $RA.RemoteDNS
                    } else {
                        if (-1 -eq ($ResolvedDns.Remote.IndexOf($TU.RemoteAddress))) {
                            # 逆引き結果をキャッシュへ格納
                            $RA = New-Object PSObject
                            $RA | Add-Member -MemberType NoteProperty -Name Remote -Value $TU.RemoteAddress
                            $RA | Add-Member -MemberType NoteProperty -Name RemoteDNS -Value (Resolve-DnsName -Name $TU.RemoteAddress -ErrorAction SilentlyContinue)
                            $ResolvedDns += $RA
                            $Mem | Add-Member -MemberType NoteProperty -Name RemoteDNS -Value $RA.RemoteDNS
                        } else {
                            # 逆引き結果をキャッシュから反映
                            $Mem | Add-Member -MemberType NoteProperty -Name RemoteDNS -Value $ResolvedDns[($ResolvedDns.Remote.IndexOf($TU.RemoteAddress))].RemoteDNS
                        }
                    }
                } else {
                    $Mem | Add-Member -MemberType NoteProperty -Name RemoteDNS -Value $null
                }
            } else {
                $Mem | Add-Member -MemberType NoteProperty -Name RemoteDNS -Value $null
            }

            $Mem | Add-Member -MemberType NoteProperty -Name State -Value $TU.State
            $Mem | Add-Member -MemberType NoteProperty -Name ProcessId -Value $TU.OwningProcess

            $ProcPos = $Proc.Id.IndexOf([Int32]$TU.OwningProcess)

            $Mem | Add-Member -MemberType NoteProperty -Name Process -Value $Proc[($ProcPos)]
            $Mem | Add-Member -MemberType NoteProperty -Name ProcessName -Value $Proc[($ProcPos)].ProcessName
            $Mem | Add-Member -MemberType NoteProperty -Name Name -Value $Proc[($ProcPos)].ProcessName
            $Mem | Add-Member -MemberType NoteProperty -Name FileVersionInfo -Value (Get-Process -Id $TU.OwningProcess -FileVersionInfo -ErrorAction SilentlyContinue)
            $Mem | Add-Member -MemberType ScriptProperty -Name FileName -Value {
                if ($null -ne $this.ServiceDetail.PathName) {
                    $this.ServiceDetail.PathName
                } else {
                    $this.FileVersionInfo.FileName
                }
            }

            if ($Svc.ProcessId.IndexOf($TU.OwningProcess) -ne -1) {
                $Mem.Type = "Service"

                $SvcPos = $Svc.ProcessId.IndexOf($TU.OwningProcess)

                $Mem | Add-Member -MemberType NoteProperty -Name ServiceDetail -Value $Svc[($SvcPos)]
                $Mem | Add-Member -MemberType NoteProperty -Name ServiceName -Value $Svc[($SvcPos)].Name
                $Mem | Add-Member -MemberType NoteProperty -Name ServiceDisplayName -Value $Svc[($SvcPos)].DisplayName
                $Mem.Name = $Svc[($SvcPos)].DisplayName
                $Mem | Add-Member -MemberType NoteProperty -Name ServicePathName -Value $Svc[($SvcPos)].PathName
                $Mem | Add-Member -MemberType NoteProperty -Name ServiceDescription -Value $Svc[($SvcPos)].Description
            }

            if ($false -eq $SelectRemote) {
                $defaultProperties = @("Type","Binding Information","State","Name")
            } else {
                $defaultProperties = @("Type","Remote Information","State","Name")
            }

            if ($True -eq $Summary) {
                $defaultProperties = @("Type","TCP Local Address Port Remote Address Port","State","Name")
            }

            $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet("DefaultDisplayPropertySet",[string[]]$defaultProperties)
            $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
            $Mem | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers

            $Results += $Mem

            if ($False -eq $NoProgress) {
                $Mem
            }
        }
    }

    # UDP

    if ($Protocol -like "*UDP*") {

        foreach ($TU in $UDP) {
            $Mem = New-Object PSObject
            $Mem | Add-Member -MemberType NoteProperty -Name Type -Value "Process"
            $Mem | Add-Member -MemberType NoteProperty -Name Protocol -Value "UDP"
            $Mem | Add-Member -MemberType NoteProperty -Name LocalAddress -Value $TU.LocalAddress
            $Mem | Add-Member -MemberType NoteProperty -Name LocalPort -Value $TU.LocalPort

            $Mem | Add-Member -MemberType ScriptProperty -Name "Binding Information" -Value {
                if ($this.LocalAddress.Length -lt 30) {
                    ("{0,-30} UDP:{1,5}" -f $this.LocalAddress,$this.LocalPort)
                } else {
                    ("{0}:{1}" -f $this.LocalAddress,$this.LocalPort)
                }
            }

            $Mem | Add-Member -MemberType NoteProperty -Name RemoteAddress -Value $null
            $Mem | Add-Member -MemberType NoteProperty -Name RemotePort -Value $null

            $Mem | Add-Member -MemberType NoteProperty -Name "Remote Information" -Value $null

            $Mem | Add-Member -MemberType ScriptProperty -Name "TCP Local Address Port Remote Address Port" -Value {
                if ($null -ne $this.RemoteDNS.NameHost) {
                    ("UDP {0,-30} {1,5} {2,-30} {3,5}" -f $this.LocalAddress, $this.LocalPort, $this.RemoteDns.NameHost, $this.RemotePort)
                } else {
                    ("UDP {0,-30} {1,5} {2,-30} {3,5}" -f $this.LocalAddress, $this.LocalPort, $this.RemoteAddress, $this.RemotePort)
                }
            }


            $Mem | Add-Member -MemberType NoteProperty -Name forDisplay -Value $forDisplay

            $Mem | Add-Member -MemberType NoteProperty -Name RemoteDNS -Value $null

            $Mem | Add-Member -MemberType NoteProperty -Name State -Value $null
            $Mem | Add-Member -MemberType NoteProperty -Name ProcessId -Value $TU.OwningProcess

            $ProcPos = $Proc.Id.IndexOf([Int32]$TU.OwningProcess)

            $Mem | Add-Member -MemberType NoteProperty -Name Process -Value $Proc[($ProcPos)]
            $Mem | Add-Member -MemberType NoteProperty -Name ProcessName -Value $Proc[($ProcPos)].ProcessName
            $Mem | Add-Member -MemberType NoteProperty -Name Name -Value $Proc[($ProcPos)].ProcessName
            $Mem | Add-Member -MemberType NoteProperty -Name FileVersionInfo -Value (Get-Process -Id $TU.OwningProcess -FileVersionInfo -ErrorAction SilentlyContinue)
            $Mem | Add-Member -MemberType ScriptProperty -Name FileName -Value {
                if ($null -ne $this.ServiceDetail.PathName) {
                    $this.ServiceDetail.PathName
                } else {
                    $this.FileVersionInfo.FileName
                }
            }

            if ($Svc.ProcessId.IndexOf($TU.OwningProcess) -ne -1) {
                $Mem.Type = "Service"

                $SvcPos = $Svc.ProcessId.IndexOf($TU.OwningProcess)

                $Mem | Add-Member -MemberType NoteProperty -Name ServiceDetail -Value $Svc[($SvcPos)]
                $Mem | Add-Member -MemberType NoteProperty -Name ServiceName -Value $Svc[($SvcPos)].Name
                $Mem | Add-Member -MemberType NoteProperty -Name ServiceDisplayName -Value $Svc[($SvcPos)].DisplayName
                $Mem.Name = $Svc[($SvcPos)].DisplayName
                $Mem | Add-Member -MemberType NoteProperty -Name ServicePathName -Value $Svc[($SvcPos)].PathName
                $Mem | Add-Member -MemberType NoteProperty -Name ServiceDescription -Value $Svc[($SvcPos)].Description
            }

            if ($false -eq $SelectRemote) {
                $defaultProperties = @("Type","Binding Information","State","Name")
            } else {
                $defaultProperties = @("Type","Remote Information","State","Name")
            }

            if ($True -eq $Summary) {
                $defaultProperties = @("Type","TCP Local Address Port Remote Address Port","State","Name")
            }

            $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet("DefaultDisplayPropertySet",[string[]]$defaultProperties)
            $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
            $Mem | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers

            $Results += $Mem

            if ($False -eq $NoProgress) {
                $Mem
            }

        }
    }

    if ($True -eq $NoProgress) {
        if ($True -eq $SelectRemote) {
            $Results | Sort-Object -Property Protocol,Type,RemotePort,RemoteAddress
        } else {
            $Results | Sort-Object -Property Protocl,Type,LocalPort,LocalAddress
        }
    }
}


Export-ModuleMember -Function Get-NetProcess