使用运行空间池和 begininvoke 时如何收集返回值数据? [英] How can I collect the return value data when using a runspace pool and begininvoke?

查看:90
本文介绍了使用运行空间池和 begininvoke 时如何收集返回值数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我让这段代码与 powershell.Invoke() 同步运行良好,但是使用 powershell.BeginInvoke() 我无法捕获输出.要使用下面的代码,您需要填充 $servers 变量,否则它应该运行.

I have this code working well synchronously with powershell.Invoke() however with powershell.BeginInvoke() I am not able to capture the output. To use the below code you'll need to populate the $servers variable and it should run otherwise.

我尝试通过在使用 EndInvoke() 时将每个线程添加到 $threads 变量来捕获输出,并且我能够看到线程句柄和 iscompleted 值,但是我无法弄清楚我返回的值在哪里存储每个函数的返回部分.

I tried to capture the output by adding each thread to the $threads variable while using EndInvoke() and I am able to see the thread handle and the iscompleted value, however I can't figure out where the value I am returning with the return portion of each function is stored.

第一个块是我看到的输出,在一个异步完成之前显示为 false,直到它完成,然后所有线程句柄显示为 true.

The first block is the output I see, showing false for one async being finished until it finishes and then all thread handles show true.

谢谢!

8804 is True
16420 is True
13352 is True
11184 is True
3872 is True
8288 is True
17296 is False
20816 is True
11628 is True
17688 is True
12856 is True
19400 is True

8804 is True
16420 is True
13352 is True
11184 is True
3872 is True
8288 is True
17296 is True
20816 is True
11628 is True
17688 is True
12856 is True
19400 is True


Thread count: 12
Time elapsed: 3


cls;

$stopwatch =  [system.diagnostics.stopwatch]::StartNew();

#region Runspace Pool

[runspacefactory]::CreateRunspacePool() | Out-Null;
$SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault();
$RunspacePool = [runspacefactory]::CreateRunspacePool(

    1, #Min Runspaces

    16 #Max Runspaces

);
$RunspacePool.Open();

#endregion Runspace pool

$threads = New-Object System.Collections.ArrayList;
$servers = @("goodServer1", "goodServer2", "badServer1", "goodServer3");

foreach ($server in $servers)
{
    $PowerShell = [powershell]::Create();
    $PowerShell.RunspacePool = $RunspacePool;

    [void]$PowerShell.AddScript({

        Param ($server, $portNumber)
        
        [pscustomobject]@{

            server = $server
            portNumber = $portNumber

        } | Out-Null
    
        Function testPort ($server, $portNumber)
        {
            $testPort = New-Object System.Net.Sockets.TCPClient # -ArgumentList $server, 3389;
            $testPort.SendTimeout = 3;
            try
            {
                $testPort.Connect($server, $portNumber);
            }
            catch
            {
                #do nothing;
            }
            $result = $testPort.Connected;
            $testPort.Close();          
            $dateTime = ([DateTime]::Now.ToString());
            
            return "$server|testPort|$result|$dateTime"; # server | function | result | DateTime
        }


        testPort -server $server -portNumber $portNumber;
    }) # end of add script

    $portNumber = "3389";
    $PowerShell.AddParameter('server', $server).AddParameter('portNumber', $portNumber) | Out-Null;
    $returnVal = $PowerShell.BeginInvoke();
    $temp = "" | Select PowerShell,returnVal;
    $temp.PowerShell = $PowerShell;
    $temp.returnVal = $returnVal;
    $threads.Add($Temp) | Out-Null;
    
    
    $PowerShell = [powershell]::Create();
    $PowerShell.RunspacePool = $RunspacePool;
    [void]$PowerShell.AddScript({

        Param ($server, $shareName, $timeOutInMs)
        
        [pscustomobject]@{

            server = $server
            shareName = $shareName
            timeOutInMs = $timeOutInMs

        } | Out-Null
    

        Function testShare ($server, $shareName, $timeOutInMs)
        {
        $cSharp = 
@'
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace cSharp7
{
    public class cSharpClass
    {
        public bool verifyDirectoryExists(string uri, int timeoutInMs)
        {
            var task = new Task<bool>(() =>
            {
                var dir = new DirectoryInfo(uri);
                return dir.Exists;
            });
            task.Start();
            return task.Wait(timeoutInMs) && task.Result;
        }
        
        public bool verifyFileExists(string uri, int timeoutInMs)
        {
            var task = new Task<bool>(() =>
            {
                var fi = new FileInfo(uri);
                return fi.Exists;
            });
            task.Start();
            return task.Wait(timeoutInMs) && task.Result;
        }
    }
}
'@

            $assemblies = ("System", "System.Collections", "System.ComponentModel", "System.Data", "System.Drawing", "System.Linq", "System.Threading.Tasks", "System.Windows.Forms", "System.Management.Automation", "System.Security", "System.Threading", "System.Collections.Concurrent", "System.Security.Principal", "System.Management", "System.IO", "System.Collections");
            Add-Type -TypeDefinition $cSharp -ReferencedAssemblies $assemblies -Language CSharp;
            $directoryExists = New-Object CSharp7.cSharpClass;
            $path = "\\" + $server + "\" + $shareName;
            try
            {
                $result = $directoryExists.verifyDirectoryExists($path, $timeOutInMs); # has a 2 minute timeout period, needs an asynchronous thread with a timeout period
                #Write-Host $result;
            }
            catch
            {
                # do nothing
            }
            
            $dateTime = ([DateTime]::Now.ToString());
            return "$server|testShare|$result|$dateTime"; # server | function | result | DateTime
        }

        testShare -server $server -shareName $shareName -timeOutInMs $timeOutInMs;
    }) # end of add script

    $shareName = "c$";
    $timeOutInMs = "3000";
    $PowerShell.AddParameter('server', $server).AddParameter('shareName', $shareName).AddParameter('timeOutInMs', $timeOutInMs) | Out-Null;
    $returnVal = $PowerShell.BeginInvoke();
    $temp = "" | Select PowerShell,returnVal;
    $temp.PowerShell = $PowerShell;
    $temp.returnVal = $returnVal;
    $threads.Add($Temp) | Out-Null;
    
    
    $PowerShell = [powershell]::Create();
    $PowerShell.RunspacePool = $RunspacePool;
    [void]$PowerShell.AddScript({

        Param ($server, $pingCount)
        
        [pscustomobject]@{

            server = $server
            pingCount = $pingCount

        } | Out-Null
    

        Function testPing ($server, $pingCount)
        { 
            try
            {
                $result = Test-Connection $server -Count $pingCount -Quiet;
            }
            catch
            {
                # do nothing
            }
            
            $dateTime = ([DateTime]::Now.ToString());
            
            return "$server|testPing|$result|$dateTime"; # server | function | result | DateTime
        } 
        
        testPing -server $server -pingCount $pingCount;
    }) # end of add script

    $pingCount = "1";
    $PowerShell.AddParameter('server', $server).AddParameter('pingCount', $pingCount) | Out-Null;
    $returnVal = $PowerShell.BeginInvoke();
    $temp = "" | Select PowerShell,returnVal;
    $temp.PowerShell = $PowerShell;
    $temp.returnVal = $returnVal;
    $threads.Add($Temp) | Out-Null;
}


$completed = $false;
while ($completed -eq $false)
{
    $completed = $true;
    
    foreach ($thread in $threads)
    {
        $endInvoke = $thread.PowerShell.EndInvoke($thread.returnVal);
        $endInvoke;
        $threadHandle = $thread.returnVal.AsyncWaitHandle.Handle;
        $threadIsCompleted = $thread.returnVal.IsCompleted;
        #Write-Host "$threadHandle is $threadIsCompleted";
        if ($threadIsCompleted -eq $false)
        {
            $completed = $false;
        }
    }
    Write-Host "";
    sleep -Milliseconds 500;
}

foreach ($thread in $threads)
{
    $thread.PowerShell.Dispose();
}

$stopwatch.Stop();

Write-Host "";
Write-Host "Thread count:" $threads.Count;
Write-Host "Time elapsed:" $stopwatch.Elapsed.Seconds;

推荐答案

以下是捕获返回值数据的方法.您使用 2 个属性名称定义自定义对象 $temp,在本例中为 Powershell 和 returnVal.然后将它们添加到数组列表中.异步 BeginInvoke 完成后,您可以通过执行此操作对 asyncResult 调用 EndInvoke $endInvoke = $thread.PowerShell.EndInvoke($thread.returnVal);并根据需要对其进行解析.

Here is how you capture the return value data. You define the custom object $temp with 2 properties names, in thise case Powershell and returnVal. Then you add them to an array list. After the async BeginInvoke is completed you can call EndInvoke against the asyncResult by doing this $endInvoke = $thread.PowerShell.EndInvoke($thread.returnVal); and parse it however you want.

这一定是我写过的最复杂的脚本,其中包含运行空间池、运行空间、异步返回、传递的函数,甚至还混入了一些 c#.希望其他人可以从这些部分或全部中汲取经验.

This has to be the most complicated script I've ever written with a runspace pool, runspaces, asynchronous returns, functions being passed and even some c# mixed in. Hopefully others can draw from parts or all of this.

$returnVal = $PowerShell.BeginInvoke();
$temp = "" | Select PowerShell,returnVal;
$temp.PowerShell = $PowerShell;
$temp.returnVal = $returnVal;
$threads.Add($Temp) | Out-Null;

$completed = $false;
while ($completed -eq $false)
{
    $completed = $true;
    
    foreach ($thread in $threads)
    {
        $endInvoke = $thread.PowerShell.EndInvoke($thread.returnVal);
        $endInvoke;
        $threadHandle = $thread.returnVal.AsyncWaitHandle.Handle;
        $threadIsCompleted = $thread.returnVal.IsCompleted;
        #Write-Host "$threadHandle is $threadIsCompleted";
        if ($threadIsCompleted -eq $false)
        {
            $completed = $false;
        }
    }
    Write-Host "";
    sleep -Milliseconds 500;
}

foreach ($thread in $threads)
{
    $thread.PowerShell.Dispose();
}

这篇关于使用运行空间池和 begininvoke 时如何收集返回值数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆