我已经运行了这个,但我更改了
PortOpen
,因为如果系统宕机,这个块将需要很长时间才能运行。然而,在我做出改变之后,我认为我很好,直到我一次又一次地测试它,不知何故,我对系统有不同的结果。有时同一个系统会出现两次而没有另一个。有时两者兼而有之。我本来希望这样可以更快地设置超时。 PortOpen
行确实有效,但我不确定如何让它在这项工作中作为一个整体工作。基本上,我不确定如何构建它以便能够利用该部分。
$ProgressPreference = 'Ignore'
$maxThreads = 32
$pool = [runspacefactory]::CreateRunspacePool(1, $maxThreads,
[initialsessionstate]::CreateDefault2(),
$Host)
$pool.Open()
$jobs = [System.Collections.Generic.List[hashtable]]::new()
$servers = ( Get-ADComputer -filter * -searchbase "OU=Sales, DC=example,DC=com" | Select-Object -expand Name )
$servers | ForEach-Object {
$instance = [powershell]::Create().AddScript({
param($computer)
[pscustomobject]@{
Computer = $computer
Port = 5985
#PortOpen = Test-NetConnection $computer -Port 5985 -InformationLevel Quiet
PortOpen = [System.Net.Sockets.TcpClient]::new().ConnectAsync($computer, 5985).Wait(100)
}
}).AddParameters(@{ computer = $_ })
$instance.RunspacePool = $pool
$jobs.Add(@{
Instance = $instance
Async = $instance.BeginInvoke()
})
}
$result = while($jobs) {
$job = $jobs[[System.Threading.WaitHandle]::WaitAny($jobs.Async.AsyncWaitHandle)]
$job.Instance.EndInvoke($job.Async)
$job.Instance.Dispose()
$null = $jobs.Remove($job)
}
$pool.Dispose()
$online = @()
$online += $result | Where-Object PortOpen | ForEach-Object Computer
Write-Output $online
正如我在评论中所述,我确实没有看到您的代码存在可能导致输出重复或丢失输出的问题。我确实认为等待任务的 100 毫秒时间太短,但我建议至少 1 秒。此外,
WaitHandle.WaitAny
支持 STA 中的前 63 个等待句柄(PowerShell 默认),来自文档备注部分:
等待句柄的最大数量为 64,如果当前线程处于 STA 状态,则为 63。
.Wait
引起的聚合异常。
PSParallelPipeline
模块,这就是我处理代码的方式:
$maxThreads = 32
$timespan = [timespan]::FromSeconds(5)
$result = Get-ADComputer -Filter * -SearchBase 'OU=Sales, DC=example,DC=com' | Invoke-Parallel {
$outObject = [pscustomobject]@{
Computer = $_.Name
Port = 5985
PortOpen = $false # <= Assume Port Closed Here
}
try {
$tcp = [System.Net.Sockets.TcpClient]::new()
# if the connection was successful, this property gets updated
$outObject.PortOpen = $tcp.ConnectAsync($_.Name, 5985).Wait($using:timespan)
}
catch {
# ignore any errors here, this avoids the exception:
# System.Net.Sockets.SocketException (10060):
# A connection attempt failed because the connected party did not properly respond after a period of time,
# or established connection failed because connected host has failed to respond.
}
finally {
# dispose the TCP instance
if ($tcp) {
$tcp.Dispose()
}
}
# output the object
$outObject
} -ThrottleLimit $maxThreads
# get all computers with the port open
$computersWithPortOpen = $result | Where-Object PortOpen | ForEach-Object Computer
# do other stuff with `$computersWithPortOpen`
Invoke-Command -ComputerName $computersWithPortOpen .....