在 Powershell 中为 Test-NetConnection 或 5985 设置跨域超时

问题描述 投票:0回答:1

我已经运行了这个,但我更改了

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
powershell
1个回答
0
投票

正如我在评论中所述,我确实没有看到您的代码存在可能导致输出重复或丢失输出的问题。我确实认为等待任务的 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 .....
© www.soinside.com 2019 - 2024. All rights reserved.