【问题标题】:Utilize Results from Synchronized Hashtable (Runspacepool 6000+ clients)利用同步哈希表的结果(Runspacepool 6000+ 客户端)
【发布时间】:2023-03-12 01:06:01
【问题描述】:

改编一个脚本来执行多个功能,从测试连接开始收集数据,将达到 6000 多台机器,所以我使用的是从以下站点改编的 RunspacePools;

http://learn-powershell.net/2013/04/19/sharing-variables-and-live-objects-between-powershell-runspaces/

数据如下,我想把它排序成一个数组(我认为这是术语),所以我可以通过结果对数据进行排序。这将适用于从序列号到 IAVM 数据的多个其他功能。

有什么方法可以使用逗号分隔的数据并将下面的值吐到列中?浏览器

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

【问题讨论】:

  • 试图让我明白为什么需要同步哈希表。您没有在运行空间之间共享任何数据,因此似乎不需要它。恕我直言,让运行空间脚本从 ping 结果创建 PS 自定义对象并输出这些对象会简单得多,然后在执行 .EndInvoke() 时从管道中获取。
  • 我一直在寻找一些方法来从运行空间中的命令中提取结果(对运行空间来说是新的),这是我发现的唯一接近它的东西。我将研究让每个运行空间创建一个 PS 自定义对象并输出给它们。关于我可以在哪里阅读它的任何指导?每次我创建 PSObject 时,它都是在没有产生任何结果的脚本块中完成的,我猜我在阅读后将它们放置在不正确的位置,将其放置在 .EndInvoke() 感谢您的帮助!
  • 添加了一个带有示例脚本的答案,以演示从运行空间将管道数据返回到管道。

标签: multithreading powershell hashtable synchronized runspace


【解决方案1】:

当您使用运行空间时,您为运行空间编写脚本块的方式与编写函数的方式几乎相同。您将希望返回的任何内容写入管道,然后将其分配给一个变量,将其通过管道传输到另一个 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() 在运行空间作业上完成并直接通过管道传输到 Export-CSV 时,这些对象会返回,但它可以很容易地输出到控制台,或保存到变量中。

【讨论】:

  • 谢谢!我已经对此进行了调整,它在我的 ping 扫描中工作得非常好,我什至已经将它用于计算 MS 补丁。现在,如果我完全了解如何建立这些(学习时间)以及如何设置超时。但这将是另一个话题。谢谢你的帮助,你是个天才!不让我投票,没有足够的声誉,但你应该投票!
  • 这里是强制超时的一种方法:mjolinor.wordpress.com/2014/05/26/…
猜你喜欢
  • 1970-01-01
  • 2019-04-21
  • 1970-01-01
  • 2017-07-22
  • 1970-01-01
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 2023-01-04
相关资源
最近更新 更多