Executing commands using expect4j - java

I'm using this Code Example, to execute commands in Tcl shell .
If you look at the main function down the page , the way of executing commands is :
SSHClient ssh = new SSHClient("linux_host", "root", "password");
List<String> cmdsToExecute = new ArrayList<String>();
cmdsToExecute.add("ls");
cmdsToExecute.add("pwd");
cmdsToExecute.add("mkdir testdir");
String outputLog = ssh.execute(cmdsToExecute);
In my program I'm doing :
SSHClient ssh = new SSHClient("linux_host", "root", "password");
List<String> cmdsToExecute = new ArrayList<String>();
cmdsToExecute.add("bpsh"); // open Tcl Shell
cmdsToExecute.add("set bps [bps::connect ... ]"); // Tcl shell commands
String outputLog = ssh.execute(cmdsToExecute);
Now the problem is that i can't execute commands from arrayList without exiting the Tcl Shell .
meaning if i run this Code :
SSHClient ssh = new SSHClient("linux_host", "root", "password");
List<String> cmdsToExecute = new ArrayList<String>();
cmdsToExecute.add("bpsh"); // open Tcl Shell
cmdsToExecute.add("set bps [bps::connect ... ]"); // Tcl shell commands
String outputLog = ssh.execute(cmdsToExecute);
cmdsToExecute.clear();
cmdsToExecute.add("set sf [$bps createSuperflow ... ]");
String outputLog = ssh.execute(cmdsToExecute);
i get that after the first execute on the remote machine it exited the first tcl shell and went back to original shell , and in the second execute it tries to run :
"set sf [$bps createSuperflow ... " in the original shell .
i assume because the line :
cmdsToExecute.add("bpsh");
doesn't exist .
The Code of the expect4j that i'm using is in the link above , can someone tell me what i need to modify so that i can execute many commands using ssh.execute() without it exiting the Tcl shell ?

You can try to build a file with the list of commands and source it.
Something like...
cmdsToExecute.add("echo \"\" > tmpcmd.txt");
cmdsToExecute.add("echo \"set bps [bps::connect ... ]\" >> tmpcmd.txt");
cmdsToExecute.add("echo \"set sf [$bps createSuperflow ... ]\" >> tmpcmd.txt");
cmdsToExecute.add("bpsh");
cmdsToExecute.add("source tmpcmd.txt");

Related

Java - execute commands line by line in the same shell

I'm new to java with Talend Open Studio.
I would like to know if it is possible to execute powershell.exe with "Import-Module ActiveDirectory", and then to launch dynamics commands without reloading powershell with "Import-Module ...".
I know this will not work, but my idea could be translated like this :
Runtime.getRuntime().Exec("powershell.exe");
Runtime.getRuntime().Exec("Import-Module ActiveDirectory");
Runtime.getRuntime().Exec("Get-ADUser TestLogin1");
Runtime.getRuntime().Exec("Set-ADUser -Identity TestLogin1 -Company MyCompany1");
Runtime.getRuntime().Exec("Get-ADUser TestLogin2");
Runtime.getRuntime().Exec("Set-ADUser -Identity TestLogin2 -Company MyCompany2");
For this to work, I have to do ...
Runtime.getRuntime().Exec("powershell.exe /c Import-Module ActiveDirectory ; Get-ADUser TestLogin");
Runtime.getRuntime().Exec("powershell.exe /c Import-Module ActiveDirectory ; Set-ADUser -Identity TestLogin1 -Company MyCompany1");
Runtime.getRuntime().Exec("powershell.exe /c Import-Module ActiveDirectory ; Get-ADUser TestLogin_2");
Runtime.getRuntime().Exec("powershell.exe /c Import-Module ActiveDirectory ; Set-ADUser -Identity TestLogin2 -Company MyCompany2");
I don't want to go through a script file because a first update command (Set-ADUser) can have an impact on the next update command.
Thanks.
I found a solution with the jPowerShell library from profesorfalken
https://github.com/profesorfalken/jPowerShell
//Creates PowerShell session (we can execute several commands in the same session)
try (PowerShell powerShell = PowerShell.openSession()) {
//Execute a command in PowerShell session
PowerShellResponse response = powerShell.executeCommand("Import-Module ActiveDirectory");
//Get an ADUser
PowerShellResponse response = powerShell.executeCommand("Get-ADUser TestLogin1");
//Print results ADUser
System.out.println("PS : " + response.getCommandOutput());
//Set an ADUser
PowerShellResponse response = powerShell.executeCommand("Set-ADUser -Identity TestLogin1 -Company MyCompany1");
//Get an ADUser
PowerShellResponse response = powerShell.executeCommand("Get-ADUser TestLogin2");
//Print results ADUser
System.out.println("PS : " + response.getCommandOutput());
//Set an ADUser
PowerShellResponse response = powerShell.executeCommand("Set-ADUser -Identity TestLogin2 -Company MyCompany2");
} catch(PowerShellNotAvailableException ex) {
//Handle error when PowerShell is not available in the system
//Maybe try in another way?
}

processBuilder not finding the main class

The command that is built is working fine on the command prompt but it not working in eclipse . This is how this looks :
String javaHome = System.getProperty("java.home");
cmds.add(javaHome+"/bin/java");
cmds.add("-cp");
cmds.add(_devInstallConfig.getProperty("CP"));
// CP = ("D:\Perforce\depot\nginst\src13920\nginst-install\repo-bootstrap-classpath-13.9.2.0-170213.1854.jar");
cmds.add("com.oracle.cie.repository.stager.CarbStager");
cmds.add("-repoURL "+repoURL);
cmds.add("-props");
cmds.add(_devInstallConfig.getProperty("PROPERTIES_FILE_LOCATION"));
//PROPERTIES_FILE_LOCATION=("C:\Users\bpurana.ORADEV\Desktop\carb.properties");
cmds.add("-repoBaseDir");
cmds.add(_ngInstallLocation.getParentFile().getAbsolutePath());
//repoBaseDir=("D:\Perforce\depot\nginst\src13920\nginst-install");
cmds.add("-PUBLISH_TYPE=BOTH");
cmds.add("-CARB_OUTPUT_DIR="+temp_file);
cmds.add("-NGINST_VERSION");
cmds.add(_devInstallConfig.getProperty("NGINST_VERSION"));
ProcessBuilder pb = new ProcessBuilder(cmds);
pb.directory(_ngInstallLocation.getParentFile());
Process process = pb.start();
The error that I am seeing is this :
Error: Could not find or load main class com.oracle.cie.repository.stager.CarbStager
Edit : I have updated the code snippet with the actual code ( and sharing sample examples of what each value means)

MySQL database restore code using java is not working and makes application not responding

Here is my code for mysql database restore code .when i tried this code app works without exception but application get hangs and database is not restored ..please help me
String databaseName = "sample"; //database name
String userName = "root"; // MySQL username
String password = ""; // MySQL password
int processComplete; // this variable for verify the process
String[] executeCmd = new String[]{"C:\\wamp\\bin\\mysql\\mysql5.5.24\\bin\\mysql",
databaseName, "-u" + userName, "-p" + password, "-e", " source D:/data.sql"};
System.out.println(executeCmd);
Process runtimeProcess = Runtime.getRuntime().exec(executeCmd);// execute the command
processComplete = runtimeProcess.waitFor();
System.out.println(processComplete);
if (processComplete == 1) { // if return value equal to 1 then failed the process
JOptionPane.showMessageDialog(null, "Restore Failed");
} else if (processComplete == 0) {{// if return value equal to 0 then failed the process
JOptionPane.showMessageDialog(null, "Restore Completed");
}
I suspect that the last parameter is been mishandled
String[] executeCmd = new String[]{
"C:\\wamp\\bin\\mysql\\mysql5.5.24\\bin\\mysql",
databaseName,
"-u" + userName,
"-p" + password,
"-e",
" source D:/data.sql" }
It should probably look more like...
String[] executeCmd = new String[]{
"C:\\wamp\\bin\\mysql\\mysql5.5.24\\bin\\mysql",
databaseName,
"-u" + userName,
"-p" + password,
"-e",
"source",
"D:/data.sql" }
Each element in the array will be a separate argument passed to the command, this allows you the flexibility of passing arguments that have spaces in them without need to first escape them using quotes
You should consider using ProcessBuilder instead of trying to build the Process yourself, apart from allowing you to re-direct the error stream to the input stream, it also allows you to specify the starting context for the process.
You should also be reading the output of the process (via it's InputStream) which would possibly highlight issues and may also allow the process to exit (as some process won't exit until there stdout is read completely)
For example: How do I execute Windows commands in Java?

execute sequense of commands in sshj

I need to execute some sequence of commands at the remote server via ssh, using sshj library.
I do
Session session = ssh.startSession();
Session.Command cmd = session.exec("ls -l");
System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
cmd.join(10, TimeUnit.SECONDS);
Session.Command cmd2 = session.exec("ls -a");
System.out.println(IOUtils.readFully(cmd2.getInputStream()).toString());
and it throws me
net.schmizz.sshj.common.SSHRuntimeException: This session channel is
all used up
But I can't recreate session for every single command, because this example it will show home directory list, but not the /some/dir list.
As odd as it is, session can only be used once. So you have to reset the session every time.
Session session = ssh.startSession();
Session.Command cmd = session.exec("ls -l");
System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
cmd.join(10, TimeUnit.SECONDS);
session = ssh.startSession();
Session.Command cmd2 = session.exec("ls -a");
System.out.println(IOUtils.readFully(cmd2.getInputStream()).toString());
Or if the shell you are connecting to supports delimited commands (and the situation allows it), you can do this (bash example):
session.exec("ls -l; <command 2>; <command 3>");
You can consider using an Expect-like third party library which simplifies working with remote services and capturing output. Those libraries are designed to execute a sequence of commands. Here is a good set of options you can try:
Expect4J
ExpectJ
Expect-for-Java
However, when I was about to solve similar problem I found these libraries are rather old. They also introduce a lot of unwanted dependencies. So I created my own and made it available for others. It is called ExpectIt. The advantages of my library it are stated on the project home page. You can give it a try.
Here is an example of interacting with a public remote SSH service using sshj:
SSHClient ssh = new SSHClient();
...
ssh.connect("sdf.org");
ssh.authPassword("new", "");
Session session = ssh.startSession();
session.allocateDefaultPTY();
Shell shell = session.startShell();
Expect expect = new ExpectBuilder()
.withOutput(shell.getOutputStream())
.withInputs(shell.getInputStream(), shell.getErrorStream())
.build();
try {
expect.expect(contains("[RETURN]"));
expect.sendLine();
String ipAddress = expect.expect(regexp("Trying (.*)\\.\\.\\.")).group(1);
System.out.println("Captured IP: " + ipAddress);
expect.expect(contains("login:"));
expect.sendLine("new");
expect.expect(contains("(Y/N)"));
expect.send("N");
expect.expect(regexp(": $"));
expect.send("\b");
expect.expect(regexp("\\(y\\/n\\)"));
expect.sendLine("y");
expect.expect(contains("Would you like to sign the guestbook?"));
expect.send("n");
expect.expect(contains("[RETURN]"));
expect.sendLine();
} finally {
session.close();
ssh.close();
expect.close();
}
Here is the link to the complete workable example.
This question is old but just to clarify, quoting from the wiki https://github.com/hierynomus/sshj/wiki
Session objects are not reusable, so you can only have one command/shell/subsystem via exec(), startShell() or startSubsystem() respectively. But you can start multiple sessions over a single connection.
In our case we have made put it in a function
public String runCmd(SSHClient sshClient, String command) throws IOException {
String response = "";
try (Session session = sshClient.startSession()) {
final Command cmd = session.exec(command);
response = (IOUtils.readFully(cmd.getInputStream()).toString());
cmd.join(5, TimeUnit.SECONDS);
// System.out.println("\n** exit status: " + cmd.getExitStatus());
}
return response;
}

Scala - Fails to execute a process through terminal in a particular scenario

I'm using graphviz to generate graphs based on the messages passed in a scala program.
To invoke the graphviz application from inside the scala program, I'm using the exec() method (similar to Java). It successfully executed the command and created the graph when I used the below code snippet:
var cmd: String = "dot -Tpng Graph.dot -o Graph.png"
var run: Runtime = Runtime.getRuntime() ;
var pr: Process = run.exec(cmd) ;
However It fails to execute after changing the path of the input and output files (I just included a directory inside which the input file and output file resides as shown below)
def main(args: Array[String]): Unit = {
var DirectoryName: String = "Logs"
var GraphFileName: String = DirectoryName + File.separator + "Graph.dot"
val GraphFileObj: File = new File(GraphFileName)
// var cmd: String = "dot -Tpng Graph.dot -o Graph.png"
var cmd: String = "dot -Tpng \"" + GraphFileObj.getAbsolutePath + "\" -o \"" + DirectoryName + File.separator + "Graph.png\"" ;
println(cmd)
var run: Runtime = Runtime.getRuntime() ;
var pr: Process = run.exec(cmd) ;
}
The same command when executed through terminal gives proper output. Can you please help me to find what I'm missing?
exec is not a shell...e.g. quoting won't work as you expect, and thus your path (which may contain spaces, etc) will not be processed as you expect. The command will be broken apart using StringTokenizer, and your literal quotes will be...well..literal.
Use the form of exec that takes an array instead, so you can tokenize the command correctly.
val args = Array[String]("dot", "-Tpng", GraphFileObj.getAbsolutePath, ...);
run.exec(args)

Categories