標籤:runspace powershell parallel
今天一個朋友問我在Powershell裡面如何能夠並發的ping上萬台機器?預設的test-connection 儘管有-computer這個參數,他的方式是按順序的挨個ping,全部跑下來可能有好幾個小時。
比如我需要花18秒的時間才能ping完40台伺服器,如果成千上萬的話就很費時間了。
measure-commnd -expression {Get-ADComputer -Filter {operatingsystem -like "*2012*"} | ForEach-Object {Test-Connection -ComputerName $_.name -Count 1}}
650) this.width=650;" src="http://s1.51cto.com/wyfs02/M02/7E/92/wKiom1cErB7jvpi9AAAakf0JJIs452.png" title="0.PNG" alt="wKiom1cErB7jvpi9AAAakf0JJIs452.png" />
這之前,豆子對多線程的使用僅僅限於瞭解invoke-command可以同時對30個對象操作,經過一番學習,終於發現還有其他 的進階方式。
PowerShell裡面,對於多線程的使用大概是兩大方式。
第一個是建立多個背景job。這種方式通過start-job或者 -asjob建立後台job,然後通過get-job擷取當前的任務,通過receive-job來擷取完成任務的結果,最後還得remove-job來釋放記憶體。缺點顯而易見是比較麻煩。而且一旦多跑幾個job 就灰常灰常地卡!
650) this.width=650;" src="http://s1.51cto.com/wyfs02/M02/7E/8F/wKioL1cEr4qx_OieAAB0fPHYMxI751.png" title="4.PNG" alt="wKioL1cEr4qx_OieAAB0fPHYMxI751.png" />
第二個方式是建立多個runspace,這個工作原理和invoke-command一樣,每一個遠端session綁定一個runspace。我們可以建立一個runspace pool,指定在這個資源集區裡面最多可以同時執行多少個runspace。
豆子主要參考了這篇部落格的方法,寫了一個簡單的指令碼。
http://thesurlyadmin.com/2013/02/11/multithreading-powershell-scripts/
$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.." -NoNewlineDo { 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秒才能出結果。
650) this.width=650;" src="http://s1.51cto.com/wyfs02/M02/7E/92/wKiom1cEqO_A3RQsAAA4ExOCLcs103.png" title="1.PNG" alt="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也是成功的
get-adcomputer -Filter {operatingsystem -like "*2012*"} | select -ExpandProperty name | Invoke-Parallel -ScriptBlock {Test-Connection -computername $_ -count 1}
650) this.width=650;" src="http://s2.51cto.com/wyfs02/M00/7E/92/wKiom1cEqqyA47xvAAAzB3SlH5Y854.png" title="2.PNG" alt="wKiom1cEqqyA47xvAAAzB3SlH5Y854.png" />
最後,網上也有現成的指令碼用來並發的測試ping,原理也是調用上面的invoke-parallel函數,不過他還增加了其他的函數用來測試rdp,winrm,rpc等遠端存取的連接埠是否開啟,進一步擴充了功能。可以直接在這裡下載
http://ramblingcookiemonster.github.io/Invoke-Ping/
invoke-ping -ComputerName (Get-ADComputer -Filter {operatingsystem -like "*2012*"}).name -Detail RDP,rpc | ft -Wrap
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/7E/8F/wKioL1cErtWwJ0l0AABCM4b7Lm8565.png" title="3.PNG" alt="wKioL1cErtWwJ0l0AABCM4b7Lm8565.png" />
本文出自 “麻婆豆腐” 部落格,請務必保留此出處http://beanxyz.blog.51cto.com/5570417/1760880
PowerShell 多線程的使用