Windows 8.1では、Test-NetConnection
コマンドレットはリモートシステムのネットワークポートの状態を確認するのに役立ちます。ただし、不必要に遅くなることがあります。このプロセスを高速化するために、調整できるいくつかのオプション、または使用できる代替のPowerShellコマンドがあるかどうかを知りたいです。
Test-NetConnection
は、リモートシステムが応答していない場合、結果を返すまでに約10秒かかることがあります。ポートが指定されるたびに、2つの接続テストが実行され、タイムアウトまでに約5秒かかります。最初のテストは、基本的なICMPエコーチェックです。システムがオフラインの場合、またはシステム(または介在するインフラストラクチャ)がICMPエコー要求をブロックするか応答しないように構成されている場合、これはタイムアウトになります。2番目のテストは、指定されたポートに対する実際のチェックです。システムがオフラインの場合、またはポートをブロックしているパスにファイアウォールがある場合、これはタイムアウトになります。
現在の使用例では、リモートシステムは信頼性の高いギガビットイーサネット接続で2ホップしか離れていません。したがって、リクエストの5秒のタイムアウトは非常に長くなります-おそらく30ミリ秒以下のタイムアウトでも信頼できる結果を得ることができます!さらに、システムがオンラインで他のすべてのサービスを利用できる場合でも、システムはICMPエコーに応答しないことがわかっています。したがって、ICMPエコーテストをまったく使用せずに実行でき、TCP接続テストのタイムアウトを減らして、この目的でTest-NetConnection
を使用するスクリプトを高速化できると便利です。
Test-NetConnection
には、これらの動作を変更するオプションがありますか? (詳細なヘルプファイルを読みましたが、答えは「いいえ」のようですが、見落としていることがあった場合は、喜んでお知らせします。)または、PowerShellを使用して同じチェックを実行できる別の方法があります。でももっと速い?
さまざまな理由から、可能な限りオペレーティングシステムに組み込まれている機能を使用するようにスクリプトを制限することを好みます。環境がWindows 8.1の新しいビルドであり、適切なすべてのWindows Updateが適用されており、サードパーティのツールがオプションでないと仮定します。
非常に基本的(タイムアウト100ミリ秒):
function testport ($hostname='yahoo.com',$port=80,$timeout=100) {
$requestCallback = $state = $null
$client = New-Object System.Net.Sockets.TcpClient
$beginConnect = $client.BeginConnect($hostname,$port,$requestCallback,$state)
Start-Sleep -milli $timeOut
if ($client.Connected) { $open = $true } else { $open = $false }
$client.Close()
[pscustomobject]@{hostname=$hostname;port=$port;open=$open}
}
testport
hostname port open
-------- ---- ----
yahoo.com 80 True
これを使用して接続をテストできます-PowerShell Code Repository (author 'BSonPosh')から取得:
「Test-Portは、指定されたポートへのTCP接続を作成します。デフォルトでは、3秒のタイムアウトでポート135に接続します。 "
Param([string]$srv,$port=135,$timeout=3000,[switch]$verbose)
# Test-Port.ps1
# Does a TCP connection on specified port (135 by default)
$ErrorActionPreference = "SilentlyContinue"
# Create TCP Client
$tcpclient = new-Object system.Net.Sockets.TcpClient
# Tell TCP Client to connect to machine on Port
$iar = $tcpclient.BeginConnect($srv,$port,$null,$null)
# Set the wait time
$wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
# Check to see if the connection is done
if(!$wait)
{
# Close the connection and report timeout
$tcpclient.Close()
if($verbose){Write-Host "Connection Timeout"}
Return $false
}
else
{
# Close the connection and report the error if there is one
$error.Clear()
$tcpclient.EndConnect($iar) | out-Null
if(!$?){if($verbose){write-Host $error[0]};$failed = $true}
$tcpclient.Close()
}
# Return $true if connection Establish else $False
if($failed){return $false}else{return $true}
あなたはフォローアップのためにそのリポジトリページに行くことができます(この答えはすでにコピージョブでは多すぎます)
より迅速な方法は次のとおりです。
param($ip,$port)
New-Object System.Net.Sockets.TCPClient -ArgumentList $ip, $port
結果は次のようになります:
Client : System.Net.Sockets.Socket
Available : 0
Connected : True
ExclusiveAddressUse : False
ReceiveBufferSize : 65536
SendBufferSize : 65536
ReceiveTimeout : 0
SendTimeout : 0
LingerState : System.Net.Sockets.LingerOption
NoDelay : False
興味深い価値は「つながる」
編集:もう1つの理由:Test-NetConnectionはPowershell v5からのみ機能します(私が正しく覚えている場合)が、このソリューションはv2から機能します:)
@Janの答えを取り入れることで、煩雑さが減り、生成されたタスクで機能するようになりました。
例外をスローし、$error
/非標準の「冗長」なものを使用するAPIユーザーにも依存しないのはいいことです(.Connected
を取得すると、SocketException
が生成されるようですきちんとした)。
Function TestTCP { Param($address, $port, $timeout=2000)
$socket=New-Object System.Net.Sockets.TcpClient
try {
$result=$socket.BeginConnect($address, $port, $NULL, $NULL)
if (!$result.AsyncWaitHandle.WaitOne($timeout, $False)) {
throw [System.Exception]::new('Connection Timeout')
}
$socket.EndConnect($result) | Out-Null
$socket.Connected
}
finally {
$socket.Close()
}
}
私は多くのIPにpingを送信する超高速の方法を探していて、この質問に遭遇しました(とりわけ)。
やがて、自分のやりたいことに簡単に統合できるスクリプトを見つけました。男はそれを Fast Ping Sweep Asynchronous と呼んでいます。
Power Shell n00bであっても、出力をパイプ処理して、出力を変更して必要なものだけを含めることができました。他のスクリプトに出くわしましたが、自分の目的に合わせて変更するスクリプトを解読できませんでした。
これに必要なPower Shellのバージョンはわかりませんが、v4およびv5で動作します。
Powershell IPスキャナー、pingスイープスクリプトのほとんどを見てきましたが、いずれもPingASyncメソッドを使用していません。同期スクリプトの「問題」は、次のアドレスに進む前にノードが応答またはタイムアウトするまで待機する必要があることです。このアプローチには数秒かかる場合があります
function Global:Ping-IPRange {
<#
.SYNOPSIS
Sends ICMP echo request packets to a range of IPv4 addresses between two given addresses.
.DESCRIPTION
This function lets you sends ICMP echo request packets ("pings") to
a range of IPv4 addresses using an asynchronous method.
Therefore this technique is very fast but comes with a warning.
Ping sweeping a large subnet or network with many swithes may result in
a peak of broadcast traffic.
Use the -Interval parameter to adjust the time between each ping request.
For example, an interval of 60 milliseconds is suitable for wireless networks.
The RawOutput parameter switches the output to an unformated
[System.Net.NetworkInformation.PingReply[]].
.INPUTS
None
You cannot pipe input to this funcion.
.OUTPUTS
The function only returns output from successful pings.
Type: System.Net.NetworkInformation.PingReply
The RawOutput parameter switches the output to an unformated
[System.Net.NetworkInformation.PingReply[]].
.NOTES
Author : G.A.F.F. Jakobs
Created : August 30, 2014
Version : 6
.EXAMPLE
Ping-IPRange -StartAddress 192.168.1.1 -EndAddress 192.168.1.254 -Interval 20
IPAddress Bytes Ttl ResponseTime
--------- ----- --- ------------
192.168.1.41 32 64 371
192.168.1.57 32 128 0
192.168.1.64 32 128 1
192.168.1.63 32 64 88
192.168.1.254 32 64 0
In this example all the ip addresses between 192.168.1.1 and 192.168.1.254 are pinged using
a 20 millisecond interval between each request.
All the addresses that reply the ping request are listed.
.LINK
http://gallery.technet.Microsoft.com/Fast-asynchronous-ping-IP-d0a5cf0e
#>
[CmdletBinding(ConfirmImpact='Low')]
Param(
[parameter(Mandatory = $true, Position = 0)]
[System.Net.IPAddress]$StartAddress,
[parameter(Mandatory = $true, Position = 1)]
[System.Net.IPAddress]$EndAddress,
[int]$Interval = 30,
[Switch]$RawOutput = $false
)
$timeout = 2000
function New-Range ($start, $end) {
[byte[]]$BySt = $start.GetAddressBytes()
[Array]::Reverse($BySt)
[byte[]]$ByEn = $end.GetAddressBytes()
[Array]::Reverse($ByEn)
$i1 = [System.BitConverter]::ToUInt32($BySt,0)
$i2 = [System.BitConverter]::ToUInt32($ByEn,0)
for($x = $i1;$x -le $i2;$x++){
$ip = ([System.Net.IPAddress]$x).GetAddressBytes()
[Array]::Reverse($ip)
[System.Net.IPAddress]::Parse($($ip -join '.'))
}
}
$IPrange = New-Range $StartAddress $EndAddress
$IpTotal = $IPrange.Count
Get-Event -SourceIdentifier "ID-Ping*" | Remove-Event
Get-EventSubscriber -SourceIdentifier "ID-Ping*" | Unregister-Event
$IPrange | foreach{
[string]$VarName = "Ping_" + $_.Address
New-Variable -Name $VarName -Value (New-Object System.Net.NetworkInformation.Ping)
Register-ObjectEvent -InputObject (Get-Variable $VarName -ValueOnly) -EventName PingCompleted -SourceIdentifier "ID-$VarName"
(Get-Variable $VarName -ValueOnly).SendAsync($_,$timeout,$VarName)
Remove-Variable $VarName
try{
$pending = (Get-Event -SourceIdentifier "ID-Ping*").Count
}catch [System.InvalidOperationException]{}
$index = [array]::indexof($IPrange,$_)
Write-Progress -Activity "Sending ping to" -Id 1 -status $_.IPAddressToString -PercentComplete (($index / $IpTotal) * 100)
Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($index - $pending) -PercentComplete (($index - $pending)/$IpTotal * 100)
Start-Sleep -Milliseconds $Interval
}
Write-Progress -Activity "Done sending ping requests" -Id 1 -Status 'Waiting' -PercentComplete 100
While($pending -lt $IpTotal){
Wait-Event -SourceIdentifier "ID-Ping*" | Out-Null
Start-Sleep -Milliseconds 10
$pending = (Get-Event -SourceIdentifier "ID-Ping*").Count
Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($IpTotal - $pending) -PercentComplete (($IpTotal - $pending)/$IpTotal * 100)
}
if($RawOutput){
$Reply = Get-Event -SourceIdentifier "ID-Ping*" | ForEach {
If($_.SourceEventArgs.Reply.Status -eq "Success"){
$_.SourceEventArgs.Reply
}
Unregister-Event $_.SourceIdentifier
Remove-Event $_.SourceIdentifier
}
}else{
$Reply = Get-Event -SourceIdentifier "ID-Ping*" | ForEach {
If($_.SourceEventArgs.Reply.Status -eq "Success"){
$_.SourceEventArgs.Reply | select @{
Name="IPAddress" ; Expression={$_.Address}},
@{Name="Bytes" ; Expression={$_.Buffer.Length}},
@{Name="Ttl" ; Expression={$_.Options.Ttl}},
@{Name="ResponseTime"; Expression={$_.RoundtripTime}}
}
Unregister-Event $_.SourceIdentifier
Remove-Event $_.SourceIdentifier
}
}
if($Reply -eq $Null){
Write-Verbose "Ping-IPrange : No ip address responded" -Verbose
}
return $Reply
}