Powershell inconsistencies when run from Java program - java

I'm working on a Java macro that runs within another program as part of a computational fluid dynamics package. One thing that annoys me about this package is that the monitor going on standby seems to pause the simulations. But seeing as I have access to these macros I thought that I would add a section to change my power settings to keep the monitor awake.
I'm rather new to Java and so I found the easiest way of doing this would be to call PowerScript to do the actual settings changes. So far, I'm able to read the current state of the settings using the following (hidden for readability since this part works).
String command;
command = "powershell.exe $p = Get-CimInstance -Name root\\cimv2\\power -Class win32_PowerPlan -Filter \"IsActive=\'True\'\"; $p.ElementName";
Process powerShellProcess = Runtime.getRuntime().exec(command);
powerShellProcess.getOutputStream().close();
String line;
BufferedReader stdout = new BufferedReader(new InputStreamReader(
powerShellProcess.getInputStream()));
line = stdout.readLine();
System.out.println("The current power mode is: "+line);
stdout.close();
The next step would be to set the power settings using something like this:
String powerMode = "Balanced";
command = "powershell.exe $p = Get-CimInstance -Name root\\cimv2\\power -Class win32_PowerPlan -Filter \"ElementName=\'"+powerMode+"\'\"; Invoke-CimMethod -InputObject $p[0] -MethodName Activate";
System.out.println(command);
powerShellProcess = Runtime.getRuntime().exec(command);
powerShellProcess.getOutputStream().close();
new InputStreamReader(powerShellProcess.getInputStream());
The command prints properly as
powershell.exe $p = Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan -Filter "ElementName='Balanced'"; Invoke-CimMethod -InputObject $p[0] -MethodName Activate
When running that command (minus the "powershell.exe", of course) in PowerShell works perfectly, but when calling it from Java results in the -Filter "ElementName='Balanced'" returning null.
Can anyone tell me why the filter argument is not being passed properly? It works fine when filtering by "IsActive" as shown in the first part but not when filtering by "ElementName". Could it have something to do with the escape sequence nightmare around the element name?

Powershell is very finicky on its handling of quotes on the command line. The easy solution is to send in the query as
-Filter 'ElementName=\"Balanced\"'
For more info on this see
https://connect.microsoft.com/PowerShell/feedback/details/376207/executing-commands-which-require-quotes-and-variables-is-practically-impossible

Related

how to pass the user and pwd via the runtime.exec() in java

I'm trying to run a simple command using java 1.8 and OS Solaris 11.
My program runs under a particular user and the command must run under SuperUser
here is the command:
Runtime.getRuntime().exec("su - root -c 'pargs -l 1111'");
if i run the command in shall its work fine and ask for password and wen i enter the password i will get the result.
the problem is wen i run it in java
here is my code
Process proc = Runtime.getRuntime().exec("su - root -c 'pargs -l 1111'");
PrintWriter out = new PrintWriter(new OutputStreamWriter(proc.getOutputStream()));
out.println(password);
out.flush();
int exitCode= proc.waitFor();
System.out.println(exitCode);//exitCode = 1
BufferedReader pArgs= new BufferedReader( new InputStreamReader(proc.getInputStream()));
if((line=pArgs.readLine()) != null)
{
//do something
}
else
{
//something not working = ERROR
}
i think that the line equal to null because something in the set of the password is not correct bat i'm not sure
what i'm doing wrong?
I might suggest a different way around this issue altogether. Instead of trying to run a shell command that dynamically asks for a password, make the command not require a password.
If its just asking for a password because it needs root, you can add a line in the sudoers file under root to say that your program user is allowed to execute that one specific command as if they were root: https://www.linux.com/blog/configuring-linux-sudoers-file.
This would be more secure too as you wouldn't have the password floating around code.
how to pass the user and pwd via the runtime.exec() in java
You can't under Solaris if you want to use su.
Solaris su uses the getpass() function to get the necessary password from the user.
From the Solaris getpass() man page:
Description
The getpass() function opens the process's controlling terminal, writes to that device the null-terminated string prompt, disables echoing, reads a string of characters up to the next newline character or EOF, restores the terminal state and closes the terminal.
...
Errors
The getpass() and getpassphrase() functions may fail if:
...
ENXIO
The process does not have a controlling terminal.
su will either get the password from the controlling terminal, or it will fail.
This is a deliberate design decision to make it almost impossible to perform insecure actions such as automated password entry.
Thank you very much for all the answers. But my solution was a little different.
It was decided to use an external file that could be written and read from both processes.
The whole goal was to do a handshake again in case the process running at the root will fall (watchdog).
So now there is no need to use the command
Runtime.getRuntime().exec("su - root -c 'pargs -l 1111'");
When the root process starts running, it records a time signature into a file.
and if the process of the user (who reads the file every X time) finds that the signature has changed, he will do a handshake again.

switch user in Process Builder

I want to switch user and then launch a command under the new user.
Actually my code is
String[] commandToRun2 = {"su","-","jboss", "./jboss-cli.sh -c :shutdown(restart=true)"};
ProcessBuilder pb = new ProcessBuilder(commandToRun2);
pb.directory(new File("/home/jboss/soft/jboss-as-7.1.1.Final/bin/"));
Process p = pb.start();
but I can't make it work.
According to this SuperUser answer, your call to su doesn't appear to be quite right.
From that question, the su command should have the form
su [username] -c "[command]"
So, try the following instead:
String[] commandToRun2 = {"su", "jboss", "-c", "./jboss-cli.sh -c :shutdown(restart=true)"};
Incidentally, it may be helpful to log any output written to the process's standard output and standard error. If there's an error, you'll then be able to see what the error is, and if the process generates a lot of output, reading the output will prevent output buffers from filling and blocking the process. This answer demonstrates how you can do this.

Get exit value of CMD child process called from java program

In my java program I am trying to run a different program through CMD with its output appearing in a command window in the foreground and then analyze the exit code of the child program (foo) in the main java program. Unfortunately, all I seem to be able to access is the exit code of the CMD window, which is always 0.
The following is a snippet of what I'm doing:
ProcessBuilder pb = new ProcessBuilder();
pb.directory(new File(dir));
pb.command("cmd","/c","start","/wait","foo.exe",arg);
process = pb.start();
exitVal = process.waitFor();
but exitVal is always 0 regardless of how foo exits. How can I get just the exit code of foo?
I'm also pretty new to java so if there's a more elegant way of doing this, I'm open to suggestions.
I found a solution by modifying one of the things I had tried before to account for windows batch being finicky. The solution was to send another command to cmd to tell it to exit with the most recent error code. Earlier I had tried this by appending & exit %errorlevel% to the command but cmd variables are only updated at the end of each command line, not at the end of each command.
To force update, I used %^errorlevel% instead.

echo from csh script not showing up on terminal

I am currently executing a csh shell script from a GUI button. The script originally calls another sql script to select information from a database and output it to a log file in the tmp directory. I now need to CAT that file and display it on the xterm window. I use the java Runtime.exec() method to execute the command and I figured I have two options that I can use
Redirect the std output to show it on the xterm
Read from the log file using the csh script and ouytput to xterm
So I chose option 2 and I cannot even get the csh script to output a simple hello world which means I cannot out put anything to the screen when I run it from netbeans. When I try to run the script directly from the xterm it works . Here is the script code
#!/bin/csh -f
#set MYSQL=${MYSQL_HOME}/mysql
#set PSQL=${PSQL_HOME}/psql
echo "Hello World"
#set REPORT=${CLEADM_HOME}/Scripts/DataValidation/CLEADM_EarthOrientationParametersDataReport.sql
#${REPORT}
#${PSQL} ${CLEDBUSER}<${REPORT}
#Get the number of lines in the report file for scrollbar control
#set lc='wc -l /tmp/results.log'
#echo $lc
I commented everything out just to see if I could even print (echo) the results to the screen and that doesn't work. When I run it from the xterm directly (~/.mysqlconnection.csh) it seems to work and prints out "Hello World". I do not know what is wrong. So i tried to force the terminal to come up by adding this code at the top of my script
/usr/openwin/bin/XTERM \ this opens up the xterm but leaves it frozen for some reason? now i cant access anything on my computer
below is the code i use to exeucte the csh script from a java button. i call this method behond the button
public class RunShellScript {
public static void runShellScript (String unixCommand)
{
try {
Runtime runtime=Runtime.getRuntime();
Process process=runtime.exec(new String [] { "/bin/csh", "-c", unixCommand});
InputStream stderr=process.getErrorStream();
InputStreamReader isr=new InputStreamReader (stderr);
BufferedReader br=new BufferedReader (isr);
String line=null;
System.out.println("<ERROR>");
while((line=br.readLine())!=null)
System.out.println(line);
System.out.println(line);
int exitVal=process.waitFor();
System.out.println("Process exitValue:" + exitVal);
}
catch (Throwable t)
{
t.printStackTrace();
}
somewhere i need to redirect the output to an exterm and i am confused as to how to dop that using the streamreader
EDIT - I'm completely starting over with my answer since I badly misunderstood the requirements.
If you want a new window each time the user presses the button, then opening an xterm from the csh script should work; try this:
/usr/openwin/bin/xterm -e "bash -c 'cat /tmp/results.log; echo press a key to continue; read'" &
If you want one window that stays open forever, but keeps updating with new results each time the user presses the button, that's a little different. I would try spawning the other window from Java. You could either have a separate Java window/frame, or use another xterm. To use another xterm, try running a Process somehow, like this:
new ProcessBuilder("/usr/openwin/bin/xterm","-e","tail -f /tmp/results.log").start();
That will open up the tail -f command on the results.log file, and everything you add to the log file will show up in the xterm.

how to wait for a process to end in java or clojure

How can I be notified when a process I did not start ends and is their a way to recover its exit code and or output? the process doing the watching will be running as root/administrator.
You can check whether a process is currently running from java by calling a shell command that lists all the current processes and parsing the output. Under linux/unix/mac os the command is ps, under windows it is tasklist.
For the ps version you would need to do something like:
ProcessBuilder pb = new ProcessBuilder("ps", "-A");
Process p = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
// Skip first (header) line: " PID TTY TIME CMD"
in.readLine();
// Extract process IDs from lines of output
// e.g. " 146 ? 00:03:45 pdflush"
List<String> runningProcessIds = new ArrayList<String>();
for (String line = in.readLine(); line != null; line = in.readLine()) {
runningProcessIds.add(line.trim().split("\\s+")[0]);
}
I don't know of any way that you could capture the exit code or output.
No (not on Unix/Windows, at least). You would have to be the parent process and spawn it off in order to collect the return code and output.
You can kind of do that. On Unix, you can write a script to continuously grep the list of running processes and notify you when the process you're searching for is no longer found.
This is pseudocode, but you can do something like this:
while ( true ) {
str = ps -Alh | grep "process_name"
if ( str == '' ) {
break
}
wait(5 seconds)
}
raise_alert("Alert!")
Check the man page for ps. You options may be different. Those are the ones I use on Mac OSX10.4.
looks like you could use jna to tie into the "C" way of waiting for a pid to end (in windows, poll OpenProcess( PROCESS_QUERY_INFORMATION ...) to see when it reports the process as dead, see ruby's win32.c

Categories