PowerShell and a bridged gap to Java
by Kristian Kraljic, February 3, 2014
Please find me a reason why I have done this? — No, no… I don’t need any excuse, Windows is a great operating system and the PowerShell is an overdue extention to it *cough, cough, the hurts, ahh I’m dying!* — But seriously, due to the system environment at my workplace, I am mainly working with Microsoft Windows and affiliated programs, such as Microsoft Office (Outlook) and Lync. This does not reflect my personal preference, but adaption is key sometimes.
In fact the Windows PowerShell is really not as bad, as the name might suggest it to be (plus, the name is not claimed, yet). The PowerShell is a quite powerfull framework when it comes to task automation and configuration management in an Windows environment. Due to its scripting capabilities and its full access to COM and WMI it is a major leap compared to its "predecessor", the Windows Command Prompt. The concept of cmdlets and especially the object-oriented pipes are a somewhat modern approach of the "old school" executables and text-based pipes. But — and this is a bold-but — is probably a blessing and a curse at once.
As always if you follow a new approach in programming, interoperability and commutability are two major challenges to face in development. Unsuprisingly as I tried to take advantage of the PowerShells capabilities, I painfully realized: Microsoft hasn’t tackled any of those, or did they? Let the devil take the hindmost! Now you could argue, why should you combine a platform-independent programming language such as Java, with a heavily platform dependent framework as the PowerShell? Simple answer, Java is a very sophisticated programming language, the PowerShell offers a very elegant way of accessing the programs I have to work with. Fusion.
Java is capable of communicating using text- and/or binary pipes, such as they are used in the old Windows Command Line or any Unix shell. A few lines of code are enough to easily utilize those:
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; public class ShellExample { public static void main(String[] args) throws IOException, InterruptedException { //start a cmd / shell-instance (also works with /bin/sh) final Process process = Runtime.getRuntime().exec("cmd"); //handle the data of the input stream (non-blocking) pipe(process.getInputStream(),System.out); //handle the data of the error stream (non-blocking) pipe(process.getErrorStream(),System.err); //pass the commands to the output stream PrintWriter commands = new PrintWriter(process.getOutputStream(),true); commands.println("cd"); commands.println("dir"); commands.close(); //wait for the process to close process.waitFor(); } private static void pipe(final InputStream from,final OutputStream to) { new Thread(new Runnable() { @Override public void run() { int length; byte[] buffer = new byte[128]; try { while((length=from.read(buffer))!=-1) to.write(buffer,0,length); } catch(IOException e) { e.printStackTrace(); } finally { try { from.close(); } catch(IOException e) { /* ... */ } } } }).start(); } }
So what’s it with the Windows PowerShell? Simply using the above code? Well, not in the first place at least.
The default in- and output pipes of the Windows PowerShell do not talk text (…or do they?)! In my thoughts there was no way of pushing Java Objects to the PowerShell’s object-pipes (cause obviously Java Objects ≠ PowerShell Objects). So I got my hands on the Invoke-Expression cmdlet and the mission was set:
- Start an Windows PowerShell instance, invoking a prepared script,
- let the script continiously read a prepared input file and pass everything it reads on to the Invoke-Expression cmdlet,
- fill the file, from Java, handle all exceptions, close the PowerShell and delete all files properly.
This does definitely not sound like a way to go, but what should I say? I’m The man who made a monster… which is threadsafe, does garbage collection and utilizes shutdown hooks. Please take a quick peak at the monster … and delete it right afterwards cause:
After hours of programming and to make a long story short, I found out that simply invoking the above script using the following exec-command:
PowerShell -NoExit -Command -
(notice the trailed dash), instead of just PowerShell
works totally fine. F*ck me.
Postscript: Neither I can blame Microsoft, they have cautiously documented the "-command -
" parameter, which will read the command text from standard input.
Wow.. Brilliant work man.
Although, if we are to use the -Command parameter from java, every command will be unique to itself. That is, in this way, we cannot declare a powershell variable and use it later on.
For the continuity and dynamic insertion of cmdlets or variables, we will probably have to go with the second method that you listed. I’m going to call ‘the monster’ and see if it fits my bill…
Thanks a lot for sharing this..
Hello Uma,
That works for me! :-) Thanks for sharing your feedback!
Regards, Kristian
Thank you for sharing this.
Brilliant work man, keep going :D