Welcome to the VanDyke Software Forums

Join the discussion today!


Go Back   VanDyke Software Forums > Scripting

Closed Thread
 
Thread Tools Rate Thread Display Modes
  #1  
Old 02-18-2021, 04:48 PM
jdev's Avatar
jdev jdev is offline
VanDyke Technical Support
 
Join Date: Nov 2003
Location: Albuquerque, NM
Posts: 1,096
Question FAQ: Why doesn't my SecureCRT script work like I need it to?

A frequent question is often asked which comes in various forms generally resembling:
Why doesn't my script work like I need it to?
If you have not yet taken any time to read through the scripting essentials guide, we strongly urge you to read through it and become familiar with the concepts -- at least chapter 4, as it provides specific guidance as to how to ensure that you can keep things "in sync".

The purpose of this FAQ is to highlight common pitfalls that a number of first-time script writers encounter (and even long-time script writers such as myself); following each pitfall highlighted, a corresponding "Best Practice:" will be included.



Pitfall: Sending commands before the remote is ready to receive anything.
One mistake many first-time SecureCRT script writers make is failing to ensure that the remote system is ready to receive commands before actually sending any commands.

The crt.Screen.Synchronous property being set to True is essential for keeping things in sync. Be aware that when crt.Screen.Synchronous is set to True and while the script is running:
  • EVERYTHING received from the remote system will be queued up in a pre-display buffer;
  • NOTHING in this pre-display buffer will be displayed to the screen until a call to WaitFor*() or ReadString() is made or until the script terminates (completes or is canceled).
    • When a WaitFor*() or ReadString() call is made, text within the not-yet-displayed buffer that does *NOT* match what you told SecureCRT to wait-for/read is transferred out of the not-yet-displayed buffer and sent to the screen (where it appears for display).
    • Once text has been displayed to the screen, WaitFor*() and ReadString() cannot act upon that text because it has already been received and displayed. If you need to grab data that is already on the screen, use crt.Screen.Get() or crt.Screen.Get2(). The caveat here is that you have to know the coordinates (row_start, col_start, row_end, col_end) of the text as it appears on the screen. This is why most scripting solutions will involve WaitForString(), WaitForStrings(), or ReadString() to know when the remote system is ready to receive commands/data.
  • If you call Send() before first waiting to make sure the remote system is ready to receive commands, if you then call WaitFor*() or ReadString() some time after your first Send(), it won't be the output of any of your Send() command that will be first in line to be found by your the initial WaitFor*() or ReadString() call. Instead, the data that has been queued up for display since the beginning of your connection will be searched; and if you haven't first made sure that the remote system was ready to receive commands (by waiting for your shell prompt initially -- before sending anything to the remote host) your initial WaitFor*() or ReadString() call is going to return positives on matching data that was already received (and queued for display) before you sent any commands at all.
Best Practice: In any script that performs a connection (or is a logon script itself) always call Screen.WaitForString("<your-shell-prompt-text-here>") near the beginning of your script to a) make sure the host is ready to receive commands, and b) to consume any output that may be buffered (not yet displayed to the screen) so that it doesn't interfere with any WaitFor*() or ReadString() calls following your Send().



Pitfall: Calling Send() multiple times in succession without intervening WaitForString() calls after each Send().
Another pitfall first-time script writers encounter is the mistake of performing two or more Send() operations in succession (where they are "pressing" {Enter} as part of each Send()) but then fail to wait for the shell prompt to appear after each first Send() before the next Send() is performed.

In the case of this mistake, a WaitForString() call made after successive Send() calls (again, where the Send() involves "pressing" {Enter}) will end up finding the shell prompt that appeared as a result of the first Send().

Best Practice: For each Send() where the text you're sending involves carriage return ("\r" in python, or vbcrlf -- same as chr(13) -- for VBScript), make sure you have a matching WaitForString() call.



Pitfall: Waiting for a simplistic single-character shell prompt when the output of a command might include that character.
This pitfall involves the script writer being unaware of the ramifications of the output of commands potentially including the very character they are waiting for as an indication of the command completing.

To be certain, a script writer should be waiting for the full CLI shell prompt (as long as the full shell prompt isn't just a ">" or a "#") because it's less likely that the output of any command would include that as part of its data. If all you are doing is waiting for a "#" and the output of your command has one of those "#" characters, then the subsequent WaitForString("#") call is going to return after finding the "#" in the command's output, rather than the "#" that is part of the CLI shell prompt.

Best practice: Wait for the entire shell prompt to appear so that there aren't any false positives triggered by the output of the command you're running.



Is there another approach to keeping things "in sync"?
Another way to sync things up is to take the approach of:
  1. Send a command (but don't "press" {Enter} yet),
  2. Wait for the text of the command itself to appear,
  3. Then "press" {Enter} to actually run the command,
  4. Now you can Wait...() for the shell prompt, knowing that the shell prompt (if not part of the command's output itself) will signal the command's completion.
For example:
Code:
strShellPrompt = "MyHost'sShellPromptText# "

' 1. Send the command (but don't "press" {Enter}!):
strCommand = "ls -alR /"
crt.Screen.Send strCommand

' 2. Wait for the text of the command to appear:
crt.Screen.WaitForString strCommand

' 3. Now "press" {Enter} to run the command
crt.Screen.Send vbcr 'same as chr(13), but easier to type

' 4. Now wait for the shell prompt to appear:
crt.Screen.WaitForString strShellPrompt
__________________
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; 02-26-2021 at 11:00 AM.
Closed Thread

Tags
faq , how-to , readstring , scripting , send , synchronous , waitforstring


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -6. The time now is 03:33 PM.