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
        }
    }
}

function Test-IsUsedIP {
    <#
    .SYNOPSIS
    指定した IP アドレスが開いていそうかどうか確認します。
 
    .DESCRIPTION
    指定した IP アドレスが開いていそうかどうか確認します。
    ping、ポート 80、443 への接続性、APR 関連情報がテストされます。
 
    .EXAMPLE
    Test-IsUsedIP -IPAddress 192.168.1.1
 
    IPAddress : 192.168.1.1
    SourceIPAddress : 0.0.0.0
    IsUsedScore : 100
    IsUsed : True
    CheckedDetails : {@{Name=ping; MAC=; isUsedScore=25; Description=TestNetConnectionResult}, @{Name=Port_80; MAC=; isUse
                      dScore=100; Description=TestNetConnectionResult}, @{Name=Port_443; MAC=; isUsedScore=100; Description
                      =TestNetConnectionResult}, @{Name=ARP; MAC=; isUsedScore=0; Description=System.Object[]}...}
 
    IsUsedScore = 100 は確実に該当 IP が利用中であることを示します。
    IsUsed = True は IsUsedScore が 100 であることを示します。
 
 
    .EXAMPLE
    Test-IsUsedIP -IPAddress 192.168.1.2
 
    IPAddress : 192.168.1.2
    SourceIPAddress : 0.0.0.0
    IsUsedScore : 25
    IsUsed : False
    CheckedDetails : {@{Name=ping; MAC=; isUsedScore=25; Description=TestNetConnectionResult}, @{Name=Port_80; MAC=; isUse
                      dScore=25; Description=TestNetConnectionResult}, @{Name=Port_443; MAC=; isUsedScore=25; Description=T
                      estNetConnectionResult}, @{Name=ARP; MAC=; isUsedScore=0; Description=System.Object[]}...}
 
    IsUsedScore = 25 IP が利用されていない可能性が高いことを示します。
    IsUsed = False は IsUsedScore が 100 未満であることを示します。
 
 
    .EXAMPLE
    (Test-IsUsedIP -IPAddress 192.168.1.1).CheckedDetails
 
    Name MAC isUsedScore Description
    ---- --- ----------- -----------
    ping 25 TestNetConnectionResult
    Port_80 100 TestNetConnectionResult
    Port_443 100 TestNetConnectionResult
    ARP 00-00-00-00-00-00 0 {MSFT_NetNeighbor (Name = ";C?8;@B8;8;55;?55;", CreationClassName = "", Syste...
    ARPing 00-00-00-00-00-00 25 67
 
    チェックの詳細を確認できます。
    この例では 以下のようになります。
    ・ ping では疎通無い場合、isUsedScore は 25 になります。Firewall 等で遮断されている場合 IP アドレス未使用と断定できんないためです。
    ・ Port 80 および Port 443 でのセッションが確立できたため、該当 IP アドレスは使用中です。
    ・ ARP 情報がテスト実施コンピューター上に該当宛先情報ないため、該当 IP アドレスとの直接的な疎通なく未使用の可能性があります。
    ・ ARPing 情報でも該当 IP アドレス仕様情報を得られなかったため、該当 IP 未使用の可能性があります。
 
    ・ 全チェック項目isUsedScore の最大値は 100 であるため 該当 IP アドレスは使用中です。
 
    .EXAMPLE
    Test-IsUsedIP -IPAddress 192.168.1.1 -CustomPort "8080,22"
 
    チェック対象にポート 80, 443 以外のポートも含めたい場合に CustomPort を指定します。
    この例では 8080, 22 ポートでの接続性も確認されます。
 
 
    .EXAMPLE
    Test-IsUsedIP -IPAddress 192.168.1.1 -SourceIPAddress 192.168.1.10
 
    複数 NIC のある端末から疎通テストを行う場合に明示的にソース IP を指定することができます。
 
 
    .PARAMETER IPAddress
 
    利用されているかどうか確認したい IPアドレスを指定して下さい。ホスト名や FQDN は指定できません。
 
 
    .PARAMETER CustomPort
 
    利用されているかどうか確認したい IPアドレスへの TCP セッションをポート 80, 443 以外に試したい場合に指定します。
 
 
    .PARAMETER SourceIPAddress
 
    複数 NIC のある環境で明示的にソース IP アドレスを指定したい場合に指定します。
 
 
    #>


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

        [Parameter(Mandatory=$false,Position=2)]
        [String]$CustomPort,

        [Parameter(Mandatory=$false,Position=3)]
        [String]$SourceIPAddress="0.0.0.0"

    )


    $StateList =@()
    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Status" -Value "Existed_IP"
    $Mem | Add-Member -MemberType NoteProperty -Name "Code" -Value 0
    $StateList += $Mem

    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Status" -Value "ERROR_BAD_NET_NAME"
    $Mem | Add-Member -MemberType NoteProperty -Name "Code" -Value 67
    $StateList += $Mem

    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Status" -Value "ERROR_BUFFER_OVERFLOW"
    $Mem | Add-Member -MemberType NoteProperty -Name "Code" -Value 111
    $StateList += $Mem

    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Status" -Value "ERROR_GEN_FAILURE"
    $Mem | Add-Member -MemberType NoteProperty -Name "Code" -Value 31
    $StateList += $Mem

    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Status" -Value "ERROR_INVALID_PARAMETER"
    $Mem | Add-Member -MemberType NoteProperty -Name "Code" -Value 87
    $StateList += $Mem

    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Status" -Value "ERROR_INVALID_USER_BUFFER"
    $Mem | Add-Member -MemberType NoteProperty -Name "Code" -Value 1784
    $StateList += $Mem

    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Status" -Value "ERROR_NOT_SUPPORTED"
    $Mem | Add-Member -MemberType NoteProperty -Name "Code" -Value 50
    $StateList += $Mem

    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Status" -Value "ERROR_NOT_CONFIGURED_GATEWAY_OR_DISABLED_NIC"
    $Mem | Add-Member -MemberType NoteProperty -Name "Code" -Value 1231
    $StateList += $Mem


    $CheckedDetails = @()

    $isUsedScore = 0
    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Name" -Value "ping"
    $Result = Test-NetConnection -ComputerName $IPAddress  -ErrorAction SilentlyContinue -InformationLevel Detailed -TraceRoute  -WarningAction SilentlyContinue

    if ($True -eq $Result.PingSucceeded) {
            $isUsedScore = 100
    } else {
            $isUsedScore = 25
    }

    $Mem | Add-Member -MemberType NoteProperty -Name "MAC" -Value ""
    $Mem | Add-Member -MemberType NoteProperty -Name "isUsedScore" -Value $isUsedScore
    $Mem | Add-Member -MemberType NoteProperty -Name "Description" -Value $Result
    $CheckedDetails += $Mem


    $PortList = @("80","443")
    $PortList += $CustomPort.Split(",")
    $PortList = $PortList | Where-Object {$_ -ne ""}

    foreach ($Port in $PortList) {
        $isUsedScore = 0
        $Mem = New-Object PSObject
        $Mem | Add-Member -MemberType NoteProperty -Name "Name" -Value ("Port_{0}" -f $Port)
        $Result = Test-NetConnection -ComputerName $IPAddress  -ErrorAction SilentlyContinue  -InformationLevel Detailed -Port $Port -WarningAction SilentlyContinue

        if ($True -eq $Result.TcpTestSucceeded) {
                $isUsedScore = 100
        } else {
                $isUsedScore = 25
        }

        $Mem | Add-Member -MemberType NoteProperty -Name "MAC" -Value ""
        $Mem | Add-Member -MemberType NoteProperty -Name "isUsedScore" -Value $isUsedScore
        $Mem | Add-Member -MemberType NoteProperty -Name "Description" -Value $Result
        $CheckedDetails += $Mem

    }


    $isUsedScore = 0
    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Name" -Value "ARP"

    $Result = @(Get-NetNeighbor -IPAddress  $IPAddress -ErrorAction SilentlyContinue)

    if (0 -ne $Result.Count) {
        switch ($Result[0].State) {
            "Reachable" {
                    $isUsedScore = 100
                }
            "Unreachable" {
                    $isUsedScore = 0
                }
            default    {
                    if ("00-00-00-00-00-00" -ne $Result[0].LinkLayerAddress) {
                        $isUsedScore = 50
                    }
                }
        }
    }

    $Mem | Add-Member -MemberType NoteProperty -Name "MAC" -Value $Result[0].LinkLayerAddress
    $Mem | Add-Member -MemberType NoteProperty -Name "isUsedScore" -Value $isUsedScore
    $Mem | Add-Member -MemberType NoteProperty -Name "Description" -Value $Result
    $CheckedDetails += $Mem


    $isUsedScore = 0
    $Mem = New-Object PSObject
    $Mem | Add-Member -MemberType NoteProperty -Name "Name" -Value "ARPing"


    $Source = '[DllImport("iphlpapi.dll")]public static extern int SendARP(UInt32 DestIP,UInt32 SrcIP,byte[] pMacAddr,ref UInt32 PhyAddrLen);'
    $Type = Add-Type -MemberDefinition $Source -Name DllSendARP -PassThru

    $TgtIP = [IPAddress]$IPAddress
    $SrcIP = [IPAddress]$SourceIPAddress

    $MACAddr = New-Object Byte[] 6

    $Result = $Type::SendARP($TgtIP.Address,$SrcIP.Address,$MACAddr,[ref]$MACAddr.length)
    $MAC = ($MACAddr | Foreach-Object {("{0:x2}" -f $_)} ) -join "-"

    $Mem | Add-Member -MemberType NoteProperty -Name "MAC" -Value $MAC


    switch ($Result) {
        0    {
# Write-Information ("{0} ({1}) is Used." -f $IPAddress, $MAC)
                $isUsedScore = 90
            }

        67    {
# Write-Information ("{0} is Not Used." -f $IPAddress)
                $isUsedScore = 25
            }

        default {
                $Idx =     $StateList.Code.IndexOf($Result)
                if (-1 -eq $Idx) {
                    Write-Information ("SendARP ERROR: {0} ." -f $Result) -ForegroundColor red
                } else {
                    Write-Information ("SendARP ERROR: {0} : {1} ." -f $Result,$StateList[$Idx].Status) -ForegroundColor red
                }
                $isUsedScore = 50
            }

    }
    $Mem | Add-Member -MemberType NoteProperty -Name "isUsedScore" -Value $isUsedScore
    $Mem | Add-Member -MemberType NoteProperty -Name "Description" -Value $Result

    $CheckedDetails += $Mem

    $Result = New-Object PSObject

    $Result | Add-Member -MemberType NoteProperty -Name "IPAddress" -Value $IPAddress
    $Result | Add-Member -MemberType NoteProperty -Name "SourceIPAddress" -Value $SourceIPAddress
    $Result | Add-Member -MemberType NoteProperty -Name "IsUsedScore" -Value ($CheckedDetails | Measure-Object -Property isUsedScore -max).Maximum
    $Result | Add-Member -MemberType NoteProperty -Name "IsUsed" -Value (100 -eq $Result.IsUsedScore)
    $Result | Add-Member -MemberType NoteProperty -Name "CheckedDetails" -Value $CheckedDetails

    $Result
}


Export-ModuleMember -Function Get-NetProcess,Test-IsUsedIP