View Single Post
  #6  
Old 10-22-2015, 09:54 AM
jdev's Avatar
jdev jdev is offline
VanDyke Technical Support
 
Join Date: Nov 2003
Location: Albuquerque, NM
Posts: 998
It looks like you're up against a situation where the "start" of a session looks different on some machines vs. others.

Since the "start" of one session has a bunch of data that differs in many ways from each other machine (content, size, time it takes to appear, etc.), you'll probably want to introduce a trick known as "Wait until any new text stops appearing on the screen". Here's an example function:

Code:
' -----------------------------------------------------------------------------
Sub WaitForScreenContentsToStopChanging(nMsDataReceiveWindow)
    ' This function relies on new data received being different from the
    ' data that was already received.  It won't work if, as one example, you
    ' have a screenful of 'A's and more 'A's arrive (because one screen
    ' "capture" will look exactly like the previous screen "capture").
    Dim bOrig
    
    ' Store Synch flag for later restoration
    bOrig = crt.Screen.Synchronous
    ' Turn Synch off since speed is of the essence; we'll turn it back on (if
    ' it was already on) at the end of this function
    crt.Screen.Synchronous = False
    
    strLastScreen = crt.Screen.Get(1,1,crt.Screen.Rows,crt.Screen.Columns)
    Do
        crt.Sleep nMsDataReceiveWindow
        
        strNewScreen = crt.Screen.Get(1,1,crt.Screen.Rows, crt.Screen.Columns)
        If strNewScreen = strLastScreen Then Exit Do

        strLastScreen = strNewScreen
    Loop
    
    ' Restore the Synch setting
    crt.Screen.Synchronous = bOrig
End Sub
Note that this function takes as a parameter nMsDataReceiveWindow, which represents the largest number of milliseconds that you ever would expect to legitimately transpire and the contents of the screen would not be updated.

It's usually only useful at the beginning of a script, where you want to know it's "safe" to start sending commands. Here, "safe" is defined as, "SecureCRT hasn't received any new data from the remote system (within the ReceiveWindow defined) that has appeared on the screen... this likely means that the remote is waiting for input now."

Here's an example script that puts this into action:
Code:
' WaitForScreenContentsToStopChanging.vbs
' 
' Example of a "WaitForScreenContentsToStopChanging()" method used as one
' way to determine if there's any new data arriving from the remote within
' a specified window of milliseconds.
'
' The method protrayed in this example will work in situations where lines of
' data coming from the remote are each unique, or the data you're waiting to
' receive is the initial data received in the session and the number of lines
' of data you're waiting to recieve has fewer lines than the number of rows
' on the terminal screen.

nMsDataReceiveWindow = 150
strCommandThatGeneratesOutput = "ls -alR /"

Sub Main()
    Do
        Do
            nMsDataReceiveWindow = _
                InputBox("Enter the max number of milliseconds the script " & _
                    "should wait for data to arrive before timing out and " & _
                    "considering the data ""stopped"".", _
                    "Specify Data Receive Interval (ms)", _
                    nMsDataReceiveWindow)
            If nMsDataReceiveWindow = "" Then Exit Sub
            If Not IsNumeric(nMsDataReceiveWindow) Then
                MsgBox "Please specify a valid number"
            Else
                Exit Do ' inner Do..Loop
            End If
        Loop

        Do
            strCommandThatGeneratesOutput = _
                InputBox("Enter the command you wish to run on the remote.", _
                    "Specify Remote Command", _
                    strCommandThatGeneratesOutput)
            If strCommandThatGeneratesOutput = "" Then Exit Sub
            If MsgBox("Are you sure you want to run this command?" & vbcrlf & _
                vbcrlf & _
                vbtab & _
                strCommandThatGeneratesOutput, vbYesNo) = vbYes Then Exit Do
        Loop

        ' Send the command to the remote, and wait for the command to be echoed
        ' back to us, including the CR that indicates the command has been
        ' received AND is being acted upon.
        crt.Screen.Send strCommandThatGeneratesOutput & vbcr
        crt.Screen.WaitForString strCommandThatGeneratesOutput
        crt.Screen.WaitForString vbcr
        
        nBeginTime = Timer
        WaitForScreenContentsToStopChanging(nMsDataReceiveWindow)
        MsgBox "Took: " & Timer - nBeginTime & _
            " seconds with a data receive window/interval of " & _
            nMsDataReceiveWindow & " milliseconds." & vbcrlf & vbcrlf & _
            "If new text is still arriving in the terminal window, it is " & _
            "a strong indication that your interval is too short."
    Loop
End Sub

' -----------------------------------------------------------------------------
Sub WaitForScreenContentsToStopChanging(nMsDataReceiveWindow)
    ' This function relies on new data received being different from the
    ' data that was already received.  It won't work if, as one example, you
    ' have a screenful of 'A's and more 'A's arrive (because one screen
    ' "capture" will look exactly like the previous screen "capture").
    Dim bOrig
    
    ' Store Synch flag for later restoration
    bOrig = crt.Screen.Synchronous
    ' Turn Synch off since speed is of the essence; we'll turn it back on (if
    ' it was already on) at the end of this function
    crt.Screen.Synchronous = False
    
    strLastScreen = crt.Screen.Get(1,1,crt.Screen.Rows,crt.Screen.Columns)
    Do
        crt.Sleep nMsDataReceiveWindow
        
        strNewScreen = crt.Screen.Get(1,1,crt.Screen.Rows, crt.Screen.Columns)
        If strNewScreen = strLastScreen Then Exit Do

        strLastScreen = strNewScreen
    Loop
    
    ' Restore the Synch setting
    crt.Screen.Synchronous = bOrig
End Sub
It's not a solve-all solution, but it can add reliability to your script without you needing to wait any longer than necessary on each device you're connecting to.

If you add this WaitForScreenContentsToStopChanging() function to your script (probably at the very end), and then add an "Else" clause to be a companion to your Telnet's "If" which calls this function, you can be relatively "sure" that the remote is ready to receive your commands...
Oh. You can also get the text on the current line after you've called this
function, and consider with relative accuracy that the text you get on the current line to the left of the cursor actually represents the shell prompt on your secondary host.

So, in the code you provide, this:
Code:
	objTab.Screen.Send cnxnString & chr(13)
	If protocol = "Telnet" then
		objTab.Screen.WaitForStrings "sername:","ogin:"
		objTab.Screen.Send UID & chr(13)
		objTab.Screen.WaitForString "assword:"
		objTab.Screen.Send Password & chr(13)
	End If
	objTab.Screen.WaitForStrings vPossiblePrompts
...would become this:
Code:
	objTab.Screen.Send cnxnString & chr(13)
	If protocol = "Telnet" then
		objTab.Screen.WaitForStrings "sername:","ogin:"
		objTab.Screen.Send UID & chr(13)
		objTab.Screen.WaitForString "assword:"
		objTab.Screen.Send Password & chr(13)
		WaitForScreenContentsToStopChanging(350)
	Else
		WaitForScreenContentsToStopChanging(350)
	End If
	
	' Get the text to the left of the cursor
	strPrompt = objTab.Screen.Get(_
		objTab.Screen.CurrentRow, _
		1, _
		objTab.Screen.CurrentRow, _
		objTab.Screen.CurrentColumn - 1)

	' Now that I have THE secondary prompt, I can reliably
	' just wait for it after sending each command in sequence.
--Jake
__________________
Jake Devenport
VanDyke Software
Technical Support
YouTube Channel: https://www.youtube.com/vandykesoftware
Email: support@vandyke.com
Web: https://www.vandyke.com/support

Last edited by jdev; 10-23-2015 at 08:34 AM. Reason: Removing unused variables