Scripting PSFTP and PLINK using VBS

Written by James McDonald

June 5, 2013

Sample script of using PuTTYs psftp and plink to:

  1. login to a remote linux host using plink via ssh,
  2. run a find command to return a list of files in a directory tree,
  3. build a psftp batch script to grab and move the remote files
  4. login again using psftp and run the batch script
  5. convert the grabbed files from unix to dos line ends

 

option explicit

dim oshell, ofso, oScriptExec
dim sftp_batch_file, local_dir, remote_base_dir, 
dim UNX, WIN, archive_dir, linux_host, pw, user, ret
dim PLINK, unix_cmd, PSFTP, TODOS, PLINK_EXE, PSFTP_EXE, PUTTY_DIR
dim ar

' set variables
' unix directory separator
UNX = "/"
' windows dir sep
WIN = "\"

' this is the top path I am looking for 
' files in
remote_base_dir = "/u6/app/erp/edilive/out"

' file to store PuTTY psftp commands
sftp_batch_file = "sftp.batch"

local_dir = "d:\EDI\edilive\out"
archive_dir = remote_base_dir & UNX & "transfer-archive/archive"
linux_host = "linux_server"
pw = "mypassword"
user = "myuser"

' this is a windows unix2dos utility
' http://www.thefreecountry.com/tofrodos/
TODOS = "d:\EDI\cmd\todos.exe"

' the fantastic PuTTY command line 
' utilities plink and psftp
PUTTY_DIR = "C:\Program Files (x86)\PuTTY\"
PLINK_EXE = PUTTY_DIR & "plink.exe"
PSFTP_EXE = PUTTY_DIR & "psftp.exe"

' create objects
set oShell = createobject("Wscript.shell")
set ofso = createobject("scripting.filesystemobject")

' find command look for all files under
' skipping certain paths
' find /u6/app/erp/edilive/out \( -path "*transfer-archive" -o -path "*cinv-nys" \) -prune -o -type f -print
unix_cmd = 	"""" & "find /u6/app/erp/edilive/out \( -path " & _
			"""" & "*transfer-archive" & """" & _
		   " -o -path " & """" & "*cinv-nys" & """" _
		   & " \) -prune -o -type f -print" & """"

' 
' runs the the find command which looks for and 
' returns a list of remote files
' the output of plink 
' is captured by oScriptExec.StdOut
PLINK = """" & PLINK_EXE & """" & _
		" -l " & user & " -pw " & _
		"""" & pw & """" & " " & linux_host & " " & unix_cmd

'ret = oShell.run(plink, 0, true)
Set oScriptExec = oShell.Exec(plink)

'pipe the result into a variable
ret = oScriptExec.StdOut.ReadAll
sendErr ret
'serr = oScriptExec.StdErr.ReadAll
'wscript.echo serr

if len(ret) = 0 then
	wscript.echo "No remote files so exiting"
	wscript.quit
end if

' trim the trailing line feed (\n)
' so you don't get an empty
' array element when you use split
ret = left(ret,Len(ret)-1)

' convert the output to an array
ar = split(ret, vbLF)

build_sftp_batch ar

PSFTP = """" & PSFTP_EXE & """" & _
		" -l " & user & " -pw " & pw & " " & _
		linux_host & " -b " & sftp_batch_file

Set oScriptExec = oShell.Exec(PSFTP)
ret = oScriptExec.StdOut.ReadAll

'log the transfer in eventvwr
sendErr ret

' pass all the files we get
' from erp and convert to dos format
convert_todos ar

sub convert_todos(afiles)
	dim x, i, file_name, get_local_dir
	for each x in afiles

		wscript.echo "Remote: " & x
		i = instrRev(x, UNX) - 1
		'wscript.echo i
		file_name = right(x, len(x) - i - 1)
		wscript.echo "File name: " & file_name
		get_local_dir = local_dir & replace(replace(left(x,i), remote_base_dir, ""), UNX, WIN)
		wscript.echo "Local: " & get_local_dir

		if ofso.fileExists(get_local_dir & WIN & file_name) then
			oshell.run TODOS & " " & """" & get_local_dir & WIN & file_name & """"
		end if
	next

end sub

' build the psftp batch file 
' that will run the commands to grab
' the remote files
sub build_sftp_batch(afiles)
	dim x, osftp_batch, i, file_name, get_local_dir
	set osftp_batch = ofso.CreateTextFile(sftp_batch_file, true)

	for each x in afiles

		wscript.echo "Remote: " & x
		i = instrRev(x, UNX) - 1
		'wscript.echo i
		file_name = right(x, len(x) - i - 1)
		wscript.echo "File name: " & file_name
		get_local_dir = local_dir & replace(replace(left(x,i), remote_base_dir, ""), UNX, WIN)
		wscript.echo "Local: " & get_local_dir

		wscript.echo "Remote archive: " & archive_dir

		osftp_batch.writeline "lcd " & get_local_dir
		osftp_batch.writeline "get " & x
		osftp_batch.writeline "ren " & x & " " & _
			archive_dir & UNX & file_name & "-" & date_stamp

	next

	osftp_batch.writeline "quit"

	osftp_batch.close

end sub

' create a YYYY-MM-DD-HHMMSS timestamp
function date_stamp()
	dim tnow, Y, M, D, H, S
	tnow = now()
	Y = YEAR(tnow)
	M = MONTH(tnow)
	if Len(M) = 1 then M = "0" & M end if
	D = DAY(tnow)
	if len(D) = 1 then D = "0" & D end if
	S = Second(tnow)
	if len(S) = 1 then S = "0" & S end if
	H = Hour(tnow)
	if len(H) = 1 then H = "0" & H end if
	M = minute(tnow)
	if len(M) = 1 then M = "0" & M end if

	date_stamp = Y & "-" & M & "-" & D & "-" & H & M & S

end function

sub sendErr(sError)
	wscript.echo sError
	oshell.LogEvent 0, sError
end sub

 

Example of the psftp.batch file

lcd d:\edi\edilive\out\cinv
get /u6/app/erp/edilive/out/cinv/CINV20005.004
ren /u6/app/erp/edilive/out/cinv/CINV20005.004 /u6/app/erp/edilive/out/transfer-archive/archive/CINV20005.004-2013-26-04-162658
quit

 

 

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

You May Also Like…