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.
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.
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.
Thanks!
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;