You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell设置5985端口检测超时后结果异常的问题

修复Runspace池内快速端口检测的稳定性问题

问题根源分析

你的代码出现重复结果、检测不稳定的核心原因有两个:

  1. WaitHandle索引错位:使用[System.Threading.WaitHandle]::WaitAny($jobs.Async.AsyncWaitHandle)时,$jobs列表是动态变化的(处理完的作业会被移除),但WaitAny返回的是调用时传入的WaitHandle数组的索引,当列表元素被移除后,后续循环的索引会对应错误的作业,导致重复处理或遗漏。
  2. TcpClient资源未释放:直接创建TcpClient实例但未释放,可能导致套接字资源泄漏,影响后续检测的稳定性。

修复后的完整代码

$ProgressPreference = 'Ignore'
$maxThreads = 32

# 创建Runspace池,使用默认会话状态避免交互冲突
$pool = [runspacefactory]::CreateRunspacePool(1, $maxThreads, [initialsessionstate]::CreateDefault2())
$pool.Open()

$jobs = [System.Collections.Generic.List[hashtable]]::new()
$servers = Get-ADComputer -Filter * -SearchBase "OU=Sales, DC=example,DC=com" | Select-Object -ExpandProperty Name

$servers | ForEach-Object {
    $computer = $_
    $instance = [powershell]::Create().AddScript({
        param($computer)
        
        $portOpen = $false
        $tcpClient = $null
        try {
            $tcpClient = [System.Net.Sockets.TcpClient]::new()
            # 执行100ms超时的异步连接检测
            $portOpen = $tcpClient.ConnectAsync($computer, 5985).Wait(100)
        }
        finally {
            # 强制释放TcpClient资源,避免套接字泄漏
            if ($tcpClient) { $tcpClient.Dispose() }
        }

        [pscustomobject]@{
            Computer = $computer
            Port     = 5985
            PortOpen = $portOpen
        }
    }).AddParameters(@{ computer = $computer })

    $instance.RunspacePool = $pool
    $jobs.Add(@{
        Instance = $instance
        Async    = $instance.BeginInvoke()
    })
}

$result = [System.Collections.Generic.List[pscustomobject]]::new()
while ($jobs.Count -gt 0) {
    # 每次循环生成当前作业的WaitHandle数组副本,确保索引对应正确
    $waitHandles = $jobs.Async.AsyncWaitHandle
    $completedIndex = [System.Threading.WaitHandle]::WaitAny($waitHandles)
    
    $completedJob = $jobs[$completedIndex]
    try {
        # 收集当前作业的执行结果
        $result.AddRange($completedJob.Instance.EndInvoke($completedJob.Async))
    }
    finally {
        # 释放PowerShell实例资源
        $completedJob.Instance.Dispose()
        # 从列表中移除已完成的作业
        $jobs.RemoveAt($completedIndex)
    }
}

$pool.Dispose()

# 筛选并输出在线服务器
$online = $result | Where-Object PortOpen | Select-Object -ExpandProperty Computer
Write-Output $online

关键修复点说明

  • 动态生成WaitHandle数组:每次循环都基于当前$jobs列表生成新的WaitHandle数组,确保WaitAny返回的索引始终对应列表中的正确作业,彻底解决索引错位导致的重复结果问题。
  • 强制释放TcpClient资源:通过try/finally块,无论连接成功与否都释放TcpClient实例,避免套接字资源累积泄漏。
  • 高效结果收集:使用List<pscustomobject>存储结果,比原生数组拼接更高效,同时避免潜在的结果丢失问题。
  • 简化Runspace池配置:移除不必要的$Host参数,使用默认初始化会话状态,减少交互冲突风险。

内容的提问来源于stack exchange,提问作者shawnixer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 17:40:29