首页 > 解决方案 > System.Threading.Timer 杀死 PowerShell 控制台

问题描述

当我在 PowerShell 控制台中运行它时:

$callback = [System.Threading.TimerCallback]{
    param($state)
}

$timer = [System.Threading.Timer]::new($callback, $null,
    [timespan]::Zero,
    [timespan]::FromSeconds(1))

然后一旦$callback被调用(我确保这是根本原因,通过将dueTime构造函数的参数从更改[timespan]::Zero为更长的延迟),整个控制台进程崩溃,说powershell has stopped working.

可能是什么原因?我该如何克服呢?

标签: powershell

解决方案


错误是:

此线程中没有可用于运行脚本的运行空间。您可以在 System.Management.Automation.Runspaces.Runspace 类型的 DefaultRunspace 属性中提供一个。

并且源于

System.Management.Automation.ScriptBlock.GetContextFromTLS()

代表是问题。这就是我的工作方式:

$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))

我借用了 NewRunspacedDelegate

https://www.powershellgallery.com/packages/ContainerTools/0.0.1


推荐阅读