这在 Powershell 中可行吗?

Posted

技术标签:

【中文标题】这在 Powershell 中可行吗?【英文标题】:Is this possible in Powershell? 【发布时间】:2021-05-10 15:23:31 【问题描述】:

我想从父 powershell 窗口生成一个子窗口,子窗口将加载一个 .ps1 文件,其中包含一个 do/while 循环,该循环引用了一个可以动态更新的参数。

所以我可以使用 names 参数从父窗口调用子窗口,然后在任何时候动态地使用一组新名称再次调用它,或者以某种方式为子窗口动态更新变量。

Powershell 可以实现这些吗?我可以让变量范围包含父 Powershell 窗口和子 Powershell 窗口吗?我可以动态更新子窗口变量数组吗?我唯一的途径是写入文本文件并让子窗口代码不断轮询该文本文件吗?如果是这样,避免权限锁定问题的最佳方法是什么?

#parentwindow

$handle = . \childWindow.ps1 -names @"One", "Two", "Three", "Four", "Five"


#childwindow

Param ($names)  

do

    foreach ($name in $names)
    
        Write-Host $name;
    
    sleep 5;

while ($continueProcessing)

几分钟后

$handle = . \childWindow.ps1 -names @"Six", "Seven", "Eight", "Nine", "Ten"

或类似的东西

$handle.names = @"Six", "Seven", "Eight", "Nine", "Ten"

【问题讨论】:

这似乎是寻找问题的解决方案。你到底想做什么?也许有更好的方法可以避免多个进程等。 我不确定启动实例后是否要更新变量,但要启动新实例,我认为您正在寻找:来自父窗口的invoke-expression 'cmd /c start powershell -file "childWindow.ps1 -names @" ' 您可能想查看同步集合 >>> 线程安全集合 | Microsoft Docs — docs.microsoft.com/en-us/dotnet/standard/collections/… 如果你想在各种 PowerShell 进程之间进行 IPC,这是可能的 (this way for example),但你真的需要在完整的 PowerShell 环境中这样做吗?你想达到什么目标? 【参考方案1】:

正如 OP 所求,这是一个简单且非常基本的完整的 PowerShell 实现的命名管道客户端/服务器,不会挂起。在一个 CLI 中启动服务器脚本。然后在另一个 CLI 中启动客户端脚本,您可以多次启动最后一个,然后在服务器 CLI 上查看效果。

PowerShell 代码不是很干净,但它只是一个示例演示。而且我负担不起那几个小时。

服务器脚本是一个基本的“主机列表”维护者,请注意,由于使用StreamWriter,每次写入后需要重新实例化输出管道。

这个服务器理解这些命令:

hello,回复当前日期和时间 add [host],它将 [host] 添加到其内部列表中,并以当前列表大小进行回复。 del [host],它将 [host] 从其内部列表中删除并回复剩余的主机数量。 list,它在其内部列表中回复 [host] 列表。

服务器脚本

# NamedPipe Server script
$status = 0;
$npipeServerInput = new-object System.IO.Pipes.NamedPipeServerStream('my_pipe_server_input', [System.IO.Pipes.PipeDirection]::In, 1, [System.IO.Pipes.PipeTransmissionMode]::Message, [System.IO.Pipes.PipeOptions]::None, 256, 256);
if (!$npipeServerInput) 
  Write-Host("Failed to open server input pipe...");
  exit(1);

$npipeServerOutput = new-object System.IO.Pipes.NamedPipeServerStream('my_pipe_server_output', [System.IO.Pipes.PipeDirection]::Out, 1, [System.IO.Pipes.PipeTransmissionMode]::Message, [System.IO.Pipes.PipeOptions]::None, 256, 256);
if (!$npipeServerOutput) 
  Write-Host("Failed to open server output pipe...");
  $npipeServerInput.Dispose();
  exit(1);

$server_list = new-object System.Collections.ArrayList;
function ProcessMessage([String]$ParMessage) 
  $reply = ""
  switch($ParMessage) 
    "hello" 
      $curdte = Get-Date -Format 'HH:mm:ss';
      $reply='Reply to '+$ParMessage+', im here, time is '+$curdte;
    
    "list" 
      $server_list | % $reply += [Environment]::NewLine + $_; ;
    
    default 
      if ($ParMessage.StartsWith("add ")) 
        $reply = $server_list.Add($ParMessage.Split(" ")[1]);
        $reply = "Added, " + [String]$server_list.Count + " items";
       else 
        if ($ParMessage.StartsWith("del ")) 
          $reply = $server_list.Remove($ParMessage.Split(" ")[1]);
          $reply = "Removed, " + [String]$server_list.Count + " items left";
         else 
          $reply = "Unknown command " + $ParMessage;
        
      
    
  
  return($reply);

Try 
  $npipeServerInput.WaitForConnection();
  $pipeReader = new-object System.IO.StreamReader($npipeServerInput);
  if (!$pipeReader) 
    Write-Host("Failed to read server input pipe...");
    $status = 2;
   else 
    Try 
      While(($msg = $pipeReader.ReadLine()) -notmatch 'QUIT') 
        Try 
          If ($msg.Length -gt 0) 
            $disp='Server got :'+$msg;
            Write-Host($disp);
            $reply = ProcessMessage($msg);
            $npipeServerOutput.WaitForConnection();
            $pipeWriter = new-object System.IO.StreamWriter($npipeServerOutput);
            if (!$pipeWriter) 
              Write-Host("Failed to write server output pipe...");
              $status = 2;
             else 
              Try 
                $reply_flag=0;
                While($reply_flag -eq 0) 
                  Try 
                    # Write-Output($reply) ^>5;
                    $pipeWriter.WriteLine($reply);
                    $reply_flag=1;
                   Catch [System.IO.IOException] 
                    # Deal as you whish with potential errors
                    Write-Host("Failed to write to server output pipe...");
                    exit(3);
                  ;
                ;
                $pipeWriter.Flush();
                Write-Host('Reply sent. '+$reply);
               Finally 
                # The streamwriter disposal will mess up our output pipe, so we recrerate it...
                $pipeWriter.Dispose();
                $npipeServerOutput.Dispose();
                $npipeServerOutput = new-object System.IO.Pipes.NamedPipeServerStream('my_pipe_server_output', [System.IO.Pipes.PipeDirection]::Out, 1, [System.IO.Pipes.PipeTransmissionMode]::Message, [System.IO.Pipes.PipeOptions]::None, 256, 256);
              
            
          
         Finally 
          $npipeServerInput.Disconnect();
          $npipeServerInput.WaitForConnection();
        
      ;
     Catch [System.IO.IOException] 
      # Deal as you whish with potential errors, you will have InvalidOperation here when the streamReader is empty
      Write-Host("Failed to read server input pipe...");
      exit(4);
    
  
 Catch [System.IO.IOException] 
  Write-Host("I/O failure...");
 Finally 
  If ($npipeServerInput) 
    $npipeServerInput.Dispose();
  
  If ($npipeServerOutput) 
    $npipeServerInput.Dispose();
  

exit($status)

客户端脚本:

    向服务器发送hello 并显示其回复。 向服务器发送add localhost 并显示其回复。 向服务器发送add google.com 并显示其回复。 向服务器发送add ***.com 并显示其回复。 向服务器发送del google.com 并显示其回复。 向服务器发送list 并显示其回复。

客户端脚本等待 5 秒以等待发送的每个命令的回复,如果服务器在客户端脚本中止的延迟时间内没有回复。每次客户端脚本运行时,localhost***.com 都会添加到服务器列表中。

对于商品,我厚颜无耻地从Oisin Grehan中取了New-ScriptBlockCallback非常方便直接在PowerShell中进行回调。

由于服务器脚本在每次写入后重新实例化其输出管道,客户端脚本随后对其连接的输入管道执行相同操作。这可以通过在服务器脚本中使用 StreamWriter 之外的其他内容来避免(我保留它以表明使用 PowerShell,您必须关心对象的底层处置)。为了方便起见,管道方法是类中的static 方法,因为我更喜欢return,它不会处理函数中发生的所有事情。还有一个用于来自服务器的传入消息的基本堆栈,以显示使用 callback 处理传入消息的基本方法。

客户端脚本

# NamedPipe Client script
#
# Client return status
#
$status = 0;
#
# Input and output named pipes to exchange with the server
# 
$npipeClientInput = new-object System.IO.Pipes.NamedPipeClientStream('.', 'my_pipe_server_output', [System.IO.Pipes.PipeDirection]::In, [System.IO.Pipes.PipeOptions]::None);
if (!$npipeClientInput) 
  Write-Host("Main: Failed to open client input pipe...");
  exit(1);

$npipeClientOutput = new-object System.IO.Pipes.NamedPipeClientStream('.', 'my_pipe_server_input', [System.IO.Pipes.PipeDirection]::Out, [System.IO.Pipes.PipeOptions]::None);
if (!$npipeClientOutput) 
  Write-Host("Main: Failed to open client output pipe...");
  $npipeClientInput.Dispose();
  exit(1);

# Thanks to Oisin Grehan, https://***.com/a/41155285/3641635
function New-ScriptBlockCallback 
    param(
        [parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [scriptblock]$Callback
    )
<#
    .SYNOPSIS
        Allows running ScriptBlocks via .NET async callbacks.
 
    .DESCRIPTION
        Allows running ScriptBlocks via .NET async callbacks. Internally this is
        managed by converting .NET async callbacks into .NET events. This enables
        PowerShell 2.0 to run ScriptBlocks indirectly through Register-ObjectEvent.         
 
    .PARAMETER Callback
        Specify a ScriptBlock to be executed in response to the callback.
        Because the ScriptBlock is executed by the eventing subsystem, it only has
        access to global scope. Any additional arguments to this function will be
        passed as event MessageData.
         
    .EXAMPLE
        You wish to run a scriptblock in reponse to a callback. Here is the .NET
        method signature:
         
        void Bar(AsyncCallback handler, int blah)
         
        ps> [foo]::bar((New-ScriptBlockCallback  ... ), 42)                        
 
    .OUTPUTS
        A System.AsyncCallback delegate.
#>
    # is this type already defined?    
    if (-not ("CallbackEventBridge" -as [type])) 
        Add-Type @"
            using System;
             
            public sealed class CallbackEventBridge
            
                public event AsyncCallback CallbackComplete = delegate  ;
 
                private CallbackEventBridge() 
 
                private void CallbackInternal(IAsyncResult result)
                
                    CallbackComplete(result);
                
 
                public AsyncCallback Callback
                
                    get  return new AsyncCallback(CallbackInternal); 
                
 
                public static CallbackEventBridge Create()
                
                    return new CallbackEventBridge();
                
            
"@
    
    $bridge = [callbackeventbridge]::create()
    Register-ObjectEvent -input $bridge -EventName callbackcomplete -action $callback -messagedata $args > $null
    $bridge.callback

class ClientPipes 
  #
  # Internal FIFO stack for incoming messages from the server
  # 
  static [System.Collections.Queue]$ReadStack;
  #
  # Function to send a message to the server
  #
  # Parameters : 
  #   ParOutputPipe : Ref to the output pipe
  #   $Message      : Message to send
  # Returns :
  #   0 : Success
  #   1 : Wrong parameters
  #   2 : I/O failure
  static [int32]SendServer([ref]$ParOutputPipe, [String]$Message) 
    $OutputPipe = [System.IO.Pipes.NamedPipeClientStream]$ParOutputPipe.value;
    # Connect the client output pipe
    if (!$OutputPipe.IsConnected) 
      $OutputPipe.Connect(2000);
      Write-Host("SendServer: output pipe connected.");
    
    $pipeWriter = new-object System.IO.StreamWriter($OutputPipe);
    if (!$pipeWriter) 
      Write-Host("SendServer: Failed to set a writer to client output pipe...");
      $status = 2;
     else 
      Try 
        if (!$pipeWriter) 
          Write-Host("SendServer: Wrong parameters..");
          return(1);
        
        Try 
          # We send to the server
          $pipeWriter.WriteLine($Message);
          $pipeWriter.Flush();
          $OutputPipe.WaitForPipeDrain();
         Catch [System.IO.IOException] 
          Write-Host("SendServer: Failed to write to server...");
          return(2);
         Finally 
          # The streamwriter disposal will mess up our output pipe, so we recrerate it...
          $pipeWriter.Dispose();
          $OutputPipe.Dispose();
          $ParOutputPipe.value = new-object System.IO.Pipes.NamedPipeClientStream('.', 'my_pipe_server_input', [System.IO.Pipes.PipeDirection]::Out, [System.IO.Pipes.PipeOptions]::None);
        
       Catch [System.IO.IOException] 
        # Deal as you whish with potential errors, you will have InvalidOperation here when the streamReader is empty
        Write-Host("SendServer: Failed to write client output pipe...");
        return(2);
      
    
    return(0);
  
  #
  # Synchonized function to push on the FIFO stack
  # 
  # Parameters : 
  #   $Message      : Message to push
  # Returns :
  #   0 : Success
  #   1 : Synchronization failure
  static [int32]PushOnStack([System.Collections.Queue]$Stack, [string]$ParMessage) 
    $SyncStack = [System.Collections.Queue]::Synchronized($Stack);
    if (!$SyncStack) 
      Write-Host("PushOnStack: Failed to synchronize...");
      return(1);
    
    $SyncStack.Enqueue($ParMessage);
    return(0);
  
  #
  # Synchonized function to pop from the FIFO stack
  # 
  # Parameters : 
  #   $Message      : Buffer to store message
  # Returns :
  #   0 : Success, there was a message
  #   1 : Success, there was no message
  #   2 : Synchronization failure
  static [int32]PopFromStack([System.Collections.Queue]$Stack,[ref]$ParMessage) 
    $SyncStack = [System.Collections.Queue]::Synchronized($Stack);
    if (!$SyncStack) 
      Write-Host("PopFromStack: Failed to synchronize...");
      return(2);
    
    if ($SyncStack.Count -ne 0) 
      $ParMessage.value = [String]$SyncStack.Dequeue();
      return(0);
     else 
      return(1);
    
  
  #
  # Callback function for incoming messages from the server
  #
  # Parameters : 
  #   $Result       : Object issued
  # Returns :
  #   0 : Success
  #   1 : Failure
  #   2 : Failure, stack
  #   3 : Failure, pipe
  static [int32]ProcessRead([IAsyncResult]$Result) 
    $status = 0;
    # Check if that comes from our ReadServer function
    $RefPipe = [ref]$Result.AsyncState[0];
    $Pipe = [System.IO.Pipes.NamedPipeClientStream]$RefPipe.value;
    if (!$Pipe) 
      Write-Host("ProcessRead: Unexpected event...");
      $status = 1;
     else 
      Write-Host("ProcessRead: Callback event");
      $Msg = [System.Text.Encoding]::ASCII.GetString($Result.AsyncState[1]);
      $Stack = [System.Collections.Queue]$Result.AsyncState[2];
      Write-Host("ProcessRead: read " + $Msg);
      if ([ClientPipes]::PushOnStack($Stack, $Msg) -ne 0) 
        Write-Host("ProcessRead: Failed to push message...");
        $status = 2;
      
      Try 
        $Pipe.EndRead($Result);
        #$Pipe.Close();
       Catch [System.IO.IOException] 
        Write-Host("Failed to terminate read client input pipe...");
        $status = 3;
       finally 
        # As the server have probably closed the pipe, we recreate it
        $RefPipe.value = new-object System.IO.Pipes.NamedPipeClientStream('.', 'my_pipe_server_output', [System.IO.Pipes.PipeDirection]::In, [System.IO.Pipes.PipeOptions]::None);
      
    
    return($status);
  
  #
  # Function to set a handler to read incoming messages from the server
  #
  # Parameters : 
  #   $ParInputPipe  : Ref to input pipe
  # Returns :
  #   0 : Success
  #   1 : Wrong parameters
  #   2 : I/O failure
  #   3 : Internal failure
  static [int32]ReadServer([ref]$ParInputPipe) 
    $InputPipe = [System.IO.Pipes.NamedPipeClientStream]$ParInputPipe.value;
    if (!$InputPipe) 
      Write-Host("ReadServer: Wrong parameters..");
      return(1);
    
    Try 
      # We create the Async callback to receive messages
      $Buffer = New-Object Byte[] 256
      $CallBackParams = @($ParInputPipe, $Buffer, [ClientPipes]::ReadStack)
      $CallBack = New-ScriptBlockCallback  param([IAsyncResult] $Result) Write-Host("Callback event"); [ClientPipes]::ProcessRead($Result); ;
      if (!$CallBack) 
        Write-Host("ReadServer: Failed to create a  callback...");
        return(3);
      
      # Connect the Pipe
      if (!$InputPipe.IsConnected) 
        $InputPipe.Connect(2000);
        Write-Host("ReadServer: Pipe connected.");
      
      # We add a signal handler to get incoming Message
      $AsyncHandler = $InputPipe.BeginRead($Buffer, 0, 256, $CallBack, $CallBackParams)
     Catch [System.IO.IOException] 
      Write-Host("ReadServer: Failed to set a callback...");
      return(2);
    
    return(0);
  
  #
  # Get last message from the msg stack
  #
  # Parameters : 
  #   $LastMsg  : Buffer to store last message
  #   $ParDelay : Timeout in second
  # Returns :
  #   0 : Success, there was a message
  #   1 : Timeout, no last message
  #   2 : Failure
  static [int32]GetLastMessage([ref]$LastMsg, [int32]$ParDelay) 
    $StackStatus = 1;
    $Timer = [Diagnostics.Stopwatch]::StartNew();
    While($StackStatus -eq 1 -and $Timer.Elapsed.TotalSeconds -lt $ParDelay) 
      Write-Host("GetLastMessage: Waiting for a reply...");
      $StackStatus = [ClientPipes]::PopFromStack([ClientPipes]::ReadStack, $LastMsg);
      if ($StackStatus -eq 1)  
        sleep -m 1000
      
    ;
    if ($StackStatus -eq 2) 
      Write-Host("GetLastMessage: Error on incoming reply...");
      return(2);
    
    return($StackStatus); 
  
  #
  # Exchnage request / rsponse with the server
  #
  # Parameters : 
  #   $InputPipe  : Ref to client input pipe
  #   $OutputPipe : Ref to client output pipe
  #   $Request    : Requets to send to the server
  #   $Response   : Buffer to store server response
  #   $ParDelay   : Timeout in second
  # Returns :
  #   0 : Success, we have have a response
  #   1 : Timeout, no last message
  #   2 : Failure
  static [int32]Request([ref]$InputPipe, [ref]$OutputPipe, [String]$Request,[ref]$Response, [int32]$ParDelay) 
    # We send to the server and we expect to get a reply
    Write-Host("Request: Sending " + $Request);
    if ([ClientPipes]::SendServer($OutputPipe, $Request) -ne 0) 
      Write-Host("Request: Failed to send a message through client output pipe...");
      return(2);
     else 
      # We poll the incoming stack for messages
      if ([ClientPipes]::ReadServer($InputPipe) -ne 0) 
        Write-Host("Request: Failed to set a callback...");
        return(2);
      
      if ([ClientPipes]::GetLastMessage($Response, $ParDelay) -eq 0) 
        return(0);
      
      return(1);
    
  

#
# Main
#
[ClientPipes]::ReadStack = new-object System.Collections.Queue;
if (![ClientPipes]::ReadStack) 
  Write-Host("Main: Can't get a stack...");
  exit(1);

Try 
  Write-Host("Main: Setting up client");
  # We send to the server "Hello" and we expect to get a reply in less than 5 seconds
  Write-Host("Main: Sending hello");
  $LastMsg=""
  $status = [ClientPipes]::Request([ref]$npipeClientInput,[ref]$npipeClientOutput,"hello",[ref]$LastMsg, 5);
  if ($status -eq 0) 
    Write-Host("Main: Get a reply : " + $LastMsg);
   else 
    exit(1);
  
  # We send to the server  a request to add "localhsot" to its internal stack and we expect to get a reply in less than 5 seconds
  Write-Host("Main: Server, store localhost please.");
  $LastMsg=""
  $status = [ClientPipes]::Request([ref]$npipeClientInput,[ref]$npipeClientOutput,"add localhost",[ref]$LastMsg, 5);
  if ($status -eq 0) 
    Write-Host("Main: Get a reply : " + $LastMsg);
   else 
    exit(1);
  
  # We send to the server  a request to add "google.com" to its internal stack and we expect to get a reply in less than 5 seconds
  Write-Host("Main: Server, store google.com please.");
  $LastMsg=""
  $status = [ClientPipes]::Request([ref]$npipeClientInput,[ref]$npipeClientOutput,"add google.com",[ref]$LastMsg, 5);
  if ($status -eq 0) 
    Write-Host("Main: Get a reply : " + $LastMsg);
   else 
    exit(1);
  
  # We send to the server  a request to add "***.com" to its internal stack and we expect to get a reply in less than 5 seconds
  Write-Host("Main: Server, store ***.com please.");
  $LastMsg=""
  $status = [ClientPipes]::Request([ref]$npipeClientInput,[ref]$npipeClientOutput,"add ***.com",[ref]$LastMsg, 5);
  if ($status -eq 0) 
    Write-Host("Main: Get a reply : " + $LastMsg);
   else 
    exit(1);
  
  # We send to the server  a request to remove "google.com" from its internal stack and we expect to get a reply in less than 5 seconds
  Write-Host("Main: Server, remove google.com please.");
  $LastMsg=""
  $status = [ClientPipes]::Request([ref]$npipeClientInput,[ref]$npipeClientOutput,"del google.com",[ref]$LastMsg, 5);
  if ($status -eq 0) 
    Write-Host("Main: Get a reply : " + $LastMsg);
   else 
    exit(1);
  
  # We send to the server an output of  its internal stack and we expect to get a reply in less than 5 seconds
  Write-Host("Main: Server, your stack please.");
  $LastMsg=""
  $status = [ClientPipes]::Request([ref]$npipeClientInput,[ref]$npipeClientOutput,"list",[ref]$LastMsg, 5);
  if ($status -eq 0) 
    Write-Host("Main: Get a reply : " + $LastMsg);
   else 
    exit(1);
  
 Catch [System.IO.IOException] 
  Write-Host("Main: I/O failure...");
 Finally 
  If ($npipeClientInput) 
    $npipeClientInput.Dispose();
  
  If ($npipeClientOutput) 
    $npipeClientOutput.Dispose();
  

exit($status)

最后一点,我猜你对管道和套接字的问题来自于常见的事情,例如:

PowerShell 中的“非类”函数将从其标准输出返回所有内容。例如,服务器脚本中的ArrayList.Add 方法在标准输出上输出结果的项目数,然后将回复作为对象而不是String。避免这种情况的一种简单方法是将其输出分配给一个变量。 “读/写管道”函数中的&gt;NUL 等重定向会弄乱您的管道。不要那样做。 像StreamReaderStreamWriter 这样的一些流助手将关闭底层管道供他们使用,因此请注意或不要使用它们。

我肯定忘记了很多东西。

对于演示,服务器脚本的输出:

Server got :hello
Reply sent. Reply to hello, im here, time is 23:23:13
Server got :add localhost
Reply sent. Added, 1 items
Server got :add google.com
Reply sent. Added, 2 items
Server got :add ***.com
Reply sent. Added, 3 items
Server got :del google.com
Reply sent. Removed, 2 items left
Server got :list
Reply sent.
localhost
***.com

客户端脚本的输出:

Main: Setting up client
Main: Sending hello
Request: Sending hello
SendServer: output pipe connected.
ReadServer: Pipe connected.
Callback event
ProcessRead: Callback event
ProcessRead: read Reply to hello, im here, time is 23:23:13

GetLastMessage: Waiting for a reply...
Main: Get a reply : Reply to hello, im here, time is 23:23:13

Main: Server, store localhost please.
Request: Sending add localhost
SendServer: output pipe connected.
ReadServer: Pipe connected.
GetLastMessage: Waiting for a reply...
Callback event
ProcessRead: Callback event
ProcessRead: read Added, 1 items

GetLastMessage: Waiting for a reply...
Main: Get a reply : Added, 1 items

Main: Server, store google.com please.
Request: Sending add google.com
SendServer: output pipe connected.
ReadServer: Pipe connected.
Callback event
ProcessRead: Callback event
ProcessRead: read Added, 2 items

GetLastMessage: Waiting for a reply...
Main: Get a reply : Added, 2 items

Main: Server, store ***.com please.
Request: Sending add ***.com
SendServer: output pipe connected.
ReadServer: Pipe connected.
Callback event
ProcessRead: Callback event
ProcessRead: read Added, 3 items

GetLastMessage: Waiting for a reply...
Main: Get a reply : Added, 3 items

Main: Server, remove google.com please.
Request: Sending del google.com
SendServer: output pipe connected.
ReadServer: Pipe connected.
GetLastMessage: Waiting for a reply...
Callback event
ProcessRead: Callback event
ProcessRead: read Removed, 2 items left

GetLastMessage: Waiting for a reply...
Main: Get a reply : Removed, 2 items left

Main: Server, your stack please.
Request: Sending list
SendServer: output pipe connected.
ReadServer: Pipe connected.
GetLastMessage: Waiting for a reply...
Callback event
ProcessRead: Callback event
ProcessRead: read
localhost
***.com

GetLastMessage: Waiting for a reply...
Main: Get a reply :
localhost
***.com

【讨论】:

以上是关于这在 Powershell 中可行吗?的主要内容,如果未能解决你的问题,请参考以下文章

启动时使用 Powershell 脚本的参数

使用 SqlAlchemy 在 for 循环中更新对象,这在理论上应该有效吗?

我们可以检查 Powershell 脚本所需的 Powershell/WPF/.Net 版本吗?

PowerShell ISE:调试从 power-shell 脚本调用的另一个 power-shell 脚本

powershell 更新power shell中的帮助系统。第二个文件在Windows中显示帮助文件。第三个文件显示来自在线来源的帮助。

即使应用程序未在后台运行,VoIP 推送通知也会自动打开应用程序,这在 iOS 中是不是可行?