header1   header
header
header Register : : Login header
header
connector   connector
menuleft menuright
submenu   submenu
left
Do Unil loop question
Last Post 08 Aug 2010 10:36 PM by Ryan. 3 Replies.
Printer Friendly
  •  
  •  
  •  
  •  
  •  
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages
RyanUser is Offline
New Member
New Member
Posts:16
Avatar

--
06 Aug 2010 06:59 AM
    I have a Do Until loop that does not appear to be functioning as I think it should.  I was hoping some of you with a better understanding of Powershell could look at my code and see if I've done something wrong.  All of the pieces appear to work correctly, other than the timeout portion, if the other two parts of the until piece of the statement are never met, the script will not proceed, even if the timeout is exceeded. -TIA

    function ReadConsoleOutput([diagnostics.process]$process,[string]$command,[int]$timeout) { $strOutput = "" $process.StandardInput.Writeline($command) $strOutput = WaitForPrompt $process $prompt $timeout Return $strOutput } function WaitForPrompt([diagnostics.process]$process,[string]$strPrompt,[int]$intMaxwait) { $strOutput = "" $startTime = Get-Date do { $null = $process.StandardOutput.EndOfStream while ($process.StandardOutput.peek() -ge 0) { $char=[char]$process.StandardOutput.read() Out-Null -nonewline $char #write-host -nonewline $char $strOutput+=$char } } until ($strOutput.contains($strPrompt) -or ((Get-Date) - $startTime).TotalSeconds -gt $intMaxwait -or $process.HasExited -eq $true) Return $strOutput } $strOutput = ReadConsoleOutput $exe $prompt 600
    RyanUser is Offline
    New Member
    New Member
    Posts:16
    Avatar

    --
    06 Aug 2010 10:47 AM
    I have some more information if it will help.

    So it seems its not the timeout that's broken, but the timeout not working is a symptom of a larger problem.

    $char=[char]$process.StandardOutput.read()

    The line above is the issue.  Basically I am reading each character of output looking for a certain string of characters, when that string is found, the script proceeds.

    The problem appears to be if the following bit of code never sees the expected output.
    $strOutput.contains($strPrompt)
    The script continues to read, waiting till the expected output is found. Since output to console has stopped and the expected output is not seen, Powershell appears to stop at the $char=[char]$process.StandardOutput.read() bit of code waiting for more output to be sent to the console. As such the timer never increments any farther and the do until statement never completes.

    Is there a way I can still keep the $char=[char]$process.StandardOutput.read() bit of code, yet somehow get the bigger overall sequence to continue?
    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    06 Aug 2010 02:42 PM

    Try this:

    function Read-ConsoleOutput
    {
        param (
            [System.Diagnostics.Process]$Process,
            [String]$Command,
            [Int32]$Timeout
        )
       
        $Process.StandardInput.WriteLine($Command)

        $output = Wait-Prompt -Process $Process -Prompt $prompt -Timeout $Timeout

        return $output
    }

    function Wait-Prompt
    {
        param (
            [System.Diagnostics.Process]$Process,
            [String]$Prompt,
            [Int32]$Timeout
        )
       
        $output = [String]::Empty
       
        $timer = New-Timer -Seconds $Timeout
        $timer.Start()
       
        do
        {
            while ($Process.StandardOutput.Peek() -ge 0)
            {
                $char = [Char]$Process.StandardOutput.Read()
                $output += $char
            }
        }
        until ($output.Contains($Prompt) -or $timer.HasElapsed -or $Process.HasExited)
       
        $timer.Dispose()
       
        return $output
    }

    function New-Timer
    {
        param (
            [Int32]$Seconds
        )
       
        $timer = New-Object System.Timers.Timer
        $timer.AutoReset = $false
        $timer.Interval = [Double]($Seconds * 1000)
        $timer | Add-Member -MemberType NoteProperty -Name HasElapsed -Value $false
       
        $TimerElapsed = {
            param (
                [Object]$Sender,
                [System.Timers.ElapsedEventHandler]$EventArgs
            )
           
            $Sender.HasElapsed = $true
            $Sender.Stop()
        }
       
        Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier Timer.Elapsed -Action $TimerElapsed
       
        $TimerDisposed = {
            param (
                [Object]$Sender,
                [System.Timers.ElapsedEventHandler]$EventArgs
            )
           
            Unregister-Event -SourceIdentifier Timer.Elapsed
            Unregister-Event -SourceIdentifier Timer.Disposed
        }
       
        Register-ObjectEvent -InputObject $timer -EventName Disposed -SourceIdentifier Timer.Disposed -Action $TimerDisposed
           
        return $timer
    }

    $output = Read-ConsoleOutput -Process $exe -Command $prompt -Timeout 600

    RyanUser is Offline
    New Member
    New Member
    Posts:16
    Avatar

    --
    08 Aug 2010 10:36 PM
    Thank you for your hard work on this, but unfortunately the behavior has not changed.  I believe the cause to be this bit of code:

    do
      { 
      while ($Process.StandardOutput.Peek() -ge 0)
            {
            $char = [Char]$Process.StandardOutput.Read()
            $output += $char
            }
       }
    until ($output.Contains($Prompt) -or $timer.HasElapsed -or $Process.HasExited)

    I also think it specifically has something to do with the line italicized above.  Basically I have an interactive process that I am using Powershell to manipulate.  The waitforprompt function reads the output of this process sent to the console, and when it sees a particular bit of text, it's supposed to continue on to the next bit of the script.  This functions as expected, the problem is, it appears what's happening is if the output to the console never displays what is in $output.Contains($Prompt), and the output also stops, the script halts right at the line italicized above, I'm assuming waiting for more output to try to match up to.

    Since the process has stopped sending output to the console, the line above waits indefinitely for more output.  If I kill the process, or if the output matches what $output.Contains($Prompt) is looking for the script progresses as expected.

    What I've been unable to figure out is a way to force it to process past that line, or maybe another function altogether that will read console output, but that will keep running the script, even if output to the console has ceased.

    You are not authorized to post a reply.


    Active Forums 4.3
    right
    footer   footer
    footer Sponsored by Quest Software • SAPIEN Technologies • Compellent • Microsoft Windows Server 2008 R2 footer
    footer   footer