.net powershell中使用回调的异步命名管道

.net powershell中使用回调的异步命名管道,.net,powershell,asynchronous,named-pipes,.net,Powershell,Asynchronous,Named Pipes,我正在尝试使用powershell中的回调异步使用.net NamedPipeServerStream的命名管道 我目前正在使用以下代码: 服务器端: $myCallback = [AsyncCallback]{ "Connected" } $pipe = New-Object System.IO.Pipes.NamedPipeServerStream("alert", [System.IO.Pipes.PipeDirection]::InOut, 1, [System.IO.Pipes.

我正在尝试使用powershell中的回调异步使用.net NamedPipeServerStream的命名管道

我目前正在使用以下代码:

服务器端:

$myCallback = [AsyncCallback]{
  "Connected"
}

$pipe = New-Object System.IO.Pipes.NamedPipeServerStream("alert", [System.IO.Pipes.PipeDirection]::InOut, 1, [System.IO.Pipes.PipeTransmissionMode]::Message, [System.IO.Pipes.PipeOptions]::Asynchronous)
$pipe.BeginWaitForConnection($myCallback, "alertCallback")
客户端:

$pipe = new-object System.IO.Pipes.NamedPipeClientStream("alert");
$pipe.Connect(3000); 

$sw = new-object System.IO.StreamWriter($pipe);
$sw.WriteLine("Test"); 
我首先调用服务器端代码,它报告回调已成功注册

AsyncState                                        IsCompleted AsyncWaitHandle                       CompletedSynchronously
----------                                        ----------- ---------------                       ----------------------
alertCallback                                           False System.Threading.ManualRese...                         False
一旦客户端代码被调用,powershell服务器脚本就会崩溃-不会引发异常,我只会收到一个“powershell已停止工作”windows样式的错误框。我不知道为什么会发生这种情况,而且我似乎无法从脚本中获取任何异常或其他调试信息,以了解出了什么问题。如果我尝试同步地做同样的事情,一切都会按预期进行。非常感谢您的帮助

  • 希望客户端代码在作业中或在不同的脚本中
  • pipeDirection
    添加到客户端管道
  • 在写入客户端流之前添加
    sw.AutoFlush=$true
  • 如果仍不起作用,请尝试将CRLF添加到消息:
    $sw.WriteLine(“Test\r\n”)

  • 希望这有帮助。

    我也遇到了同样的问题,我在Windows事件日志中发现了一个与所述错误类似的异常

    我实施了相同的解决方案,我能够这样工作:

    服务器代码:

    $PipeName = 'testPipe'
    $PipeDir  = [System.IO.Pipes.PipeDirection]::In
    $PipeOpt  = [System.IO.Pipes.PipeOptions]::Asynchronous
    $PipeMode = [System.IO.Pipes.PipeTransmissionMode]::Message
    
    $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
    
    $Global:messageReceived = $null
    
    $callback = [System.AsyncCallback] {
        param([IAsyncResult] $iar)
    
        $pipeServer.EndWaitForConnection($iar)
        $Global:messageReceived = $sr.Readline()
        $pipeServer.Close()
    }
    
    $runspacedDelegate = [RunspacedDelegateFactory]::NewRunspacedDelegate($callback, [Runspace]::DefaultRunspace)
    
    try
    {
        $pipeServer = New-Object system.IO.Pipes.NamedPipeServerStream($PipeName, $PipeDir, 1, $PipeMode, $PipeOpt)
        $sr = new-object System.IO.StreamReader($pipeServer)
    
        $task = $pipeServer.BeginWaitForConnection($runspacedDelegate ,$null)
    
        while(! $Global:messageReceived)
        {
            Write-Host 'waiting'
            Start-Sleep 1
        }
    
        Write-Host "Message Received: $messageReceived"
    }
    catch
    {
        Write-Host "Error receiving pipe message: $_" -ForegroundColor Red
    }
    finally
    {
        if ($sr)
        {
            $sr.Dispose()
            $sr = $null
        }
        if ($pipeServer)
        {
            $pipeServer.Dispose()
            $pipeServer = $null
        }
    }
    
    客户端代码

    $PipeName = 'testPipe'
    $PipeDir  = [System.IO.Pipes.PipeDirection]::Out
    $PipeOpt  = [System.IO.Pipes.PipeOptions]::Asynchronous
    
    $Message = Read-Host 'Enter the message to send'
    
    try
    {
        $pipeClient = new-object System.IO.Pipes.NamedPipeClientStream(".", $PipeName, $PipeDir, $PipeOpt)
        $sw = new-object System.IO.StreamWriter($pipeClient)
        $pipeClient.Connect(1000)
        if (!$pipeClient.IsConnected)
        {
            throw "Failed to connect client to pipe $pipeName"
        }
        $sw.AutoFlush = $true
        $sw.WriteLine($Message)
    }
    catch
    {
        Write-Host "Error sending pipe message: $_" -ForegroundColor Red
    }
    finally
    {
        if ($sw)
        {
            $sw.Dispose()
            $sw = $null
        }
        if ($pipeClient)
        {
            $pipeClient.Dispose()
            $pipeClient = $null
        }
    }
    

    客户端的Windows日志中有任何内容吗?不幸的是没有。我一直在查看事件日志的Powershell部分,我可以看到我知道的异常条目,以及从以前编写上述代码的失败尝试中向控制台报告的异常条目,因此我假设这是正确的位置。您可以使用sysinternals中的procdump在异常发生时让它创建一个转储文件。类似于
    procdump-ma-e100
    。在发生崩溃转储后,可以开始使用WinDbg进行调查。