Reputation: 9015
When I run this in a PowerShell console:
$callback = [System.Threading.TimerCallback]{
param($state)
}
$timer = [System.Threading.Timer]::new($callback, $null,
[timespan]::Zero,
[timespan]::FromSeconds(1))
Then once $callback
gets called (I made sure that this is the root cause, by changing the dueTime
constructor's parameter from [timespan]::Zero
to longer delays), the whole console process crashes, saying that powershell has stopped working
.
What could be the reason? how can I overcome this?
Upvotes: 3
Views: 731
Reputation: 311
The error is:
There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type.
And stems from
System.Management.Automation.ScriptBlock.GetContextFromTLS()
The delegate is the issue. This is how I got it working:
$helper = @'
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Management.Automation.Runspaces;
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;
}
}
'@
add-type -TypeDefinition $helper
$runspacedDelegate = [RunspacedDelegateFactory]::NewRunspacedDelegate($callback, [Runspace]::DefaultRunspace)
$timer = [System.Threading.Timer]::new(
$runspacedDelegate,
$null,
[timespan]::Zero,
[timespan]::FromSeconds(1))
I borrowed NewRunspacedDelegate from
https://www.powershellgallery.com/packages/ContainerTools/0.0.1
Upvotes: 3