如何从 powershell 运行空间作业中检索数据

如何从 powershell 运行空间作业中检索数据

尝试多线程运行一些需要一段时间才能运行的脚本。一个例子是获取用户的最后一次登录。它检查我们所有的 DC,然后返回最近的时间。我们有相当多的 DC,而且它们是全局的,因此按顺序运行需要一段时间。

我看到了这个答案如何在不使用作业的情况下并行运行 PowerShell 脚本?

这让我开始设置运行空间并运行它,但我不确定如何恢复数据。

这是我目前所拥有的

$username = Read-Host "Enter the Users ID"
$dcs = Get-ADDomainController -Filter {Name -like "*"} | Select -expandproperty name
$Code = {
  Param($username,$dc)
  Get-ADUser $username | Get-ADObject -Server $dc -Properties lastLogon | 

Select -Expandproperty lastLogon
  }
$rsPool = [runspacefactory]::CreateRunspacePool(1,8)
$rsPool.Open()
foreach($dc in $dcs)
  {
  $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($username).AddArgument($dc)
  $PSinstance.RunspacePool = $RunspacePool
  $PSinstance.BeginInvoke()
  }

所以我只需要等待每项工作完成,然后捕获每项工作的结果,但我不知道该怎么做

编辑:此外,我以前也曾尝试过用作业来做到这一点,但代码实际上比正常的脚本花费的时间更长

$userName = Read-Host "Enter NTID: "

$time = 0


$dcs = Get-ADDomainController -Filter {Name -like "*"} | Select -expandproperty name


$scriptbox = {

Param($username,$dc)

Get-ADUser $username | Get-ADObject -Server $dc -Properties lastLogon | Select -Expandproperty lastLogon

}   

foreach($dc in $dcs){start-Job -ScriptBlock $scriptbox -ArgumentList $username,$dc}


Get-Job | Wait-Job


Get-Job

$Data = ForEach ($Job in (Get-Job)) {

Receive-Job $Job

Remove-Job $Job

}


Foreach ($date in $Data){if($date -gt $time){$time = $date}}


$dt = [DateTime]::FromFileTime($time)

write-Host $username "last logged on at:" $dt 

答案1

您正确地使用运行空间而不是*-Jobcmdlet,因为它们速度更快!

我最近发过异步Tcp扫描它利用了 Runspaces,速度非常快!可以轻松修改它以运行任何脚本块。下面是集成后您的原始脚本应该是什么样子。

警告:我无法测试以下代码。我根据使用 Active Directory cmdlet 的经验对原始脚本进行了一些更改。

# Script to run in each thread.
[System.Management.Automation.ScriptBlock]$ScriptBlock = {

    $adUser = Get-ADUser -Identity $args[0] -Server $args[1] -Properties lastLogon

    $result = New-Object PSObject -Property @{ 'User'      = $args[0];
                                               'DC'        = $args[1];
                                               'LastLogon' = $adUser.LastLogon; }

    return $result

} # End Scriptblock

function Invoke-AsyncJob
{
    [CmdletBinding()]
    param(
        [parameter(Mandatory=$true)]
        [System.String]
        # User ID
        $Username
    )

    Import-Module -Name ActiveDirectory

    $Results = @()

    $AllJobs = New-Object System.Collections.ArrayList

    $AllDomainControllers = Get-ADDomainController -Filter "*"

    $HostRunspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(2,10,$Host)

    $HostRunspacePool.Open()

    foreach($DomainController in $AllDomainControllers)
    {
        $asyncJob = [System.Management.Automation.PowerShell]::Create().AddScript($ScriptBlock).AddParameters($($Username,$($DomainController.Name)))

        $asyncJob.RunspacePool = $HostRunspacePool

        $asyncJobObj = @{ JobHandle   = $asyncJob;
                          AsyncHandle = $asyncJob.BeginInvoke()    }

        $AllJobs.Add($asyncJobObj) | Out-Null
    }

    $ProcessingJobs = $true

    Do {

        $CompletedJobs = $AllJobs | Where-Object { $_.AsyncHandle.IsCompleted }

        if($null -ne $CompletedJobs)
        {
            foreach($job in $CompletedJobs)
            {
                $result = $job.JobHandle.EndInvoke($job.AsyncHandle)

                if($null -ne $result)
                {
                    $Results += $result
                }

                $job.JobHandle.Dispose()

                $AllJobs.Remove($job)
            } 

        } else {

            if($AllJobs.Count -eq 0)
            {
                $ProcessingJobs = $false

            } else {

                Start-Sleep -Milliseconds 1000
            }
        }

    } While ($ProcessingJobs)

    $HostRunspacePool.Close()
    $HostRunspacePool.Dispose()

    return $Results

} # End function Invoke-AsyncJob

相关内容