tags:

views:

603

answers:

6

Hi I am working in a delphi application. I need to execute a perl script which is in remote machine in delphi application from local machine. I need to do this process automatically that is without manual intereption. Now I will explain the process clearly, at present to run the perl script,I just open the putty window, connect to the remote machine and execute the perl script. The perl script in turn calls an store procedure and updates the table.

Now I want to do above explained process automatically by clicking a button. So when I click a button, it should call a function which connects to the remote machine and then executes the perl script. Am I clear to you??? Please help to solve this. I need this code in delphi as soon as possible.

+2  A: 

Two steps:

  • Use a Delphi module/function that allows you to SSH
  • Run the Perl script.
Alan Haggai Alavi
A: 

You could look into Capistrano - it's designed for precisely this sort of automation. You should just have to:

  1. download and install Ruby for Windows
  2. download and install RubyGems
  3. create a Capistrano recipe to call the Perl script remotely
  4. invoke Capistrano from your Delphi app
Duncan Bayne
A: 

I don't know Perl. But if I understand correctly it is a web scripting language similar to php. I too was faced with a similar situation but with php. So I ended up making a call using Indy within my Delphi app to a php script. I don't know if the same sort of logic could be applied for perl. Here are some snippets of the logic.

var
  IdHTTP: TIdHTTP;
  IdSSLIOHandlerSocket1: TIdSSLIOHandlerSocketOpenSSL;
begin
  try
    IdSSLIOHandlerSocket1 := TIdSSLIOHandlerSocketOpenSSL.create(nil);
    IdHTTP := TIdHTTP.create(nil);
    idhttp.handleredirects := True;
    with IdSSLIOHandlerSocket1 do begin
      SSLOptions.Method := sslvSSLv3;
      SSLOptions.Mode :=  sslmUnassigned;
      SSLOptions.VerifyMode := [];
      SSLOptions.VerifyDepth := 2;
    end;
    with IdHTTP do begin
      IOHandler := IdSSLIOHandlerSocket1;
      ProxyParams.BasicAuthentication := False;
      Request.ContentType := 'text/html';
      request.connection := 'keep-alive';
      Request.Accept := 'text/html, */*';
    end;
    result := idhttp.get('http://www.mysite.com/myscript.php');
  finally
    IdHTTP.free;
    IdSSLIOHandlerSocket1.free;
  end;
end;
M Schenkel
Perl is not a web scripting language: "Perl is a high-level, general-purpose, interpreted, dynamic programming language." (http://en.wikipedia.org/wiki/Perl) - you can write web applications with Perl, but not every Perl script is a web application :)
mjustin
Thanks for all your replies. I will let you know once I complete this automation process. Thanks a lot. If you have some others solutions please share with me.
JVNR
A: 

If the remote machine is running Windows, PsExec could be a solution.

PsExec is a light-weight telnet-replacement that lets you execute processes on other systems

There are similar tools like WinExe which remotely execute programs on a Windows host

mjustin
A: 

Is the remote machine running Windows? If so, you can always call "psexec" from Delphi. Or you can use WMI to remotely execute a process (assuming the remote host is running some version of Windows)

Here is a complete example in Delphi, taken from here. You need the WbemScripting_TLB unit, which you can create by installing the type library %windir%\System32\wbem\wbemdisp.tlb using the "Component|Import Component|Import a Type Library" menu options within Delphi 2007.

unit Unit1;

interface

uses
  Windows,
  Messages,
  SysUtils,
  Variants,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  StdCtrls,
  ComCtrls;

type
  TForm1 = class(TForm)
    btnExecute: TButton;
    edtProgramToExecute: TEdit;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    edtRemoteMachine: TEdit;
    edtUser: TEdit;
    edtPassword: TEdit;
    procedure btnExecuteClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses WbemScripting_TLB;

function remoteExecute(programName: string; machine: string = ''; user: string = '';
  password: string = ''): string;
var
  SWbemLocator1: TSWbemLocator;
  Service: ISWbemServices;
  InParam,
    OutParam, SObject: ISWbemObject;
  Method: ISWbemMethod;
  SProp1
    , SProp2, MyProperty
    : ISWbemProperty;
  s, methodName: string;
  PropValue: OleVariant;
begin
  methodName := 'Create';
  //  CoInitialize(nil);
  SWbemLocator1 := TSWbemLocator.Create(nil);
  if machine = '' then
    machine := '.';
  Service := SWbemLocator1.ConnectServer(machine, 'root\CIMV2', user, password, '', '',
    0, nil);
  Service.Security_.Set_ImpersonationLevel(wbemImpersonationLevelImpersonate);
  SObject := Service.Get('Win32_Process', 0, nil);

  Method := SOBject.Methods_.Item(methodName, 0);
  InParam := Method.InParameters.SpawnInstance_(0);

  MyProperty := InParam.Properties_.Add('CommandLine', wbemCimtypeString, False, 0);
  PropValue := programName;
  MyProperty.Set_Value(PropValue);

  MyProperty := InParam.Properties_.Add('CurrentDirectory', wbemCimtypeString, False, 0);
  PropValue := Null;
  MyProperty.Set_Value(PropValue);

  MyProperty := InParam.Properties_.Add('ProcessStartupInformation', wbemCimtypeObject,
    False, 0);
  PropValue := Null;
  MyProperty.Set_Value(PropValue);

  OutParam := SObject.ExecMethod_(methodName, InParam, 0, nil);
  //  OutParam:= SObject.ExecMethod_(methodName, nil, 0, nil);
  SProp1 := outParam.Properties_.Item('ReturnValue', 0);
  SProp2 := outParam.Properties_.Item('ProcessId', 0);
  case SProp1.Get_Value of
    0: s := 'Successful completion.';
    2: s := 'Access denied.';
    3: s := 'Insufficient privilege.';
    8: s := 'Unknown failure.';
    9: s := 'Path not found.';
    21: s := 'Invalid parameter.';
  else
    s := 'Unknown reply code!';
  end;
  SWbemLocator1.Free;
  service := nil;
  SObject := nil;
  OutParam := nil;
  SProp1 := nil;
  result := s + '(PID=' + inttostr(SProp2.Get_Value) + ')';
  //  CoUninitialize;
end;

procedure TForm1.btnExecuteClick(Sender: TObject);
begin
  statusbar1.simpletext := remoteExecute(edit1.text, edit2.text, edit3.text, edit4.text);
end;

end.

You can also do this in VBScript:

Here's a VBScript snippet that demonstrates how this would work.
' This script provides a function for executing a command on a remote computer
' This uses WMI and requires that you have administrative righs on the remote machine
'

Dim strComputer, strCommandLineToRun

'change the period to an IP Address or computer name
strComputer = "."   'example: strComputer = "192.168.1.105"

'this is the path to the file on the computer whose name/IP address is stored in the strComputer variable
strCommandLineToRun = "c:\windows\system32\calc.exe"


' This calls the function to run the process on a remote computer
RemoteExecute strComputer,"","",strCommandLineToRun


Function RemoteExecute(strServer, strUser, strPassword, CmdLine)
    Const Impersonate = 3

    RemoteExecute = -1

    Set Locator = CreateObject("WbemScripting.SWbemLocator")
    Set Service = Locator.ConnectServer(strServer, "root\cimv2", strUser, strPassword)

    Service.Security_.ImpersonationLevel = Impersonate 
    Set Process = Service.Get("Win32_Process")

    result = Process.Create(CmdLine, , , ProcessId)

    If (result <> 0) Then
        WScript.Echo "Creating Remote Process Failed: " & result
        Wscript.Quit
    End If

    RemoteExecute = ProcessId
End Function
Mick
+1  A: 

In the spirit of automating what you already do manually, you can use the Plink utility that comes with Putty. It accepts various command-line options, including the user name, host, password, and command to run. You can specify most options in a saved Putty session, too. See the Putty documentation for more. You can use CreateProcess to run the command from your program.

var
  cmd: string;
begin
  cmd := 'plink -batch -ssh -pw secret user@host /home/user/command.pl';
  UniqueString(cmd);
  CreateProcess(nil, PChar(cmd), ...);

If the command you need to run has parameters, you might need to quote the whole command. If you have multiple commands to run, you should put them in a file and then use Plink's -m option.

Rob Kennedy
Thanks for your reply. I will implement this in my application and let you know if I face some problems in this.
JVNR