Jump to content

Recommended Posts

Posted (edited)

Hi

I have written "plink_wrapper.au3" UDF to assist utilizing the command line terminal emulation program know as "plink".

For more information about plink and putty see "http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html".

The plink_wrapper.au3 UDF contains a few basic functions:

_Start_plink($_plink_loc,$_plinkserver); is used to start your terminal session

_Plink_close(); is used to close the session

_Init_plink_log($_plink_logfile); used to create a log file of the information sent to the screen

_Expect($match_text); wait's for text to appear on screen before continuing

_Expector($match_text1, $say1, $match_text2, $say2, $match_text3, $say3); performs one of three tasks based on information on screen

_Expectlog($match_text); logs text for an individual Expect command; used when main logging is turned off

_Say($output); Sends text to screen input

_SayPlus($output); Sends text to screen input and a carrage return

_Plink_close_logfile($_plink_logfile_handle); closes the log file

_Collect_stdout($time); collect _stdout stream for designated period of time

_ExpectTimed($match_text,$time); waits for specified time to check for string value in terminal output stream

General Comments

- This code has been in use for a few months and is not very sophisticated.

- When entering your userid and password strings add an extra space at the end.

- Finding a valid string to wait for can be tricky. I suggest using putty to record your sessions to find such strings.

- New Function _Collect_stdout($time) added 7/10/2011

- New Function _ExpectTimed($match_text, $time) added 7/12/2011

#include-Once

; ====================================================================================================================================
; Title....................: plink_wrapper
; AutoIt Version...........: 3.3.6.1
; Language.................: English
; Description..............: UDF Functions to Control "plink.exe" allowing intelligent response to text displayed in terminal sessions
; Author...................: Joel Susser (susserj)
; Last Modified............: 07/12/2011
; Status:..................: In Production 
; Testing Workstation......; WinXP sp3, win7 32bit (It likely works with other versions of Windows but I cannot confirm this right now )
; Tested Version of Autoit.; Autoit 3.3.6.1

; What is plink?
;plink is a command line terminal emulation program similar to putty that allows rudimentary scripting.

;Requirements
; Autoit 3.3.6.X
; putty.exe, plink.exe. You can acquire these programs at "http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html".

; Hints
; If you are using the ssh protocol I suggest you connect to your server first
; with putty before you use plink for the first time so that you will not
; be disrupted by the authentication certificate requests.

; When entering your userid and password variables I suggest that you add an
; additional space at the end of these strings. I'm not sure why but if you don't it will likely
; cut off the last letters of your userid and password.

; Figuring out what screen information to wait for before continuing the data input stream
; can sometimes be difficult. I suggest using the putty logging feature to record the text that appears on each screen.
; I beleive it is advisable to do so in small chunks.

; Also, choose strings to recognize that are unique and at the end of the putty screen capture logging sessions
; for each screen. Avoid terminal escape coding.
; ================================================================================================================================

#comments-start
Changelog:
6-09-2011 changed example script to use equivalent path with spaces
7-09-2011 added function _Collect_stdout and modified example script
7-12-2011 added function _ExpectTimed and modified example script
#comments-end


;#Current List of Functions=======================================================================================================
;_Start_plink($_plink_loc,$_plinkserver)
;_Plink_close()
;_Init_plink_log($_plink_logfile)
;_Expect($match_text)
;_Expector($match_text1, $say1, $match_text2, $say2, $match_text3, $say3)
;_Expectlog($match_text)
;_Say($output)
;_SayPlus($output)
;_Plink_close_logfile($_plink_logfile_handle)
;_Collect_stdout($time)
;_ExpectTimed($match_text, $_plink_timeout)

; ===============================================================================================================================


; #VARIABLES# ====================================================================================================================
global $_plinkhandle="" ; used to handle starting of plink
global $_plinkserver="" ; name of server you wish to connect to
global $_plink_loc ="" ; location of plink.exe executable on workstation
global $_plink_display_messages=false ; display interim messages to screen (default false)
global $_plink_display_message_time=1 ; time in seconds messages are displayed
global $_plink_logging=false ; record plink log file (default false)
global $_plink_logfile="" ; location of plink log file
global $_plink_logfile_handle="" ; plink log file handle
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Plink_close
; Description ...: closes plink.exe process
; Author ........: Joel Susser (susserj)
; Syntax.........: $_Plink_close()
; Parameters ....: none required
; example .......: _Plink_close()
;
; Remarks .......: plink.exe should only be running once

; ===============================================================================================================================
func _Plink_close()
;If there are any stray plink sessions kill them
if ProcessExists("plink.exe") then
ProcessClose("plink.exe")
Else
return false
endif

EndFunc
; ===============================================================================================================================



; #FUNCTION# ====================================================================================================================
; Name...........: _Start_plink
; Description ...: open a new plink.exe terminal session
; Author ........: Joel Susser (susserj)
; Syntax.........: $_plinkhandle=_Start_plink($_plink_loc, $_plinkserver)
; Parameters ....: $_plink_loc is the location of the plink.exe ececutable on you workstation
; Parameters ....: $_plinkserver is the location of the server you wish to access
; Example........: $_plinkhandle = _Start_plink("c:/putty/plink.exe", "testserver.com")
; Return values .: $plinkhandle, pid of cmd processor
; Remarks........; Currently configured to use ssh protocol
; Remarks .......: Needs to be made more robust
; ===============================================================================================================================

;start the plink session
func _Start_plink($_plink_loc,$_plinkserver)

_Plink_close(); close any stray plink sessions before starting

if $_plink_loc = "" then
MsgBox(0, "Error", "Unable to open plink.exe",10)
return false
Exit
endif

if $_plinkserver = "" then
MsgBox(0, "Error", "Unable to open server",10)
Exit
return false
endif

$_plinkhandle = Run(@comspec & " /c" & $_plink_loc & " -ssh " & $_plinkserver,"",@SW_HIDE,7)
return $_plinkhandle
endFunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Init_plink_log
; Description ...: open a new file handle for saving a log file recording your plink terminal session
; Syntax.........: _Init_plink_log($_plink_logfile)
; Parameters ....: $_plink_logfile is the location of the log file
; Example........: _Init_plink_log("c:/putty/plink.log")
; Author ........: Joel Susser (susserj)
; Remarks .......: If the file exists it will be ovewritten (2)
; Remarks........: Initializing the log file does not mean logging gets turned on.
; remarks........; Logging gets turned on with the flag $_plink_logging=true. The default is false
; Remarks........; Sometimes the log files get too long and you just want to log a small section of code see $_Expectlog()
; Remarks........;
; ===============================================================================================================================
;Initialize plink session log file
func _Init_plink_log($_plink_logfile)
$_plink_logfile_handle = FileOpen($_plink_logfile, 2)
; Check if file opened for writing OK
If $_plink_logfile_handle = -1 Then
MsgBox(0, "Error", "Unable to open file.")
Exit
EndIf
return true
endfunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Expect
; Description ...: Pause until expected text is displayed on output stream of terminal
; Syntax.........: _Expect("text string")
; Parameters ....: one parameter containing a text string.
; Example........: _Expect("Password:")
; Author ........: Joel Susser (susserj)
; Remarks .......: If the flag $_plink_logging is set to true then it will record all the data sent to the output screen
; Remarks........: while it is waiting for the required text to appear. If it runs to long and doesn't find the text this
; remarks........; file can get very big so be careful.
; Remarks........; If the flag $plink_display_message is set to true then it will popup a messages showing you that the text is found.
; Remarks........; I usaully leave the $_plink_display_messages flag on but reduce the time display to 1 second. However, during
; Remards........; development I usually bump it up to 5 seconds.
; ===============================================================================================================================

func _Expect($match_text)
local $text
local $found
While 1
$text = StdoutRead($_plinkhandle)
if $_plink_logging Then
filewriteline($_plink_logfile_handle,"**********************NEW SECTION************************")
filewrite($_plink_logfile_handle,$match_text)
filewrite($_plink_logfile_handle,$text)
filewriteline($_plink_logfile_handle,"**********************END SECTION************************")
endif
$found = StringRegExp($text,$match_text)
If $found = 1 Then
If $_plink_display_messages Then MsgBox(4096, $match_text, $text, $_plink_display_message_time)
ExitLoop
endif
sleep(100)
Wend
EndFunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Expector
; Description ...: Depending on the text that is found in the input stream, perform one of three different tasks
; Syntax.........: _Expector($match_text1, $say1, $match_text2, $say2, $match_text3, $say3)
; Parameters ....: If string in $match_text1 is found then sent the text in $say1 input string
; Parameters ....: If string in $match_text2 is found then sent the text in $say2 input string
; Parameters ....: If string in $match_text3 is found then give the user a popup message and exit script
; Author ........: Joel Susser (susserj)
; Remarks .......:
; Example........: _Expector("Press <Space Bar> to continue", " ", "Do you wish to continue", "y" "Error no data found", "Script shutting down")
; Remarks .......:
; Remarks........: I'm not fully satified with this function. It requires exactly 6 parameters. It should be more fexable to handle
; remarks........; a variable number of parameters.
; Remarks........; Also, it should perhaps have some error handling to check that the parameters it receives are correct.
; Remarks........; Right now when I only need only two choices, not three choices I put dummy data in my second pair of data variables
; Remards........;
; ===============================================================================================================================
func _Expector($match_text1, $say1, $match_text2, $say2, $match_text3, $say3)
local $text

While 1
$text = StdoutRead($_plinkhandle)
if $_plink_logging then
filewrite($_plink_logfile_handle,"**********************NEW SECTION************************")
filewrite($_plink_logfile_handle,"Expector")
filewrite($_plink_logfile_handle,$text)
filewrite($_plink_logfile_handle,"**********************END SECTION************************")
endif
If $_plink_display_messages Then MsgBox(4096, $match_text1 & $match_text2, $text, $_plink_display_message_time)
sleep(5000)



If StringRegExp($text,$match_text3) then
MsgBox(4096, "System Error", $say3, 6)
ProcessClose("plink.exe")
FileClose($_plink_logfile)
exit; close program
endif

If StringRegExp($text,$match_text2) then
_Say($say2)
ExitLoop
Endif



If StringRegExp($text,$match_text1) then
_Say($say1)
ExitLoop
Endif
sleep(100)
Wend
EndFunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Expectlog
; Description ...: Similar to _Expect but if forces a logging of the data for a particular search patern in the input stream
; Description ...: Pause until text is displayed on output stream of terminal
; Syntax.........: _Expectlog("text string")
; Parameters ....: one parameter containing a text string.
; Example........: _Epector("Password:")
; Author ........: Joel Susser (susserj)
; Remarks .......:
; Remarks........: As I indicated previously, the log files can get very big.
; remarks........; This function allows targeted logging related to a specific area of your script.
; Remarks........; It is primarily used for debugging. After your script is functional, you will likely convert your _Expectlog
; Remarks........; function calls to _Expect.
; Remards........;
; ===============================================================================================================================
func _Expectlog($match_text)
local $text
local $found
While 1
$text = StdoutRead($_plinkhandle)
filewrite($_plink_logfile_handle,"**********************" & $match_text & "************************" )
filewrite($_plink_logfile_handle,$match_text)
filewrite($_plink_logfile_handle,$text)
$found = StringRegExp($text,$match_text)
If $found = 1 Then
MsgBox(4096, $match_text, $text, 10)
ExitLoop
endif
sleep(100)
Wend
EndFunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Say
; Description ...: Send the following text string to the input stream of the terminal session
; Syntax.........: _Say("text")
; Parameters ....: Function takes on parameter which contains the text to sent to the input stream.
; Example........: _Say("y")
; Author ........: Joel Susser (susserj)
; Remarks .......: Don't try and say to much at once. Wait for the screen to appear with the prompt for information
; Remards........; This say does not perform a carrage return. If you need a carrage return use _SayPlus
; ===============================================================================================================================
; Say Function
func _Say($output)
StdinWrite($_plinkhandle, $output)
endfunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _SayPlus
; Description ...: Send the following text string to the input stream of the terminal session
; Syntax.........: _SayPlus("text")
; Parameters ....: Function takes on parameter which contains the text to sent to the input stream.
; Example........: _SayPlus("y")
; Author ........: Joel Susser (susserj)
; Remarks .......: Don't try and say to much at once. Wait for the screen to appear with the prompt for information
; Remards........; This type of say performs a carrage return. If you don't need a carrage return use _Say()
; ===============================================================================================================================
func _SayPlus($output)
StdinWrite($_plinkhandle, $output & @CR)
endfunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Plink_close_logfile
; Description ...: close the plink logging file
; Syntax.........: _Plink_close_logfile($_plink_logfile_handle_)
; Parameters ....: $_Plink_close_logfile_handle
; Example........: N/A
; Author ........: Joel Susser (susserj)
; Remarks .......:
; Remards........;
; ===============================================================================================================================
;Close log file
func _Plink_close_logfile($_plink_logfile_handle)
FileClose($_plink_logfile_handle)
endfunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Collect_stdout
; Description ...: Collects text sent to output stream of terminal for specified period of time
; Syntax.........: $variable = _Collect_stdout($time)
; Parameters ....: Function takes one parameter which specifies time(milliseconds) to collect the input buffer.
; Returns........: Returns the contents of stdout collected during specified time interval
; Example........: $output_buffer = $_Collect_stdout(500); 500 is half a second
; Author ........: Joel Susser (susserj)
;
; Remarks........; This function was inspired by comments made by (Phil; justhatched) and jp10558
; Remarks .......: There are certain situations which can benefit from the ability to collectively parse the stdout stream.
; Remarks........: The potential problem with this approach is that it can sometimes be difficult to predict how long it takes for certain
; remarks........; screens to output their text due to variables such as server load and internet speed etc.
; Remarks........; That being said, with proper testing the time interval can potentially be evaluated for such situations and
; Remarks........; upon potential failure to succeed, the procedure can be repeated.
; Remarks........; See New Sample Script
;
; ===============================================================================================================================
Func _Collect_stdout($_plink_timeout)

local $text
local $sBuffertext
local $iBegin = TimerInit()
While 1
$text = StdoutRead($_plinkhandle)
$sBuffertext = $sBuffertext & $text
if $_plink_logging Then
filewriteline($_plink_logfile_handle, $text)
endif
If TimerDiff($iBegin) > $_plink_timeout then
ExitLoop
endif
sleep(100)

Wend
return $sBuffertext
EndFunc

; ===============================================================================================================================

; #FUNCTION# ====================================================================================================================
; Name...........: _ExpectTimed
; Description ...: Searches for a string in the stdout stream which was collected for a specified period of time
; Syntax.........: $variable = _Epect_timed("string", $time)
; Parameters ....: Function takes two parameters. First is string to find, second is period of in time(milliseconds) to collect the input buffer
; Returns........: Returns the contents of stdout collected during specified time interval
; Example........: $output_buffer = $_Expect__timed("Login:", 5000); 5 seconds
; Author ........: Joel Susser (susserj)
;
; Remarks........; This function was inspired by comments made by (Phil; justhatched) and jp10558
; Remarks .......: There are certain situations which can benefit from the ability to collectively parse the stdout stream.
; Remarks........: The potential problem with this approach is that it can sometimes be difficult to predict how long it takes for certain
; remarks........; screens to output their text due to variables such as server load and internet speed etc.
; Remarks........; That being said, with proper testing the time interval can potentially be evaluated for such situations and
; Remarks........; upon potential failure to succeed, the procedure can be repeated.
; Remarks........; See New Sample Script
; ===============================================================================================================================
Func _ExpectTimed($match_text, $_plink_timeout)
    local $found
    local $sBuf_text
    $sBuf_text = _Collect_stdout($_plink_timeout)
    $found = StringRegExp($sBuf_text, $match_text)
    If $found Then
        If $_plink_display_messages Then MsgBox(4096, $match_text, $sBuf_text, $_plink_display_message_time)
        return $sBuf_text
    endif
EndFunc

; ===============================================================================================================================




; Sample Script Starts Here=============================================================================================================
;

#cs
#include plink_wrapper.au3
;Initialize Variables------------------------------------------------------------------------------------------------------------
$username="admin " ; It seems necessary to put an extra space after the login name. The last character is being cut off.
$password="admin1 "; It seems necessary to put an extra space after the password. The last characters is being cut off.
$_plink_logging=true ; Turn Logging ON (default is off)
$_plink_display_messages=true ; Turn Screen Messages ON (default is on)
$_plink_display_message_time=5 ; Display message for 5 secs (default 1 sec)
;--------------------------------------------------------------------------------------------------------------------------------

; Initizations-------------------------------------------------------------------------------------------------------------------
$_plinkhandle=_Start_plink("c:\PROGRA~1\1putty\plink.exe","hostname.com"); Initialized plink connection to server
_Init_plink_log("c:\PROGRA~1\putty\plink.log"); Initialize log file. Required even it not being used
;(Special Notes for Windows 7. If you are puttying plink, putty, and plink.log in a subdirectory of "c:\Program Files\" make sure
; you give your user account sufficient rights. Otherwises it may fail to run properly.
; To find the short file name, navigate to directory with cmd console, then type "command". This will show you the short name)
; -------------------------------------------------------------------------------------------------------------------------------


; Terminal Emulation Session Interaction
_Expect("login as:")
_SayPlus($username)
_Expect("Password:")
_SayPlus($password)
_Expect("hostname >")
_SayPlus("ls")
_Expect("hostname >")

;--------Sample Coding to illustrate using _Collect_stdout function-----------------
_SayPlus("vncserver")
$buf_collect = _Collect_stdout(5000); (5 sec)
If StringInStr($buf_collect, "computer:0",1) then
    ;some function
ElseIf StringInStr($buf_collect, "computer:1",1) then
    ; some function
ElseIf StringInStr($buf_collect, "computer:2",1) then
    ; some function
Elseif
...
Else
MsgBox(0,"Error", "Unable to find required string")

Endif
;----------------------------------------------------------------------------------

;--------Sample Coding to illustrate using _ExpectTimed function -----------------
; Terminal Emulation Session Interaction
$buf_collect = _ExpectTimed("login as:", 1000)
if not $buf_collect then
MsgBox(4096, "error", "unable to log into server", $_plink_display_message_time)
exit
Endif


_SayPlus($username)
_ExpectTimed("Password:", 1000)
_SayPlus($password)
_ExpectTimed("hostname >", 1000)
_SayPlus("ls")
_ExpectTimed("hostname >", 1000)


;----------------------------------------------------------------------------------


_SayPlus("exit")

;SHUTDOWN-----------------------------------------------------------------------------------------------------------------------
_Plink_close(); shutdown plink session
_Plink_close_logfile($_plink_logfile_handle);shutdown log file
; ------------------------------------------------------------------------------------------------------------------------------

#ce

If you have any questions or comments please let me know.

Thanks

Edited by susserj
  • 4 weeks later...
Posted

This is really nice and just what I have been looking for! Just a tiny suggestion - escaping/quoting the command string for paths with spaces so it doesn't break - took me a little while to figure out why I had a blank with no errors...

Hi

I have written "plink_wrapper.au3" UDF to assist utilizing the command line terminal emulation program know as "plink".

General Comments

- This code has been in use for a few weeks and is not very sophisticated.

- When entering your userid and password strings add an extra space at the end.

- Finding a valid string to wait for can be tricky. I suggest using putty to record your sessions to find such strings.

If you have any questions or comments please let me know.

Thanks

Posted (edited)

Added some tweaks:

2011-06-01 Added escaping of commandline so that if plink is in a dir with spaces it still works,

2011-06-05 Added global timeout const for expect functions so that if the text is not found the calling script

can either handle or set an error state(not hang)

2011-06-05 Added return value for _expect and _expectlog functions so that timeout can be trapped,

and so that the buffertext can be parsed for other information by the calling script. eg the use case is when

the needle text may be found, but the actual text that is required for the calling text may be at different point(s) in the buffer

eg scraping a web page or spreadhseet, walking thru some green screens and populating a third system based on green screen data

2011-06-05 Deleted the expector function, as the ability to parse the buffer from the calling script has more flexibilty

#include-Once
;#include <Constants.au3>
; ====================================================================================================================================
; Title....................: plink_wrapper
; AutoIt Version...........: 3.3.6.1
; Language.................: English
; Description..............: UDF Functions to Control "plink.exe" allowing intelligent response to text displayed in terminal sessions
; Author...................: Joel Susser (susserj)
; Last Modified............: 5/6/2011 (Phil; justhatched)
; Status:..................: Alpha
; Testing Workstation......; WinXP sp3, Vista Business (It likely works with other versions of Windows but I cannot confirm this right now )
; Tested Version of Autoit.; Autoit 3.3.6.1

; What is plink?
    ;plink is a command line terminal emulation program similar to putty that allows rudimentary scripting.

;Requirements
    ; Autoit 3.3.6.X
    ; putty.exe, plink.exe. You can acquire these programs at "http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html".

; Hints
    ; If you are using the ssh protocol I suggest you connect to your server first
    ; with putty before you use plink for the first time so that you will not
    ; be disrupted by the authentication certificate requests.

    ; When entering your userid and password variables I suggest that you add an
    ; additional space at the end of these strings. I'm not sure why but if you don't it will likely
    ; cut off the last letters of your userid and password.

    ; Figuring out what screen information to wait for before continuing the data input stream
    ; can sometimes be difficult. I suggest using the putty logging feature to record the text that appears on each screen.
    ; I believe it is advisable to do so in small chunks.

    ; Also, choose strings to recognize that are unique and at the end of the putty screen capture logging sessions
    ; for each screen. Avoid terminal escape coding.
; ================================================================================================================================

#comments-start
    Changelog:
    4-12-2011 no changes yet
    2011-06-01 Added escaping of commandline so that if plink is in a dir with spaces it still works, 
    2011-06-05 Added global timeout const for expect functions so that if the text is not found the calling script 
                can either handle or set an error state
    2011-06-05 Added return value for _expect and _expectlog functions so that timeout can be trapped, 
                and so that the text can be parsed for other information by the calling script. eg the use case is when
                the text may be found, but the actual text that is required for the calling text may be at a different point in the buffer
                eg scraping a web page or spreadhseet, walking thru some green screens and populating a third system based on green screen data
    2011-06-05  Deleted the expector function, as the ability to parse the buffer from the calling script has more flexibilty
#comments-end


;#Current List of Functions=======================================================================================================
;_Start_plink($_plink_loc,$_plinkserver)
;_Plink_close()
;_Init_plink_log($_plink_logfile)
;_Expect($match_text)
;_Expector($match_text1, $say1, $match_text2, $say2, $match_text3, $say3)
;_Expectlog($match_text)
;_Say($output)
;_SayPlus($output)
;_Plink_close_logfile($_plink_logfile_handle)
; ===============================================================================================================================


; #VARIABLES# ====================================================================================================================
    global $_plinkhandle=""                 ; used to handle starting of plink
    global $_plinkserver=""                 ; name of server you wish to connect to
    global $_plink_loc =""                  ; location of plink.exe executable on workstation
    global $_plink_display_messages=false   ; display interim messages to screen (default false)
    global $_plink_display_message_time=1   ; time in seconds messages are displayed
    global $_plink_logging=false            ; record plink log file (default false)
    global $_plink_logfile=""               ; location of plink log file
    global $_plink_logfile_handle=""        ; plink log file handle
    global Const $_plink_timeout = 5000         ; Global timeout for expect based functions so no hanging....
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Plink_close
; Description ...: closes plink.exe process
; Author ........: Joel Susser (susserj)
; Syntax.........: $_Plink_close()
; Parameters ....: none required
; example .......: _Plink_close()
;
; Remarks .......: plink.exe should only be running once

; ===============================================================================================================================
func _Plink_close()
    ;If there are any stray plink sessions kill them
    if ProcessExists("plink.exe") then
        ProcessClose("plink.exe")
    Else
            return false
    endif

EndFunc
; ===============================================================================================================================



; #FUNCTION# ====================================================================================================================
; Name...........: _Start_plink
; Description ...: open a new plink.exe terminal session
; Syntax.........: $_plinkhandle=_Start_plink($_plink_loc, $_plinkserver)
; Parameters ....: $_plink_loc is the location of the plink.exe ececutable on you workstation
; Parameters ....: $_plinkserver is the location of the server you wish to access
; Example........: $_plinkhandle = _Start_plink("c:/putty/plink.exe", "testserver.com")
;
; Author ........: Joel Susser (susserj)
; Return values .: $plinkhandle, pid of cmd processor
; Remarks........; Currently configured to use ssh protocol
; Remarks .......: Needs to be made more robust
; ===============================================================================================================================

;start the plink session
func _Start_plink($_plink_loc,$_plinkserver)

    _Plink_close(); close any stray plink sessions before starting

    if $_plink_loc = "" then
        MsgBox(0, "Error", "Unable to open plink.exe",10)
        return false
        Exit
    endif

    if $_plinkserver = "" then
        MsgBox(0, "Error", "Unable to open server",10)
        Exit
        return false
    endif

    $_plinkhandle = Run(@comspec & " /c" & $_plink_loc & " -ssh " & $_plinkserver,"",@SW_HIDE, 7) ; $STDIN_CHILD + $STDOUT_CHILD + $STDERR_CHILD)
    return $_plinkhandle
endFunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Init_plink_log
; Description ...: open a new file handle for saving a log file recording your plink terminal session
; Syntax.........: _Init_plink_log($_plink_logfile)
; Parameters ....: $_plink_logfile is the location of the log file
; Example........: _Init_plink_log("c:/putty/plink.log")
; Author ........: Joel Susser (susserj)
; Remarks .......: If the file exists it will be ovewritten (2)
; Remarks........: Initializing the log file does not mean logging gets turned on.
; remarks........; Logging gets turned on with the flag $_plink_logging=true. The default is false
; Remarks........; Sometimes the log files get too long and you just want to log a small section of code see $_Expectlog()
; Remarks........;
; ===============================================================================================================================
;Initialize plink session log file
func _Init_plink_log($_plink_logfile)
    $_plink_logfile_handle = FileOpen($_plink_logfile, 2)
    ; Check if file opened for writing OK
    If $_plink_logfile_handle = -1 Then
        MsgBox(0, "Error", "Unable to open file.")
        Exit
    EndIf
    return true
endfunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Expect
; Description ...: Pause until expected text is displayed on output stream of terminal in less than $iTimeout global const
; Syntax.........: _Expect("text string")
; Parameters ....: one parameter containing a text string.
; Returns........: Stdoutread buffer up to the matched text string, else 0 if timed out
; Example........: _Expect("Password:")
; Author ........: Joel Susser (susserj)
; Remarks .......: If the flag $_plink_logging is set to true then it will record all the data sent to the output screen
; Remarks........: while it is waiting for the required text to appear. If it runs to long and doesn't find the text this
; remarks........; file can get very big so be careful.
; Remarks........; If the flag $plink_display_message is set to true then it will popup a messages showing you that the text is found.
; Remarks........; I usaully leave the $_plink_display_messages flag on but reduce the time display to 1 second. However, during
; Remards........; development I usually bump it up to 5 seconds.
; ===============================================================================================================================

func _Expect($match_text)
    local $text
    local $sBuffertext
    local $found
    local $iBegin = TimerInit()
    While 1
        if TimerDiff($iBegin) > $_plink_timeout then return false
        $text = StdoutRead($_plinkhandle)
        $sBuffertext = $sBuffertext & $text
        if $_plink_logging Then
            filewriteline($_plink_logfile_handle,"**********************NEW SECTION************************")
            filewrite($_plink_logfile_handle, $match_text)
            filewrite($_plink_logfile_handle, $text)
            filewriteline($_plink_logfile_handle,"**********************END SECTION************************")
        endif
        $found = StringRegExp($text,$match_text)
        If $found = 1 Then
            If $_plink_display_messages Then MsgBox(4096, $match_text, $text, $_plink_display_message_time)
            ExitLoop
        endif
    sleep(100)
Wend
    return $sBuffertext
EndFunc
; ===============================================================================================================================

; #FUNCTION# ====================================================================================================================
; Name...........: _Expectlog
; Description ...: Similar to _Expect but if forces a logging of the data for a particular search patern in the input stream
; Description ...: Pause until text is displayed on output stream of terminal
; Syntax.........: _Expectlog("text string")
; Parameters ....: one parameter containing a text string.
; Example........: _Epector("Password:")
; Author ........: Joel Susser (susserj)
; Remarks .......:
; Remarks........: As I indicated previously, the log files can get very big.
; remarks........; This function allows targeted logging related to a specific area of your script.
; Remarks........; It is primarily used for debugging. After your script is functional, you will likely convert your _Expectlog
; Remarks........; function calls to _Expect.
; Remards........;
; ===============================================================================================================================
func _Expectlog($match_text)
    local $text
    local $sBuffertext
    local $iBegin = TimerInit()
    local $found
    While 1
        if TimerDiff($iBegin) > $_plink_timeout then return false
        $text = StdoutRead($_plinkhandle)
        $sBuffertext = $sBuffertext & $text
        filewrite($_plink_logfile_handle,"**********************" &  $match_text &  "************************" )
        filewrite($_plink_logfile_handle,$match_text)
        filewrite($_plink_logfile_handle,$text)
        $found = StringRegExp($text,$match_text)
        If $found = 1 Then
            MsgBox(4096, $match_text, $text, 10)
            ExitLoop
        endif
        sleep(100)
    Wend
    return $sBuffertext
EndFunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Say
; Description ...: Send the following text string to the input stream of the terminal session
; Syntax.........: _Say("text")
; Parameters ....: Function takes on parameter which contains the text to sent to the input stream.
; Example........: _Say("y")
; Author ........: Joel Susser (susserj)
; Remarks .......: Don't try and say to much at once. Wait for the screen to appear with the prompt for information
; Remards........; This say does not perform a carrage return. If you need a carrage return use _SayPlus
; ===============================================================================================================================
; Say Function
func _Say($output)
    StdinWrite($_plinkhandle, $output)
endfunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _SayPlus
; Description ...: Send the following text string to the input stream of the terminal session
; Syntax.........: _SayPlus("text")
; Parameters ....: Function takes on parameter which contains the text to sent to the input stream.
; Example........: _SayPlus("y")
; Author ........: Joel Susser (susserj)
; Remarks .......: Don't try and say to much at once. Wait for the screen to appear with the prompt for information
; Remards........; This type of say performs a carrage return. If you don't need a carrage return use _Say()
; ===============================================================================================================================
func _SayPlus($output)
    If $_plink_display_messages Then MsgBox(4096, "Output", $output, $_plink_display_message_time)
    StdinWrite($_plinkhandle, $output & @CR)
endfunc
; ===============================================================================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Plink_close_logfile
; Description ...: close the plink logging file
; Syntax.........: _Plink_close_logfile($_plink_logfile_handle_)
; Parameters ....: $_Plink_close_logfile_handle
; Example........: N/A
; Author ........: Joel Susser (susserj)
; Remarks .......:
; Remards........;
; ===============================================================================================================================
;Close log file
func _Plink_close_logfile($_plink_logfile_handle)
    FileClose($_plink_logfile_handle)
endfunc
; ===============================================================================================================================

; Sample Script Starts Here=============================================================================================================
;

#cs
;Initialize Variables------------------------------------------------------------------------------------------------------------
$username="admin " ; It seems necessary to put an extra space after the login name. The last character is being cut off.
$password="admin1 "; It seems necessary to put an extra space after the password. The last characters is being cut off.
$_plink_logging=true                        ; Turn Logging ON (default is off)
$_plink_display_messages=true               ; Turn Screen Messages ON (default is on)
$_plink_display_message_time=5              ; Display message for 5 secs (default 1 sec)
;--------------------------------------------------------------------------------------------------------------------------------

; Initizations-------------------------------------------------------------------------------------------------------------------
$_plinkhandle=_Start_plink("c:\putty\plink.exe","hostname.com"); Initialized plink connection to server
_Init_plink_log("c:\putty\plink.log"); Initialize log file. Required even it not being used
; -------------------------------------------------------------------------------------------------------------------------------


; Terminal Emulation Session Interaction
_Expect("login as:")
_SayPlus($username)
_Expect("Password:")
_SayPlus($password)
$buffertext = _Expect("hostname >")
if not $buffertext Then
    ;we have timed out waiting for our string, so failed to login 
    _Plink_close()
    _Plink_close_logfile($_plink_logfile_handle);shutdown log file
    Exit
Else
    ;record something about the machine we have logged into, and optionally apply some logic to what is found
    _SayPlus("ls")
    _Expect("hostname >")
    _SayPlus("exit")
EndIf

;SHUTDOWN-----------------------------------------------------------------------------------------------------------------------
_Plink_close(); shutdown plink session
_Plink_close_logfile($_plink_logfile_handle);shutdown log file
; ------------------------------------------------------------------------------------------------------------------------------
#ce
Edited by justhatched
Posted

Hi justhatched

I like many of your improvements except the removal of my "_expector" function. My particular terminal sessions require, fairly lengthy, and variable amounts of time to process, which occur at certain places in the script and the terminal application throws lots of output to the screen, which could likely overflow the "$sBuffertext" variable.

I liked the rest though.

Cheers

susserj

Posted

Thanks susserj, toyed with adding an optional param to the _expect function for a lossy buffer for the same reason, as some scenarios you only need to know it got there, whereas in other scenarios you may need to process the data(eg a list). Was not sure what could generate so much data without asking for it that it would blow up so left it, and it also meant no calling script would fail with param mismatches.

The reason I dropped the _Expector function was because it looked like a select case from the calling script would allow a better separation into script vs library, as well as more flexibility. eg you can have as many or few inputs to a select case statement. Horses for courses tho so whatever works best for the one doing the work!

This is a nice library for reusing plink functions in all sorts of ways, thanks for putting it up.

Posted

I must say it looks great, very clear and easy.

im looking for this functions a long time.

trying them right now...

:huh2:

Thanks!

  • 4 weeks later...
Posted

So, let's say I want to run a vnc server, specifically running vncserver on the remote Linux computer. I then need to know, from the output, what display it got assigned. I get output like

New 'computer:2 (jmp242)' desktop is computer:2

Starting applications specified in /home/jmp242/.vnc/xstartup
Log file is /home/jmp242/.vnc/computer:2.log

How do I parse for the "2" with this to get what I need?

Posted

So, let's say I want to run a vnc server, specifically running vncserver on the remote Linux computer. I then need to know, from the output, what display it got assigned. I get output like

New 'computer:2 (jmp242)' desktop is computer:2

Starting applications specified in /home/jmp242/.vnc/xstartup
Log file is /home/jmp242/.vnc/computer:2.log

How do I parse for the "2" with this to get what I need?

Hi

I have added a new function to my plink_wrapper.au3 UDF to accommodate this type of situation. The function is called “_Collect_stdout”. Please see my updated coding and sample scripting in my original post.

Thanks

Posted (edited)

Great- I'm much closer. How do I forward a port over SSH so that I can connect to my VNC server?

I tried just running my own plink with command line options:

Run("plink " & $username & "@computer -pw " & $password & ' -L 159'& $vnc & ':computer:59'&$vnc,"",@SW_SHOW,0x8)

I did not add the spaces for the username + password here, so should work, but it just flashes on the screen and looks like it's immediately exiting . . . Any ideas?

Edited by jp10558
  • 1 month later...
Posted

Great- I'm much closer. How do I forward a port over SSH so that I can connect to my VNC server?

I tried just running my own plink with command line options:

Run("plink " & $username & "@computer -pw " & $password & ' -L 159'& $vnc & ':computer:59'&$vnc,"",@SW_SHOW,0x8)

I did not add the spaces for the username + password here, so should work, but it just flashes on the screen and looks like it's immediately exiting . . . Any ideas?

Sorry, this is outside of my area of expertise.
  • 2 months later...
Posted

Hi People,

I am using plink to obtain the data from a log file on server using the tail command .

using the function _start_plink()

It is working fine .

Only issue is since tail is a never ending command , i use _plink_close() to stop the command.

using _ plink_close() also closes my session.

Is there any way to maintain the session , like by sending the (CTRL+C) command to the server (same as we do in putty).

Thanks!!...

  • 2 weeks later...
Posted

HI,

Got the solution myself.

The trick is to not close plink .

But instead use

Stdinwrite($plinkhandle,char(03)) ; sending CTRL +C to the console.

Now to pause the the connection to keep the session alive .(Below routine will keep the session alive)

while true

StdinWrite($_plinkhandle,"date"& @CRLF)

$msg = TrayGetMsg()

Sleep(1000)

Switch $msg

Case $end

ConsoleWrite("Exiting SSH Pause routine at " & _Now() & @CR)

_start_session()

Case $ExitItem

_plink_close()

Exit 0

EndSwitch

WEnd

It is important to flush the stdout before sending any more command so as to flush out the output generated using the date command which is have used as a dummy command to keep the shell busy.

Hope this is useful.

Thanks!!

Posted

hi,

I modify the _Start_plink Function to send the Username and password when using ssh. and maak the option to use other protecols end poorts.

; #FUNCTION# ====================================================================================================================
; Name...........: _Start_plink
; Description ...: open a new plink.exe terminal session
; Author ........: Joel Susser (susserj)
; Syntax.........: $_plinkhandle=_Start_plink($_plink_loc, $_plinkserver)
; Parameters ....: $_plink_loc is the location of the plink.exe ececutable on you workstation
; Parameters ....: $_plinkserver is the location of the server you wish to access
; Parameters ....: $_plink_user
; Parameters ....: $_plink_Password
; Parameters ....: $_plink_Conection_Type
; Parameters ....: $_plink_Port
; Example........: $_plinkhandle = _Start_plink("c:/putty/plink.exe", "testserver.com","my name","my password","ssh","5022")
; Return values .: $plinkhandle, pid of cmd processor

; ===============================================================================================================================
 
;start the plink session
func _Start_plink($_plink_loc,$_plinkserver,$_plink_user = "",$_plink_Password= "",$_plink_Conection_Type= "Telnet",$_plink_Port= "23")
 
    _Plink_close(); close any stray plink sessions before starting
 $Protocol = " -telnet "
    $LogonData = ""
 if not FileExists($_plink_loc)then
        MsgBox(0, "Error", "Unable to located plink.exe",10)
        return false
        Exit
    endif
 
    if $_plinkserver = "" then
        MsgBox(0, "Error", "NO server ip ",10)
        Exit
        return false
    endif
 

    if $_plink_Conection_Type <> "Telnet" then
  if $_plink_Conection_Type = "Rlogin" then
   If $_plink_Port = "23" Then $_plink_Port= "513"
   $Protocol = " -rlogin "
  ElseIf $_plink_Conection_Type = "ssh" then
   If $_plink_Port = "23" Then $_plink_Port= "22"
   $Protocol = " -ssh "
  Elseif $_plink_Conection_Type = "serieal" then
   If $_plink_Port = "23" Then $_plink_Port= "9600"
   $Protocol = " -serial "
  ElseIf $_plink_Conection_Type = "Raw" then
   If $_plink_Port= "" Then
    MsgBox(0, "Error", "NO server Poort ",10)
    Exit
    return false
   endif
   $Protocol = " -raw "
  EndIf
 endif
 
 if not $_plink_user = "" then
  $LogonData = " -l "&$_plink_user
  if not $_plink_Password = "" then $LogonData = $LogonData&" -pw "&$_plink_Password
 EndIf
 

 ;Plink.exe -telnet -p 23 host.name -l User.name -pw Password
 If $Protocol = " -ssh " then ;ssh
  $_plinkhandle = Run(@comspec & " /c" &$_plink_loc & $Protocol & "-P "&$_plink_Port&" "& $_plinkserver& $LogonData,"",@SW_SHOW,$STDIN_CHILD + $STDOUT_CHILD )
 Else; not ssh
  $_plinkhandle = Run(@comspec & " /c" & $_plink_loc & $Protocol & "-P "&$_plink_Port&" "& $_plinkserver,"",@SW_SHOW,$STDIN_CHILD + $STDOUT_CHILD )
 EndIf
 ProcessWait("Plink.exe");Wait to proses exists
 
 return $_plinkhandle
endFunc
; ===============================================================================================================================
  • 1 year later...
Posted

Hi there! I use plink wrapper to connect to SSH, but found some problem.

# include <Plink Wrapper.au3>

$ iPID = _Start_plink (@ ScriptDir & ' plink.exe', '192 .168.0.122 ')

$ a = _Collect_stdout (3000)

MsgBox (0,'', $ a)

_Plink_close ()

With above code, the return value $ a = "login as" at some folder, I can log in with root / alpine, but when I move it to another folder, the return value $ a = '', that means "login as" does not appear and I can not enter a username and password, as well as the implementation of the next command. Please help me. Thank you very much!

  • 2 months later...
Posted (edited)

Sorry to resurrect. I was looking for a way to run a remote unix bash script from a Windows domain login (autoit-)script, and get back the output from the bash script and came to this thread by search. Looks nice!

But, I could not really use this UDF because it "says" things to the plink session and "waits" for a certain string to appear, even to the point of waiting for user/password prompt. Should not be necessary (is actually quite cumbersome) if you just want to run some remote command on some user@host combination and get its output in a string, as long as your remote machine accepts that kind of direct login, which should be pretty normal. plink.exe supports using username/password (or username/keyfile) direct connect session already, as BartW also demonstrated a couple of posts before.

Also, having to manually putty or plink to the server to allow it to push the host ssh key into the registry (to not be disrupted by the auth request - I need a full-auto login script obviously) is not an option for tens to hundreds of very limited and unpredictable office user logins. So for my purposes I proactively write the key of the machine in question to the correct place in the registry (which is in CURRENT_USER-land so should be possible from limited user elevation), so plink.exe will never ask to allow it and just do as it's told. Security note: this is not auto-acceptance of a host-key (which would kinda defeat part of the purpose of ssh), it's pre-configuring the known host key in the registry so plink.exe thinks it was accepted earlier. If that key is wrong/unknown (i.e. fake server in between?), the connect should just gracefully fail. This works well enough (and is secure enough) for our purposes.

I just wanted to give username/password/host/command to a function, run the command, and get the output and then quit the session. I imagine others visiting this thread might want this too. It can be easily done in just a few lines of code (though omitting some error checking). This can be easily modified for more customization possibilities (like BartW did) but for most of my cases that won't be needed. The bottom line is that this function is just one function that runs one command and feeds back all standard output that was received from the plink session. Nothing more, nothing less :)

Hope this helps anyone. Feel free to use this in any way you want.

Func _runSshCommand($plinkUser, $plinkHost, $command, $password = "", $timeoutInMs = 0)

$plinkFile = @UserProfileDir & "\AppData\Local\plink.exe"
FileInstall("c:\AU3_dox\plink.exe", $plinkFile, 1)

$runThis = @ComSpec & " /c " & $plinkFile & " -batch " & $plinkUser & "@" & $plinkHost
If $password <> "" Then $runThis &= " -pw " & $password
$runThis &= " " & $command

$plinkHandle = Run($runThis, "", @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD + $STDERR_CHILD)

$plinkFeedback = ""
$waitForOutputStartTime = TimerInit()
Do
Sleep(10)
$plinkFeedback &= StdoutRead($plinkHandle)
$stdoutReadError = @error
Until $stdoutReadError Or ($timeoutInMs And TimerDiff($waitForOutputStartTime) > $timeoutInMs)

If ProcessExists("plink.exe") Then ProcessClose("plink.exe")

If $stdoutReadError <> 0 Then Return $plinkFeedback

MsgBox(16, "Timeout", "Timeout while waiting for plink command output!")
EndFunc ;==>_runSshCommand

Usage example:

#include <Constants.au3>

Global $unixUser = "user"
Global $unixPassword = "password"
Global $unixHost = "unixhost"
Global $unixHostKey = "0x23,0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"

_writePuttyKnownHostKeyToRegistry($unixHost, $unixHostKey)

$sshCommand = "ls -la /tmp"


$answer = _runSshCommand($unixUser, $unixHost, $sshCommand, $unixPassword)
If $answer <> "" Then
MsgBox(0, "output", $answer)
EndIf

Exit

Func _writePuttyKnownHostKeyToRegistry($host, $hostKey)
RegWrite("HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys", "rsa2@22:" & $host, "REG_SZ", $hostKey)
EndFunc ;==>_writePuttyKnownHostKeyToRegistry

Note: to learn what unixHostKey cache entry to write to the registry on machines that have not connected to the unix box before (thus preventing the interactive 'store this key in cache' prompt from plink), do one manual session from your own machine, allow it to store the key, then look in HKEY_CURRENT_USERSoftwareSimonTathamPuTTYSshHostKeys and just copypaste the whole thing into the RegWrite function call.

Edited by SadBunny

Roses are FF0000, violets are 0000FF... All my base are belong to you.

  • 5 months later...
Posted (edited)

Thank you very much . The "plink_wrapper.au3" UDF help me a lot to hide and automate everything in the background. 

Edited by ali980
Posted

Ok so I'm completely new to plink, I understand putty enough to use it for what I need.

Here is what I am attempting hopefully I can get some help.

I am using putty to test a device on a serial connection. I run commands and it tests the devices buttons, boards, and so on. then gives me a pass/fail.

I want to make a wrapper with this by executing predefined scripts and having my program monitor the output back (the pass/fail results). 

I figured out how to launch putty from a script with the settings I need but can't figure out how to get plink to do the same thing. The putty website isn't descriptive enough to help.

Is this the tool that would do what I need it to do. Any help would be much appreciated!!!

Thanks!

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...