Reputation: 5817
I am attempting to spawn a new thread in PowerShell's command line using:
$t = New-Object System.Threading.Thread ([System.Threading.ThreadStart]{
Write-Host "Hello World"
});
$t.Start();
What happens is that a dialog appears saying "Powershell has stopped working".
I want to use my own Job
class, written in C#, with start, pause, continue and stop methods. It uses a couple of WaitHandles
to achieve this together with a new Thead
instance.
I am aware of Start-Job
etc, but would like to use real threads.
Any way?
EDIT: There seems to be a way https://davewyatt.wordpress.com/2014/04/06/thread-synchronization-in-powershell/
Upvotes: 3
Views: 1184
Reputation: 5817
UPDATE I have packaged the below into a module called PSRunspacedDelegate
, which you can install using Install-Package PSRunspacedDelegate
. You can find documentation on GitHub.
Adam Driscoll's PowerShell Parallel Foreach explains that a thread running PowerShell code must have a Runspace
.
In other words [Runspace]::DefaultRunspace
cannot be null.
I ended up writing a RunspacedDelegateModule.psm1
module, with a function New-RunspacedDelegate
that does the work.
Add-Type -Path "$PSScriptRoot\RunspacedDelegateFactory.cs"
Function New-RunspacedDelegate(
[Parameter(Mandatory=$true)][System.Delegate]$Delegate,
[Runspace]$Runspace=[Runspace]::DefaultRunspace) {
[PowerShell.RunspacedDelegateFactory]::NewRunspacedDelegate($Delegate, $Runspace)
}
RunspacedDelegateFactory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Management.Automation.Runspaces;
namespace PowerShell
{
public class RunspacedDelegateFactory
{
public static Delegate NewRunspacedDelegate(Delegate _delegate, Runspace runspace)
{
Action setRunspace = () => Runspace.DefaultRunspace = runspace;
return ConcatActionToDelegate(setRunspace, _delegate);
}
private static Expression ExpressionInvoke(Delegate _delegate, params Expression[] arguments)
{
var invokeMethod = _delegate.GetType().GetMethod("Invoke");
return Expression.Call(Expression.Constant(_delegate), invokeMethod, arguments);
}
public static Delegate ConcatActionToDelegate(Action a, Delegate d)
{
var parameters =
d.GetType().GetMethod("Invoke").GetParameters()
.Select(p => Expression.Parameter(p.ParameterType, p.Name))
.ToArray();
Expression body = Expression.Block(ExpressionInvoke(a), ExpressionInvoke(d, parameters));
var lambda = Expression.Lambda(d.GetType(), body, parameters);
var compiled = lambda.Compile();
return compiled;
}
}
}
What I noticed is that it would still crash if I used Write-Host
, but Out-File
seems to be ok.
Here is how to use it:
Import-Module RunspacedDelegateModule;
$writeHello = New-RunspacedDelegate ([System.Threading.ThreadStart]{
"$([DateTime]::Now) hello world" | Out-File "C:\Temp\log.txt" -Append -Encoding utf8
});
$t = New-Object System.Threading.Thread $writeHello;
$t.Start();
Upvotes: 4