将测试连接脚本改造为多线程版本求助
PowerShell多线程改造求助:批量主机检测脚本提速问题
我最近写了个PowerShell脚本,用来批量检测主机可用性——它能从文本文件读主机列表,把结果输出到屏幕和文件,还能在特定条件下自动发邮件。但是!一旦主机数量多起来,脚本跑起来慢得让人崩溃!我作为PowerShell新手,试着改成多线程版本,折腾了半天没搞定,有没有大佬能给我支支招呀?
以下是我目前的脚本片段:
# start looping here Do{ $available = @() $notavailable = @() $ComputerName = @() #Path to text file of hostnames we want to monitor $ComputerName = Get-Con... }
适合新手的多线程改造方案
其实PowerShell里有几种简单的多线程实现方式,我给你推荐两种最实用的:
方案1:用ForEach-Object -Parallel(PowerShell 7+ 推荐)
这个语法最简洁,适合已经升级到PowerShell 7及以上版本的场景,自带并发控制:
# 1. 读取主机列表文件 $ComputerList = Get-Content -Path "C:\你的主机列表路径.txt" # 2. 并行检测每个主机(设置并发数,按需调整) $results = $ComputerList | ForEach-Object -Parallel { $hostname = $_ # 用Test-Connection检测主机是否在线,也可以换成检测特定端口的Test-NetConnection if (Test-Connection -ComputerName $hostname -Count 1 -Quiet -ErrorAction SilentlyContinue) { [PSCustomObject]@{ ComputerName = $hostname Status = "Available" Timestamp = Get-Date } } else { [PSCustomObject]@{ ComputerName = $hostname Status = "Not Available" Timestamp = Get-Date } } } -ThrottleLimit 50 # 并发数,根据你的机器性能和网络情况调整,别太高避免拥堵 # 3. 分离可用/不可用主机 $available = $results | Where-Object { $_.Status -eq "Available" } $notavailable = $results | Where-Object { $_.Status -eq "Not Available" } # 4. 输出结果到屏幕 Write-Host "`n可用主机列表:" $available | Format-Table -AutoSize Write-Host "`n不可用主机列表:" $notavailable | Format-Table -AutoSize # 5. 输出结果到文件 $available | Export-Csv -Path "AvailableHosts.csv" -NoTypeInformation $notavailable | Export-Csv -Path "UnavailableHosts.csv" -NoTypeInformation # 6. 特定条件下发邮件(比如有不可用主机时) if ($notavailable.Count -gt 0) { $mailSettings = @{ To = "收件人邮箱@xxx.com" From = "发件人邮箱@xxx.com" Subject = "主机检测报告:$($notavailable.Count)台主机离线" Body = "以下主机无法连接:`n$($notavailable.ComputerName -join "`n")" SmtpServer = "你的SMTP服务器地址" # 如果需要认证可以加 -Credential (Get-Credential) } Send-MailMessage @mailSettings }
方案2:用Start-Job(兼容PowerShell 5.1)
如果还在使用PowerShell 5.1,用Start-Job来实现多线程也很方便:
# 1. 读取主机列表 $ComputerList = Get-Content -Path "C:\你的主机列表路径.txt" $jobs = @() # 2. 给每个主机启动单独的检测任务 foreach ($hostname in $ComputerList) { $job = Start-Job -ScriptBlock { param($hostName) if (Test-Connection -ComputerName $hostName -Count 1 -Quiet -ErrorAction SilentlyContinue) { return [PSCustomObject]@{ ComputerName = $hostName Status = "Available" Timestamp = Get-Date } } else { return [PSCustomObject]@{ ComputerName = $hostName Status = "Not Available" Timestamp = Get-Date } } } -ArgumentList $hostname $jobs += $job } # 3. 等待所有任务完成并收集结果 $results = $jobs | Wait-Job | Receive-Job # 清理已完成的作业,避免残留 $jobs | Remove-Job # 后续的结果分离、输出、发邮件步骤和方案1完全一致,直接复用即可
新手小贴士
-ThrottleLimit(方案1)或者同时运行的Job数量(方案2)别设太高,不然可能导致网络拥堵或者本地机器卡顿,建议先从30-50开始测试- 如果需要检测特定服务(比如RDP、HTTP),把
Test-Connection换成Test-NetConnection -Port 3389这类命令就行 - 域环境下也可以用
Invoke-Command来并行执行,效率也不错,但需要对应主机的访问权限
内容的提问来源于stack exchange,提问作者brian bye
相关产品推荐
相关产品推荐

