PowerShell 多线程的使用

简介:

今天一个朋友问我在Powershell里面如何能够并发的ping上万台机器?默认的test-connection 尽管有-computer这个参数,他的方式是按顺序的挨个ping,全部跑下来可能有好几个小时。


比如我需要花18秒的时间才能ping完40台服务器,如果成千上万的话就很费时间了。


1
2
3
4
5
6
measure-commnd  -expression {
$computers = Get-ADComputer  - Filter  {operatingsystem  -like  "*2012*"
 
Test-Connection  -ComputerName  $computers .name -Count 1
 
}

wKiom1cErB7jvpi9AAAakf0JJIs452.png



这之前,豆子对多线程的使用仅仅限于了解invoke-command可以同时对30个对象操作,经过一番学习,终于发现还有其他 的高级方式。

PowerShell里面,对于多线程的使用大概是两大方式。

第一个是创建多个后台的job。这种方式通过start-job或者 -asjob创建后台job,然后通过get-job获取当前的任务,通过receive-job来获取完成任务的结果,最后还得remove-job来释放内存。缺点是性能不高,尤其在创建job和退出job的过程中会消耗大量时间和资源。


wKioL1cEr4qx_OieAAB0fPHYMxI751.png


第二个方式是创建多个runspace,这个工作原理和invoke-command一样,每一个远程的session绑定一个runspace。我们可以创建一个runspace pool,指定在这个资源池里面最多可以同时执行多少个runspace。

比起第一种方式,runspace的性能强悍了太多。下面有人做的对比实验,可以看见几乎是几十倍的性能差距。


http://learn-powershell.net/2012/05/13/using-background-runspaces-instead-of-psjobs-for-better-performance/


现在看看怎么来实现。豆子主要参考了这篇博客的方法和原理,写了一个简单的脚本来。 

http://thesurlyadmin.com/2013/02/11/multithreading-powershell-scripts/


思路很简单,创建runspace pool,指定runspace的数量,然后对要测试的对象集合,对每一个对象都创建一个后台的runspace job,绑定要执行的脚本,传入参数,把结果保存在ps对象或者hash表中,最后等待所有job结束,输出结果。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
$Throttle  = 20  #threads
 
#脚本块,对指定的计算机发送一个ICMP包测试,结果保存在一个对象里面
  
$ScriptBlock  = {
    Param  (
       [string] $Computer
    )
    $a = test-connection  -ComputerName  $Computer  -Count 1 
    
    $RunResult  New-Object  PSObject -Property @{
       IPv4Adress= $a .ipv4address.IPAddressToString
       ComputerName= $Computer
       
    }
    Return  $RunResult
}
 
 
#创建一个资源池,指定多少个runspace可以同时执行
 
$RunspacePool  [RunspaceFactory] ::CreateRunspacePool(1,  $Throttle )
$RunspacePool .Open()
$Jobs  = @()
  
 
#获取Windows 2012服务器的信息,对每一个服务器单独创建一个job,该job执行ICMP的测试,并把结果保存在一个PS对象中
  
( get-adcomputer  - filter  {operatingsystem  -like  "*2012*" }).name | % {
    
    #Start-Sleep -Seconds 1
    $Job  [powershell] ::Create().AddScript( $ScriptBlock ).AddArgument( $_ )
    $Job .RunspacePool =  $RunspacePool
    $Jobs  +=  New-Object  PSObject -Property @{
       Server =  $_
       Pipe =  $Job
       Result =  $Job .BeginInvoke()
    }
}
  
 
  #循环输出等待的信息.... 直到所有的job都完成 
  
Write-Host  "Waiting.."  -NoNewline
Do  {
    Write-Host  "."  -NoNewline
    Start-Sleep  -Seconds 1
While  $Jobs .Result.IsCompleted  -contains  $false )
Write-Host  "All jobs completed!"
 
 
#输出结果 
$Results  = @()
ForEach  ( $Job  in  $Jobs )
{    $Results  +=  $Job .Pipe.EndInvoke( $Job .Result)
}
  
$Results

大概5秒之后 结果就出来了。 如果有兴趣的话可以使用measure-command命令来测试不同线程数的效果,根据我的测试,30个进程同时执行只需4秒出结果,而2个同时执行大概需要9秒才能出结果。


wKiom1cEqO_A3RQsAAA4ExOCLcs103.png


知道原理之后就可以进一步优化和抽象化脚本。这一点已经有人做好了。https://github.com/RamblingCookieMonster/Invoke-Parallel/blob/master/Invoke-Parallel/Invoke-Parallel.ps1


下载,Unlock和dot source之后就能直接调用了。这里提供了一些例子作为参考https://github.com/RamblingCookieMonster/Invoke-Parallel


依葫芦画瓢,我想通过他来调用test-connection也是成功的

1
get-adcomputer  - Filter  {operatingsystem  -like  "*2012*" } | select -ExpandProperty name |  Invoke-Parallel  -ScriptBlock { Test-Connection  -computername  $_  -count 1}


wKiom1cEqqyA47xvAAAzB3SlH5Y854.png


再比如我ping 一个IP范围的计算机

1
1..254|  Invoke-Parallel  -ScriptBlock { Test-Connection  -ComputerName  "10.2.100.$_"  -Count 1 -ErrorAction SilentlyContinue -ErrorVariable err | select Ipv4address, @{n= 'DNS' ;e={ [System.Net.Dns] ::gethostentry( $_ .ipv4address).hostname}}} -Throttle 20


wKioL1cFuu3RrNmKAAA0aXK7aUE813.png


最后,网上也有现成的脚本用来并发的测试ping,原理也是调用上面的invoke-parallel函数,不过他还增加了其他的函数用来测试rdp,winrm,rpc等远程访问的端口是否打开,进一步扩充了功能。可以直接在这里下载

http://ramblingcookiemonster.github.io/Invoke-Ping/

1
invoke-ping  -ComputerName ( Get-ADComputer  - Filter  {operatingsystem  -like  "*2012*" }).name -Detail RDP,rpc | ft -Wrap

wKioL1cErtWwJ0l0AABCM4b7Lm8565.png


参考资料:

1. http://learn-powershell.net/2012/05/13/using-background-runspaces-instead-of-psjobs-for-better-performance/

2. https://github.com/RamblingCookieMonster/Invoke-Parallel

3. http://thesurlyadmin.com/2013/02/11/multithreading-powershell-scripts/

4. http://ramblingcookiemonster.github.io/Invoke-Ping/

5. http://learn-powershell.net/2012/05/10/speedy-network-information-query-using-powershell/










本文转自 beanxyz 51CTO博客,原文链接:http://blog.51cto.com/beanxyz/1760880,如需转载请自行联系原作者

目录
相关文章
|
11月前
|
机器学习/深度学习 数据采集 数据挖掘
实战派教学:掌握Scikit-learn,轻松实现数据分析与机器学习模型优化!
【10月更文挑战第4天】Scikit-learn凭借高效、易用及全面性成为数据科学领域的首选工具,简化了数据预处理、模型训练与评估流程,并提供丰富算法库。本文通过实战教学,详细介绍Scikit-learn的基础入门、数据预处理、模型选择与训练、评估及调优等关键步骤,助你快速掌握并优化数据分析与机器学习模型。从环境搭建到参数调优,每一步都配有示例代码,便于理解和实践。
316 2
|
前端开发 开发工具 git
Git 标签(Tag)实战:打标签和删除标签的步骤指南
Git 标签(Tag)实战:打标签和删除标签的步骤指南
|
JSON PHP 开发工具
PHP Monolog 日志的使用
PHP Monolog 日志的使用
1114 0
|
11月前
|
机器学习/深度学习 人工智能 自然语言处理
[大语言模型-论文精读] ACL2024-长尾知识在检索增强型大型语言模型中的作用
[大语言模型-论文精读] ACL2024-长尾知识在检索增强型大型语言模型中的作用
275 0
|
机器学习/深度学习 算法 大数据
【机器学习】朴素贝叶斯算法及其应用探索
在机器学习的广阔领域中,朴素贝叶斯分类器以其实现简单、计算高效和解释性强等特点,成为了一颗璀璨的明星。尽管名字中带有“朴素”二字,它在文本分类、垃圾邮件过滤、情感分析等多个领域展现出了不凡的效果。本文将深入浅出地介绍朴素贝叶斯的基本原理、数学推导、优缺点以及实际应用案例,旨在为读者构建一个全面而深刻的理解框架。
455 1
|
流计算
基于双闭环PI和SVPWM的PMSM控制器simulink建模与仿真
该文主要介绍了一个基于双闭环PI和SVPWM技术的PMSM控制器的Simulink建模与仿真项目。系统包含逆变桥、PMSM电机、变换器、SVPWM、PI控制器等模块,实现了转速和电流的快速稳定控制。文章提供了系统仿真的图表,并详细阐述了双闭环PI控制器设计及SVPWM技术。在控制流程中,系统不断采集反馈信息,通过PI控制器调整直轴和交轴电流,经SVPWM调制后驱动电机运行,确保高效精确的电机控制。使用的工具为MATLAB2022a。
|
算法
MATLAB | 插值算法 | 一维Lagrange插值法 | 附数据和出图代码 | 直接上手
MATLAB | 插值算法 | 一维Lagrange插值法 | 附数据和出图代码 | 直接上手
460 0
|
Windows
Win10锁屏壁纸位置在哪? 默认锁屏壁纸怎么提取?
  Win10默认系统下载的壁纸怎么下载?在哪里找出来呢?首先它是要设置为Windows聚焦才会自动从微软的服务器上去下载壁纸。这些都是随机下载的。每个人的都Win10 都有可能不一样。 Win10锁屏壁纸位置:   C:\Users\Bruce\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets   步骤:   1. 进入C盘,点击 Users 文件夹。
7422 0
|
Linux 数据安全/隐私保护
Centos修改root用户密码
如果不是以root用户登录的,请先切换到root用户下, 执行命令:su root 然后按提示输入root用户的密码。 英文系统: [root@localhost ~]# passwd Changing password for user root. New password: Retype new password: passwd: all authentication tokens updated successfully. 中文系统: [root@localhost /]# passwd 更改用户 root 的密码 。
2373 0
如何优雅的在本地调试npm包
如何优雅的在本地调试npm包
1359 0