So when I started looking around for something quick and easy to carry out batched updates, I looked at Putty first. Using Putty for scripted tasks wasn't as easy as I thought it would be, the main problem being access to screen feedback so that I can verify that my commands have had the expected effect.
One solution is to turn on logging and use that as a proxy screen. Here's a VBScript class which includes some basic send and "receive" functionality. Error handling is stripped to a bare minimum to keep the size of the script down here, but hopefully it gives a flavour of what is possible.
Option Explicit
'===========================================================================
'Name: Putty class
'Author: Philip Damian-Grint
'Version: 1.0
'Date: 12th Oct 2012
'
'Description:
'
' A starter VB class used to drive Putty sessions typically for Cisco
' devices, allowing sending of commands, and returning screen output
' to allow the possibility of conditional processing.
'
' Putty has a number of logging options; for Cisco vty sessions, only
' printable output is required for line-based output processing, but
' full session output at least is required where escape sequences
' need to be captured for screen positioning. (Not demonstrated here)
'===========================================================================
' Constants
Const EXELOC = """c:\Program Files\Linux Utilities\PuTTY\putty.exe"""
Const LOG_PRINT = "1"
Const LOG_SESSION = "2"
Const MODE_LINE = 0
Const MODE_CHAR = 1
Const REGPUTTY = "HKCU\Software\SimonTatham\PuTTY\Sessions\Default%20Settings\"
Const REGLGFILE = "HKCU\Software\SimonTatham\PuTTY\Sessions\Default%20Settings\LogFileName"
Const REGLGTYPE = "HKCU\Software\SimonTatham\PuTTY\Sessions\Default%20Settings\LogType"
Const STATUS_SUCCESS = 0
Const STATUS_FAILURE = -1
Class Putty
'CLASS PRIVATE VARIABLES
Private p_iLastTideMark
Private p_iMode
Private p_iStatus
Private p_iWait
Private p_oFSO
Private p_oSession
Private p_oWShell
Private p_sEnable
Private p_sHost
Private p_sLogName
Private p_sLogType
Private p_sPasswd
Private p_sTempDir
Private p_sUser
'CLASS CREATOR & DESTRUCTOR
Private Sub Class_Initialize()
Set p_oWShell = WScript.CreateObject( "WScript.Shell" )
Set p_oFSO = WScript.CreateObject( "Scripting.FileSystemObject" )
p_sLogType = LOG_PRINT ' default to printable output
p_iLastTideMark = 0 ' initial tide mark
p_iWait = 5 ' default to 5 seconds wait after each command
p_iMode = MODE_LINE ' default to reading lines
End Sub
Private Sub Class_Terminate()
ResetLog() ' Clear our registry settings
p_oFSO.DeleteFile( p_sLogName ) ' Get rid of the temporary file
Set p_oWShell = Nothing
Set p_oFSO = Nothing
Set p_oSession = Nothing
End Sub
'CLASS PROPERTIES
'enable() is WO
Public Property Let enable( sEnable ) : p_sEnable = sEnable : End Property
'host() is RW
Public Property Let host( sHost ) : p_sHost = sHost : End Property
Public Property Get host() : host = p_sHost : End Property
'logtype() is RW
Public Property Let logtype( sLogType ) : p_sLogType = sLogType : End Property
Public Property Get logtype() : logtype = p_sLogType : End Property
'mode() is RW
Public Property Let mode( iMode ) : p_iMode = iMode : End Property
Public Property Get mode() : mode = p_iMode : End Property
'passwd() is WO
Public Property Let passwd( sPasswd ) : p_sPasswd = sPasswd : End Property
'status() is RO
Public Property Get status() : status = p_iStatus : End Property
'user() is RW
Public Property Let user( sUser ) : p_sUser = sUser : End Property
Public Property Get user() : user = p_sUser : End Property
'wait() is RW
Public Property Let wait( iWait ) : p_iWait = iWait : End Property
Public Property Get wait() : user = p_iWait : End Property
'CLASS PRIVATE FUNCTIONS
Private Function EnableLog ' Switch on Putty logging
EnableLog = -1
p_sLogName = p_oWShell.ExpandEnvironmentStrings( "%Temp%" ) & _
"\" & p_oFSO.GetTempName()
If IsEmpty( p_oWShell.RegWrite( REGLGFILE, p_sLogName,"REG_SZ" ) ) AND _
IsEmpty( p_oWShell.RegWrite( REGLGTYPE, p_sLogType, "REG_DWORD" ) ) Then
EnableLog = 0
End If
End Function
Private Function Quit( sReason ) ' Display message and Exit
WScript.Echo sReason : WScript.Quit
End Function
Private Function ResetLog ' Switch off Putty logging
p_oWShell.RegDelete( REGPUTTY )
End Function
Private Function ReadLog ' Read latest output from Putty log
Dim oFile : Set oFile = p_oFSO.OpenTextFile( p_sLogName )
Dim iCount : iCount = 0
Dim aLogLines(), sLogChars
Do Until oFile.AtEndOfStream ' Find our old tide mark
If iCount < p_iLastTideMark Then
oFile.SkipLine
Else
Redim Preserve aLogLines( iCount - p_iLastTideMark )
aLogLines( iCount - p_iLastTideMark ) = oFile.ReadLine
End If
iCount = iCount + 1
Loop
p_iLastTideMark = iCount ' New tidemark
ReadLog = aLogLines ' Return everything since the last tidemark
oFile.Close
Set oFile = Nothing
End Function
Private Function SendInput( sInput ) ' find Putty's active window and send keystrokes to it
WScript.Sleep 3000 ' Or greater if debugging to give time for window switching
Do
WScript.Sleep 100
Loop until p_oWShell.AppActivate( p_oSession.ProcessID ) ' Find our session window
p_oWShell.SendKeys( sInput & "{ENTER}" ) ' Do the deed
End Function
'CLASS METHODS
Public Function Connect ' Launch Putty
p_iStatus = STATUS_FAILURE ' assume failure
If (NOT IsEmpty( p_sUser ) AND _
NOT IsEmpty( p_sPasswd ) AND _
NOT IsEmpty( p_sUser ) AND _
NOT IsEmpty( p_sHost ) ) Then
If EnableLog <> 0 Then Quit( "Aborting - Can't update registry" )
On Error Resume Next ' graceful error handling
Set p_oSession = p_oWShell.exec( EXELOC & " " & p_sHost & " -l " & _
p_sUser & " -pw " & p_sPasswd )
WScript.Sleep 2000 ' Allow some time to settle down
If ( ( p_oSession Is Nothing ) OR ( p_oSession.Status <> 0 ) ) Then Exit Function
On Error Goto 0
p_iStatus = STATUS_SUCCESS
Connect = ReadLog() ' Pass the initial screen back
End If
End Function
Public Function Send( sChars ) ' Send a command and read the output after waiting iWait seconds
SendInput( sChars )
WScript.Sleep p_iWait * 1000
Send = ReadLog()
End Function
End Class
And to demonstrate the class in use, we take the code above and store it in a file called "classes.vbi", and then pull that file in using an "Include" function to our puttytest.vbs below.
All this demo does is log onto a cisco device, send a command and logout, relaying any putty screen output to our screen:
Tested with Putty version 0.60 under WIndows XP SP3:
Option Explicit
'===========================================================================
'Name: puttytest.vbs
'
'Description:
'
' Wrapper to test our putty class
' Run from command line:
' cscript puttytest.vbs
'===========================================================================
'Utility Functions
Function Include ( sFileVBI ) ' include an external vbs/vbi file
Dim oFSO : Set oFSO = WScript.CreateObject( "Scripting.FileSystemObject" )
Dim oFile : Set oFile = oFSO.OpenTextFile( sFileVBI )
ExecuteGlobal oFile.ReadAll()
oFile.Close : Set oFile = Nothing
Set oFSO = Nothing
End Function
Function GetUserInfo( sPrompt ) ' prompt for input
WScript.StdOut.Write( sPrompt )
GetUserInfo = WScript.StdIn.ReadLine
End Function
Function GetPassword( sPrompt ) ' prompt for hidden input
Dim oPasswd : Set oPasswd = WScript.CreateObject( "ScriptPW.Password" )
WScript.StdOut.Write( sPrompt )
GetPassword = oPasswd.GetPassword()
Set oPasswd = Nothing
End Function
Function WriteLines( aOut ) ' print array of strings
Dim sLine : For Each sLine in aOut
WScript.StdOut.Write( sLine & VbCrLf )
Next
End Function
'========================
' Test our Putty Class
'========================
Include "classes.vbi"
Dim aOutPut
Dim sLineOut
Dim sTextToSend
Dim oSession : Set oSession = New Putty ' Create a new instance of our class
oSession.host = GetUserInfo( "Please type hostname: " ) ' Get some basic info
oSession.user = GetUserInfo( "Please type username: " )
oSession.passwd = GetPassword( "Please type password: " )
aOutPut = oSession.Connect ' and launch our putty session
If oSession.Status = STATUS_SUCCESS Then
WriteLines( aOutPut )
oSession.wait = 3 ' we can set a timer for each command
aOutPut = oSession.Send( "show ver" ) ' show version IOS command
WriteLines( aOutPut )
aOutPut = oSession.Send( " " ) ' usually runs to 2 screens
WriteLines( aOutPut )
aOutPut = oSession.Send( "logout" ) ' close session
WriteLines( aOutPut )
Else
WScript.Echo "Failed to launch Putty"
End If
No comments:
Post a Comment