powershelltcpclientcontrol-c

Powershell AcceptTcpClient() cannot be interrupted by Ctrl-C


I am writing a simple TCP/IP server using Powershell. I notice that Ctrl-C cannot interrupt the AcceptTcpClient() call. Ctrl-C works fine after the call though. I have searched around, nobody reported similar problem so far.

The problem can be repeated by the following simple code. I am using Windows 10, latest patch, with the native Powershell terminal, not Powershell ISE.

$listener=new-object System.Net.Sockets.TcpListener([system.net.ipaddress]::any, 4444)
$listener.start()
write-host "listener started at port 4444"
$tcpConnection = $listener.AcceptTcpClient()
write-host "accepted a client"

This is what happens when I run it

ps1> .\test_ctrl_c.ps1
listener started at port 4444
(Ctrl-C doesn't work here)

Solution

  • (As of PowerShell 7.0) Ctrl-C only works while PowerShell code is executing, not during execution of a .NET method.

    Since most .NET method calls execute quickly, the problem doesn't usually surface.

    See this GitHub issue for a discussion and background information.


    As for possible workarounds:

    Here's a simple demonstration:

    # Start the long-running, blocking operation in a background job (child process).
    $jb = Start-Job -ErrorAction Stop {
      # Simulate a long-running, blocking .NET method call.
      [Threading.Thread]::Sleep(5000)
      'Done.'
    }
    
    $completed = $false
    try {
    
      Write-Host -ForegroundColor Yellow "Waiting for background job to finish. Press Ctrl-C to abort."
    
      # Note: The output collected won't be *live* objects, and with complex
      #       objects will be *emulations* of the original objects that have
      #       static copies of their property values and no methods.
      $output = Receive-Job -Wait -Job $jb
    
      $completed = $true
    
    }
    finally { # This block is called even when Ctrl-C has been pressed.
    
      if (-not $completed) { Write-Warning 'Aborting due to Ctrl-C.' }
    
      # Remove the background job.
      #  * If it is still running and we got here due to Ctrl-C, -Force is needed
      #    to forcefully terminate it.
      #  * Otherwise, normal job cleanup is performed.
      Remove-Job -Force $jb
    
      # If we got here due to Ctrl-C, execution stops here.
    }
    
    # Getting here means: Ctrl-C was *not* pressed.
    
    # Show the output received from the job.
    Write-Host -ForegroundColor Yellow "Job output received:"
    $output
    

    no Ctrl-C

    Ctrl-C