Are you aware of some Java APIs/Libraries for remote PowerShell invocation?
From this API I need things like:
- Authentication
- PowerShell Scripts execution
- Getting results of scripts
Are you aware of some Java APIs/Libraries for remote PowerShell invocation?
From this API I need things like:
You can use JPowerShell library: https://github.com/profesorfalken/jPowerShell
PowerShell powerShell = null;
try {
//Creates PowerShell session
PowerShell powerShell = PowerShell.openSession();
//Increase timeout to give enough time to the script to finish
Map<String, String> config = new HashMap<String, String>();
config.put("maxWait", "80000");
//Execute script
PowerShellResponse response = powerShell.configuration(config).executeScript("./myPath/MyScript.ps1");
//Print results if the script
System.out.println("Script output:" + response.getCommandOutput());
} catch(PowerShellNotAvailableException ex) {
//Handle error when PowerShell is not available in the system
//Maybe try in another way?
} finally {
//Always close PowerShell session to free resources.
if (powerShell != null)
powerShell.close();
}
If you want to execute remotely something through Java it is nice thing to consider RMI. I do not know if You would like to keep the login (is it needed to use different users?), but this method keeps working if you change your windows password etc. There are ways to keep it secure too (but in a home environment it is not that necessary). To the shell call I recommend to use is Apache Commons Exec (ExecuteWatchdog) to build a robust solution.
Long story short: You could bypass login with this and keep a somehow portable solution.
use winrm4j: https://github.com/cloudsoft/winrm4j
winrm4j is a project which enables Java applications to execute batch or PowerShell commands on a remote Windows server using WinRM
WinRmClientContext context = WinRmClientContext.newInstance();
WinRmTool tool = WinRmTool.Builder.builder("my.windows.server.com", "Administrator", "pa55w0rd!")
.authenticationScheme(AuthSchemes.NTLM)
.port(5985)
.useHttps(false)
.context(context)
.build();
tool.executePs("echo hi");
context.shutdown();
You could try ProcessBuilder and redirect the output stream, like this:
Compiled with javac 1.8.0_60 and ran with: java version "1.8.0_91"
import java.util.*;
import java.io.*;
public class Test {
public static void main(String ... args) {
try {
ProcessBuilder launcher = new ProcessBuilder();
Map<String, String> environment = launcher.environment();
launcher.redirectErrorStream(true);
launcher.directory(new File("\\\\remote_machine\\Snaps\\"));
launcher.command("powershell.exe", ".\\Script.ps1");
Process p = launcher.start(); // And launch a new process
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String line;
System.out.println("Output :");
while ((line = stdInput.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e){
e.printStackTrace();
}
}
}
My Script.ps1 was a for testing, it was simple file that prints to the output stream:
Write-Host 'Hello World!'
Hello I have not tried this specifically with PowerShell but I have tried it with Batch files and Windows Shell Host. An alternative to using RMI is to use the windows provided remoting capabilities DCOM. This way you will not need to deploy an extra remote service on the windows machine. Instead you can use the DCOM server provided by each windows machine. The windows machine exposes something called Windows Shell Host. This windows shell host can be used to execute scripts remotely. Since almost everything in Windows comes in the form of COM objects my expectation is that Powershell as well comes as a registered COM service that you need to just find out.
In this link you will find a solution to your problem using Windows Shell Host and J-interop as a Java implementation of the DCOM protocol : How to call a remote bat file using jinterop
/ Create a session
JISession session = JISession.createSession(<domain>, <user>, <password>);
session.useSessionSecurity(true);
// Execute command
JIComServer comStub = new JIComServer(JIProgId.valueOf("WScript.Shell"),<IP>, session);
IJIComObject unknown = comStub.createInstance();
final IJIDispatch shell = (IJIDispatch)JIObjectFactory.narrowObject((IJIComObject)unknown.queryInterface(IJIDispatch.I ID));
JIVariant results[] = shell.callMethodA("Exec", new Object[]{new JIString("%comspec% /c asadmin.bat" )});
If you need the output from the batch you can use StdOut to read it.
JIVariant stdOutJIVariant = wbemObjectSet_dispatch.get("StdOut");
IJIDispatch stdOut = (IJIDispatch)JIObjectFactory.narrowObject(stdOutJIVariant.getObjectAsComObject());
// Read all from stdOut
while(!((JIVariant)stdOut.get("AtEndOfStream")).getObjectAsBoolean()){
System.out.println(stdOut.callMethodA("ReadAll").getObjectAsString().getString());
}