1

Using a PowerShell script I will have to read and write to a console. We write an input and wait for an out that will be captured by $Reader.ReadLine(). But in some cases there wont be any output to get captured for the reader in that case the reader needs to look data from the stream and if there is no data the ReadLine() gets stuck/blocked waiting for the data from the console stream, whereas we need the ReadLine() to just wait for 5 seconds. If there is no data, it needs to get timed out and move on to the next command.

Please let me know whether there is any way to timeout $Reader.ReadLine() in PowerShell?

I see that in Java/C# we can use $Reader.ReadLine(1000) to timeout after 1 second but that doesn't seem to be working on PowerShell.

$tcpConnection = New-Object System.Net.Sockets.TcpClient($Computername, $Port)
$tcpStream = $tcpConnection.GetStream()
$reader = New-Object System.IO.StreamReader($tcpStream)
$writer = New-Object System.IO.StreamWriter($tcpStream)
$writer.AutoFlush = $true

$buffer = New-Object System.Byte[] 1024
$encoding = New-Object System.Text.AsciiEncoding 

while ($tcpStream.DataAvailable) {
    $reader.ReadLine()
}
if ($tcpConnection.Connected) {
    $writer.WriteLine($username)
    $reader.ReadLine()
    $writer.WriteLine($password)
    $reader.ReadLine()

    try {
        # if there is any data it will show here if there is no data then
        # it should get timed out after 5 seconds
        $Reader.ReadLine()
    } catch {
        Write-Host "Login Failed"
    }
}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
user4278054
  • 13
  • 1
  • 4
  • i have not tested it, but this ... `$Test = [System.IO.StreamReader]::Null; $Test.BaseStream.ReadTimeout` seems to indicate that you can set the read timeout by assigning a value to that property. it _appears_ to default to `$Null`. – Lee_Dailey Feb 27 '19 at 09:32
  • @Lee_Dailey Thank you! but i get an error stating, Exception setting "ReadTimeout": "Timeouts are not supported on this stream. – user4278054 Feb 27 '19 at 10:33
  • i'm beyond my depth at this point. [*blush*] that info is all i can find. have you tried replacing the `::Null` with `::New()` - or whatever method is required to associate the reader with a target file? – Lee_Dailey Feb 27 '19 at 10:52
  • @Lee_Dailey the target is not a file. But it's an output from a console (i.e., telnet session from command prompt) – user4278054 Feb 27 '19 at 11:24
  • then i can only say that if you can do it with c#, then the same method should work in powershell. if nothing else, you can simply embed the c# into powershell. – Lee_Dailey Feb 27 '19 at 11:55
  • @Lee_Dailey can you please help me on it? I haven't run a c# code in powershell before. – user4278054 Feb 27 '19 at 13:19
  • from a quick net search, you can wrap the c# in a here-string and then use `Add-Type` to get c# code into powershell. i do NOT know anything about c# ... and have never tried to embed it into PoSh. i have seen a number of folks use it, tho. it's a good way to speed up things that are simply too slow in PoSh - especially when "no compiled code" is policy. [*grin*] – Lee_Dailey Feb 27 '19 at 13:30

1 Answers1

1

I would say that you should read this post C# Stream.Read with timeout

Converting that to your code sample, should end up with something like this.

$tcpConnection = New-Object System.Net.Sockets.TcpClient($Computername, $Port)

#This is one way you could try
$tcpConnection.ReceiveTimeout = 5000;

$tcpStream = $tcpConnection.GetStream()
$reader = New-Object System.IO.StreamReader($tcpStream)

$writer = New-Object System.IO.StreamWriter($tcpStream)
$writer.AutoFlush = $true

$buffer = New-Object System.Byte[] 1024
$encoding = New-Object System.Text.AsciiEncoding 

while ($tcpStream.DataAvailable) {
    $reader.ReadLine()
}
if ($tcpConnection.Connected) {
    $writer.WriteLine($username)
    $reader.ReadLine()
    $writer.WriteLine($password)
    $reader.ReadLine()

    try {
        # if there is any data it will show here if there is no data then
        # it should get timed out after 5 seconds
        $Reader.ReadLine()
    } catch {
        Write-Host "Login Failed"
    }
}

Take it for a spin and let me know if it works or not.

Updated: Updated to reflect the code to only contain the working solution.

Mötz
  • 1,682
  • 11
  • 17