Invoking an external process with a different user in java - java

We have a java application running as a windows service. A particular functionality needs to execute a binary but with a different user then which started the application.
Is there any way by which we can invoke an exe with 'Run as a different user' style.
I checked API of ProcessBuilder but didn't found anything related to user. Is there any 3rd party tool to achieve this.

You can use PSExec to execute processes as a different user. The command line looks like:
psexec.exe -u username -p password mybinary.exe
You can then use ProcessBuilder to build the command around this.
Edit: here is an example of how you can do it:
public int startProcess(String username, String password,
String executable, String... args) throws IOException {
final String psexec = "C:\\PsTools\\psexec.exe"; //psexec location
//Build the command line
List<String> command = new LinkedList<String>();
command.add(psexec);
if(username != null) {
command.add("-u");
command.add(username);
command.add("-p");
command.add(password);
}
command.add(executable);
command.addAll(Arrays.asList(args));
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
int returnCode;
try {
returnCode = process.waitFor();
} catch (InterruptedException e) {
returnCode = 1;
}
return returnCode;
}
You can then use it like this:
startProcess("Bob", "Password", "Notepad.exe", "C:\\myfile.txt");

I believe you can use the runas DOS command in a pinch, if you can't find something else. (Type runas in a dos prompt for usage info.)
Edit: Unfortunately, according to a note here this apparently won't work from a service. :/ You might be able to create a small separate wrapper app that you could invoke which would then invoke the binary with runas, though.

Related

How to write a string to a cmd prompt using ProcessBuilder in Java?

I have a batch (.bat) program that asks that user to supply a hostname and password. (Two fields) I am using a separate Java application to gather to automate this task and so I need it to enter multiple hostnames at once into the script. However, I am having a hard time accomplishing this goal using ProcessBuilder.
Please take a look at the below code:
This code I have only redirects the input and output to the java process. However, I would solely like to write to the cmd. Please let me know if there is any way. Thanks
import java.io.IOException;
public class Main {
public static void main(String[] args) throws InterruptedException,
IOException {
ProcessBuilder pb = new ProcessBuilder("cmd" ," /k d: && cd DATA\\Virtualization Scripts\\EMC ESXi Grab && Script_Run");
//inherit IO
pb.inheritIO();
Process process = pb.start();
process.waitFor();
}
}
#Tharriott, as per our discussion, first of all you have to modify a bit your batch script like this. I provide below the code.
#ECHO OFF
set host=%1
set password=%2
echo Host Name : %host%
echo Password : %password%
"D:\UPSDATA\Virtualization Scripts\EMC ESXi Grab\EMC-ESXi-GRAB-1.3.10\emcgrab.exe" -host %host% -vmsupport -user root -password %password% -case 00000000 -legal -customer UPS -party 00000 -contact user -phone NA -email NA
exit
Imagine that the name of the batch script is emc-grab.bat.
Now you have to run the above batch file like this.
:/emc-grab.bat
one example is like this
D:/test/emc-grab.bat abcd.dellemc.com pa$$word99
Now what is next ?
In your java gui program, capture hostname and password, then in the processbuilder class, pass the complete command along with the file name, hostname and password.
I provide below the code snippet.
String hostNameAndPassword = "captured Host Name"+" "+"captured password";
ProcessBuilder pb = new ProcessBuilder("cmd" ,"some path:/emc-grab.bat "+hostNameAndPassword);
Try it, it will solve your problem.

Set focus of any application with Java (OSX)?

How can I set the focus (e.g. cmd+tab) of an arbitrary application (Java or not) from a Java program, on OSX?
Looking for an answer to this question, I came across this question, but it doesn't really help for OSX.
EDIT: one possibiltiy seems to be to use something like Quicksilver, and a Robot to send it keypresses with modifiers. I'd prefer something more portable, though, that requires less setup to make changes after it's compiled....
You should be able to reactivate an already running app using the open command that comes with OS X:
Runtime.exec("open /path/to/Whichever.app");
(Or some equivalent overload of that function.) This will also open an app if it's not running yet.
Chuck's answer tipped me off to osascript, so I decided to give it a shot straight from the command line. Managed to get it working with Runtime.exec(), osascript, and AppleScript.
Java launches an AppleScript and passes it the application name, using osascript from the command line, via Runtime.exec():
try {
List<String> shellCommandList = new ArrayList<String>();
shellCommandList.add("osascript");
shellCommandList.add("activateApplication.scpt");
shellCommandList.add(appName);
String[] shellCommand = (String[])shellCommandList.toArray(new String[0]);
Process p = Runtime.getRuntime().exec(shellCommand);
// if desired, pipe out the script's output
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String cmdOutStr = "";
while ((cmdOutStr = in.readLine()) != null) {
System.out.println(cmdOutStr);
}
// if desired, check the script's exit value
int exitValue = p.waitFor();
if (exitValue != 0) {
// TODO: error dialog
System.err.println("Invalid application name: "+ appName);
}
} catch (Exception e) {
e.printStackTrace();
}
And the AppleScript uses a run handler to capture the incoming argument:
on run (arguments)
set appName to (item 1 of arguments)
tell application appName to activate
return 0
end run
You can use the javax.script API to run AppleScripts. So you can write a script along the lines of "tell application "WhateverApp" to activate", filling in your arbitrary application for WhateverApp, and it should do what you want.

How can I call a shell script from a Java program?

I use ubuntu 10.04 with eclipse. I created a shell script, exam.sh:
#!/bin/bash
echo "Hello World"
with chmod 755 exam.sh
On the command line, I can execute ./exam.sh // ok command showing me Hello World
I want to call this exam.sh with java code, this is my java code:
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();
Process p = null;
String cmd[] = {"/bin/bash","cd","/home/erdi/Desktop", ".","/","exam.sh"};
try {
p = r.exec(cmd);
System.out.println("testing...");//ok
} catch (Exception e) {
e.printStackTrace();
}
}
This doesn't function, where did I make a mistake?
Yes I know i can search by google but I didn't find an answer to my problem. It gives howTos and tutorials about this feature but I didn't find an answer.
Try this instead:
cmd[] = {"/bin/bash", "/home/ercan/Desktop/exam.sh"};
You can just invoke bash on the shell script directly. To run a command string (like cd) you would need to use the -c switch.
If you need the working directory of the script to be your Desktop, you can use another overload of Runtime.exec:
Process proc = Runtime.getRuntime().exec(cmd, new String[0], new File("/home/ercan/Desktop"));
Alternatively, the ProcessBuilder class makes executing processes a bit nicer.

Redirecting Input/Output/Error Streams of a CMD.exe Process Completely with Java

My aim with this project was to have a remote command prompt feel with Java. Using TCP/IP sockets, I was aiming to run a command prompt process on one computer, and virtually transmit all control to the other side. I immediately stumbled over Runtime.getRuntime().exec() and Process objects, etc. I've solved my problem about halfway. With my remote command prompt, I can run a single command, gather the output, and send it back to the other side. The problem is, I can only seem to run one command per command prompt instance. This won't do (with situations where I need to change directory and THEN run a command, etc). I've stripped all socket/networking programming from this situation to show you (and to create an easier testing environment for me).
import java.io.*;
public class testingProgram {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
StringBuilder inputMessage = new StringBuilder();
String resultData;
try {
Process pr = rt.exec("cmd.exe /c net user");
BufferedReader processInput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedReader errorProcessInput = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
PrintWriter processOut = new PrintWriter(pr.getOutputStream());
while( (resultData = processInput.readLine()) != null ) {
inputMessage.append(resultData + "\n");
}
resultData = inputMessage.toString();
System.out.print(resultData);
} catch(IOException e) {
} //catch(InterruptedException e) {
//}
}
}
I have a lot more, but this is where my problem is. I can customize the command "net user" with a simple variable and message from the socketstream, so that's not my problem. My problem is that I need to create an ongoing command prompt instance, retaining all redirections of the input/output. Basically, I would like to be able to send another command AFTER "net user".
I have gathered and redirected the output stream. I want to be able to do something like:
processOut.write("net user");
I want to be able to use this, have the command prompt run the command, and retain the output (whether it be from the errorStream OR the inputStream).
I just need some more direction on how to go about doing this.
You should look into multi threading. What you basically want is a thread which keeps running and maintaining the rt.
Like this:
String commandLine;
while ((commandLine = System.in.readline()) != 'q') {
Process pc = rt.exec(commandLine);
}
For further reference on multithreading:
http://download.oracle.com/javase/tutorial/essential/concurrency/procthread.html
You problem is that your program terminates after one call.
cheers
You're telling the command interpreter to terminate. Remove the /C after cmd.exe.
cmd /?
Starts a new instance of the Windows command interpreter
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
[[/S] [/C | /K] string]
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
...

Problem with starting OpenOffice service (soffice) from Java (command working in commandline, but not from Java)

I want to exceute a simple command which works from the shell but doesn't work from Java.
This is the command I want to execute, which works fine:
soffice -headless "-accept=socket,host=localhost,port=8100;urp;"
This is the code I am excecuting from Java trying to run this command:
String[] commands = new String[] {"soffice","-headless","\"-accept=socket,host=localhost,port=8100;urp;\""};
Process process = Runtime.getRuntime().exec(commands)
int code = process.waitFor();
if(code == 0)
System.out.println("Commands executed successfully");
When I run this program I get "Commands executed successfully".
However the process is not running when the program finishes.
Is it possible that the JVM kills the program after it has run?
Why doesn't this work?
I'm not sure if I'm not mistaken, but as far as I see you're generating the commands but never passing them to the "execute" method... you're executing "".
Try using Runtime.getRuntime().exec(commands) =)
I would like to say how I solved this.
I created a sh script that basically run the command of soffice for me.
Then from Java I just run the script, and it works fine, like this:
public void startSOfficeService() throws InterruptedException, IOException {
//First we need to check if the soffice process is running
String commands = "pgrep soffice";
Process process = Runtime.getRuntime().exec(commands);
//Need to wait for this command to execute
int code = process.waitFor();
//If we get anything back from readLine, then we know the process is running
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
if (in.readLine() == null) {
//Nothing back, then we should execute the process
process = Runtime.getRuntime().exec("/etc/init.d/soffice.sh");
code = process.waitFor();
log.debug("soffice script started");
} else {
log.debug("soffice script is already running");
}
in.close();
}
I also kill the soffice process by calling this method:
public void killSOfficeProcess() throws IOException {
if (System.getProperty("os.name").matches(("(?i).*Linux.*"))) {
Runtime.getRuntime().exec("pkill soffice");
}
}
Note that this only works in Linux.
I believe you aren't handling quoting correctly. The original sh command line includes double quotes to prevent the shell interpreting the semicolons. The shell strips them off before the soffice process sees them.
In your Java code the shell will never see the arguments, so the extra double quotes (escaped with backslashes) are not needed - and they are probably confusing soffice.
Here's the code with the extra quotes stripped out (and a semicolon thrown in)
String[] commands = new String[] {"soffice","-headless","-accept=socket,host=localhost,port=8100;urp;"};
Process process = Runtime.getRuntime().exec(commands);
int code = process.waitFor();
if(code == 0)
System.out.println("Commands executed successfully");
(Disclaimer: I don't know Java, and I haven't tested this!)
"/Applications/OpenOffice.org\ 2.4.app/Contents/MacOS/soffice.bin -headless -nofirststartwizard -accept='socket,host=localhost,port=8100;urp;StartOffice.Service'"
or simply escaping the quotes will work as well. We feed a command like this to an ant script that ultimately ends up in an exec call like you have above. I would also recommend restarting the process every 500 or so conversions because OOO does not properly free memory (depending on what version you are running).

Categories

Resources