Multithreading 利用同步哈希表(Runspacepool 6000和#x2B;客户端)的结果
改编一个脚本来完成多种功能,从测试连接开始收集数据,这将影响6000多台机器,因此我使用的RunspacePools是从下面的站点改编的 数据如下所示,我希望将其排序到一个数组中(我认为这是术语),这样我就可以通过结果对数据进行排序。这将适用于从序列号到IAVM数据的多个其他函数 是否有任何方法可以使用逗号分隔的数据,并让它将下面的值吐出到列中?即Multithreading 利用同步哈希表(Runspacepool 6000和#x2B;客户端)的结果,multithreading,powershell,hashtable,synchronized,runspace,Multithreading,Powershell,Hashtable,Synchronized,Runspace,改编一个脚本来完成多种功能,从测试连接开始收集数据,这将影响6000多台机器,因此我使用的RunspacePools是从下面的站点改编的 数据如下所示,我希望将其排序到一个数组中(我认为这是术语),这样我就可以通过结果对数据进行排序。这将适用于从序列号到IAVM数据的多个其他函数 是否有任何方法可以使用逗号分隔的数据,并让它将下面的值吐出到列中?即 Name IPAddress ResponseTime Subnet x qwe qweeqw
Name IPAddress ResponseTime Subnet
x qwe qweeqwe qweqwe
现在,增加的值并不重要,只是增加值并提取它们的能力
Name Value
—- —–
x-410ZWG \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-410ZWG",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-47045Q \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-47045Q",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-440J26 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-440J26",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-410Y45 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-410Y45",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-DJKVV1 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-DJKVV1",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
nonexistant
x-DDMVV1 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-DDMVV1",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-470481 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-470481",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-DHKVV1 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-DHKVV1",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-430XXF \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-430XXF",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-DLKVV1 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-DLKVV1",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-410S86 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-410S86",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-SCH004 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-SCH004",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
x-431KMS
x-440J22 \\x-DHMVV1\root\cimv2:Win32_PingStatus.Address="x-440J22",BufferSize=32,NoFragmentation=false,RecordRoute=0,…
谢谢你的帮助
当前代码
Function Get-RunspaceData {
[cmdletbinding()]
param(
[switch]$Wait
)
Do {
$more = $false
Foreach($runspace in $runspaces) {
If ($runspace.Runspace.isCompleted) {
$runspace.powershell.EndInvoke($runspace.Runspace)
$runspace.powershell.dispose()
$runspace.Runspace = $null
$runspace.powershell = $null
} ElseIf ($runspace.Runspace -ne $null) {
$more = $true
}
}
If ($more -AND $PSBoundParameters['Wait']) {
Start-Sleep -Milliseconds 100
}
#Clean out unused runspace jobs
$temphash = $runspaces.clone()
$temphash | Where {
$_.runspace -eq $Null
} | ForEach {
Write-Verbose ("Removing {0}" -f $_.computer)
$Runspaces.remove($_)
}
Write-Host ("Remaining Runspace Jobs: {0}" -f ((@($runspaces | Where {$_.Runspace -ne $Null}).Count)))
} while ($more -AND $PSBoundParameters['Wait'])
}
#Begin
#What each runspace will do
$ScriptBlock = {
Param ($computer,$hash)
$Ping = test-connection $computer -count 1 -ea 0
$hash[$Computer]= $Ping
}
#Setup the runspace
$Script:runspaces = New-Object System.Collections.ArrayList
# Data table for all of the runspaces
$hash = [hashtable]::Synchronized(@{})
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspacepool = [runspacefactory]::CreateRunspacePool(1, 100, $sessionstate, $Host)
$runspacepool.Open()
#Process
ForEach ($Computer in $Computername) {
#Create the powershell instance and supply the scriptblock with the other parameters
$powershell = [powershell]::Create().AddScript($scriptBlock).AddArgument($computer).AddArgument($hash)
#Add the runspace into the powershell instance
$powershell.RunspacePool = $runspacepool
#Create a temporary collection for each runspace
$temp = "" | Select-Object PowerShell,Runspace,Computer
$Temp.Computer = $Computer
$temp.PowerShell = $powershell
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
$temp.Runspace = $powershell.BeginInvoke()
Write-Verbose ("Adding {0} collection" -f $temp.Computer)
$runspaces.Add($temp) | Out-Null
}
# Wait for all runspaces to finish
#End
Get-RunspaceData -Wait
$stoptimer = Get-Date
#Display info, and display in GridView
Write-Host
Write-Host "Availability check complete!" -ForegroundColor Cyan
"Execution Time: {0} Minutes" -f [math]::round(($stoptimer – $starttimer).TotalMinutes , 2)
$hash | ogv
在使用运行空间时,为运行空间编写脚本块的方式与为函数编写脚本块的方式基本相同。您可以将希望返回的内容写入管道,然后将其分配给变量,通过管道将其传递给另一个cmdlet或函数,或者只将其输出到控制台。不同之处在于,虽然函数会自动返回其结果,但它们在运行空间输出缓冲区中收集的运行空间在运行空间句柄上执行.EndInvoke()之前不会返回 一般来说,Powershell脚本的目标是(或应该是)创建对象,而使用运行空间的目标是通过多线程加速进程。您可以将运行空间中的字符串数据返回到主脚本,然后使用该数据在那里创建对象,但这将是一个单线程过程。在运行空间中创建对象,使其也是多线程的 以下是使用运行空间池对C类子网执行pingsweep的示例脚本:
Param (
[int]$timeout = 200
)
$scriptPath = (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent)
While (
($network -notmatch "\d{1,3}\.\d{1,3}\.\d{1,3}\.0") -and -not
($network -as [ipaddress])
)
{ $network = read-host 'Enter network to scan (ex. 10.106.31.0)' }
$scriptblock =
{
Param (
[string]$network,
[int]$LastOctet,
[int]$timeout
)
$options = new-object system.net.networkinformation.pingoptions
$options.TTL = 128
$options.DontFragment = $false
$buffer=([system.text.encoding]::ASCII).getbytes('a'*32)
$Address = $($network.trim("0")) + $LastOctet
$ping = new-object system.net.networkinformation.ping
$reply = $ping.Send($Address,$timeout,$buffer,$options)
Try { $hostname = ([System.Net.Dns]::GetHostEntry($Address)).hostname }
Catch { $hostname = 'No RDNS' }
if ( $reply.status -eq 'Success' )
{ $ping_result = 'Yes' }
else { $ping_result = 'No' }
[PSCustomObject]@{
Address = $Address
Ping = $ping_result
DNS = $hostname
}
}
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(100,100)
$RunspacePool.Open()
$Jobs =
foreach ( $LastOctet in 1..254 )
{
$Job = [powershell]::Create().
AddScript($ScriptBlock).
AddArgument($Network).
AddArgument($LastOctet).
AddArgument($Timeout)
$Job.RunspacePool = $RunspacePool
[PSCustomObject]@{
Pipe = $Job
Result = $Job.BeginInvoke()
}
}
Write-Host 'Working..' -NoNewline
Do {
Write-Host '.' -NoNewline
Start-Sleep -Seconds 1
} While ( $Jobs.Result.IsCompleted -contains $false)
Write-Host ' Done! Writing output file.'
Write-host "Output file is $scriptPath\$network.Ping.csv"
$(ForEach ($Job in $Jobs)
{ $Job.Pipe.EndInvoke($Job.Result) }) |
Export-Csv $scriptPath\$network.ping.csv -NoTypeInformation
$RunspacePool.Close()
$RunspacePool.Dispose()
运行空间脚本对每个地址执行ping,如果ping成功,将尝试从DNS解析主机名。然后,它根据该数据构建一个自定义对象,并将其输出到管道。最后,在运行空间作业上完成.EndInvoke()并直接导入导出CSV时,将返回这些对象,但它也可以很容易地输出到控制台,或保存到变量中。我想弄清楚为什么需要同步哈希表。您没有在运行空间之间共享任何数据,因此似乎不需要它。总之,让运行空间脚本从ping结果中创建PS自定义对象并输出这些对象,然后在执行.EndInvoke()时从管道中提取结果会简单得多。我一直在寻找从运行空间中的命令中提取结果的方法(对运行空间来说是新的),那是我在附近发现的唯一东西。我将研究让每个运行空间创建一个PS自定义对象并输出给它们。关于我在哪里可以读到它,有什么指导吗?每次我创建PSObject时,它都是在scriptblock中完成的,没有产生任何结果,我猜我在阅读后将它们放在了错误的位置,并将其放在了.EndInvoke()中,谢谢您的帮助!添加了一个带有示例脚本的答案,以演示如何从运行空间将管道数据返回到管道。谢谢!我已经修改了它,它在我的ping扫描中工作得非常好,我甚至还修改了它来计算MS补丁。现在,如果我能完全理解如何设定这些(学习时间)以及如何设定一个暂停时间就好了。但这将是另一条线索。谢谢你的帮助,你真是个天才!不会让我投票,没有足够的声誉,但你值得投票!以下是强制执行超时的一种方法: