From 9d62cfd42b4a2dea1601c23f8b866f653abd6815 Mon Sep 17 00:00:00 2001 From: profesorfalken Date: Sat, 3 Sep 2016 15:41:53 +0200 Subject: [PATCH] Create new version 1.6 which includes an specific method to launch PS scripts --- pom.xml | 2 +- .../jpowershell/PowerShell.java | 159 +++++++++++++----- .../PowerShellCommandProcessor.java | 35 +++- .../jpowershell/PowerShellTest.java | 73 ++++++-- 4 files changed, 203 insertions(+), 66 deletions(-) diff --git a/pom.xml b/pom.xml index f4b6c72..e34c5c4 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.profesorfalken jPowerShell - 1.5.2 + 1.6 jar jPowerShell diff --git a/src/main/java/com/profesorfalken/jpowershell/PowerShell.java b/src/main/java/com/profesorfalken/jpowershell/PowerShell.java index 87bc99b..d277613 100644 --- a/src/main/java/com/profesorfalken/jpowershell/PowerShell.java +++ b/src/main/java/com/profesorfalken/jpowershell/PowerShell.java @@ -16,9 +16,16 @@ package com.profesorfalken.jpowershell; import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.util.Date; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -43,7 +50,6 @@ public class PowerShell { //Process to store PowerShell session - private Process p; //Writer to send commands private PrintWriter commandWriter; @@ -51,28 +57,36 @@ public class PowerShell { //Threaded session variables private boolean closed = false; private ExecutorService threadpool; - + //Config values - private int maxThreads = 3; + private int maxThreads = 3; private int waitPause = 10; private long maxWait = 10000; + + //Variables for script mode + private boolean scriptMode = false; + public static final String END_SCRIPT_STRING = "--END-JPOWERSHELL-SCRIPT--"; //Private constructor. private PowerShell() { } - + /** - * Allows to override jPowerShell configuration using a map of key/value
- * Default values are taken from file jpowershell.properties, which can be - * replaced just setting it on project classpath - * + * Allows to override jPowerShell configuration using a map of key/value + *
+ * Default values are taken from file jpowershell.properties, which + * can be replaced just setting it on project classpath + * * The values that can be overridden are: * - * + * * @param config map with the configuration in key/value format * @return instance to chain */ @@ -88,7 +102,7 @@ public PowerShell configuration(Map config) { } //Initializes PowerShell console in which we will enter the commands - private PowerShell initalize() throws PowerShellNotAvailableException { + private PowerShell initalize() throws PowerShellNotAvailableException { ProcessBuilder pb = new ProcessBuilder("powershell.exe", "-NoExit", "-Command", "-"); try { p = pb.start(); @@ -116,7 +130,7 @@ private PowerShell initalize() throws PowerShellNotAvailableException { */ public static PowerShell openSession() throws PowerShellNotAvailableException { PowerShell powerShell = new PowerShell(); - + //Start with default configuration powerShell.configuration(null); @@ -132,10 +146,10 @@ public static PowerShell openSession() throws PowerShellNotAvailableException { * @return PowerShellResponse the information returned by powerShell */ public PowerShellResponse executeCommand(String command) { - Callable commandProcessor = new PowerShellCommandProcessor("standard", - p.getInputStream(), this.maxWait, this.waitPause); - Callable commandProcessorError = new PowerShellCommandProcessor("error", - p.getErrorStream(), this.maxWait, this.waitPause); + Callable commandProcessor = new PowerShellCommandProcessor("standard", + p.getInputStream(), this.maxWait, this.waitPause, this.scriptMode); + Callable commandProcessorError = new PowerShellCommandProcessor("error", + p.getErrorStream(), this.maxWait, this.waitPause, this.scriptMode); String commandOutput = ""; boolean isError = false; @@ -152,10 +166,10 @@ public PowerShellResponse executeCommand(String command) { Thread.sleep(this.waitPause); } if (result.isDone()) { - if (((PowerShellCommandProcessor)commandProcessor).isTimeout()) { + if (((PowerShellCommandProcessor) commandProcessor).isTimeout()) { timeout = true; } else { - commandOutput = result.get(); + commandOutput = result.get(); } } else { isError = true; @@ -173,6 +187,82 @@ public PowerShellResponse executeCommand(String command) { return new PowerShellResponse(isError, commandOutput, timeout); } + + /** + * Execute a single command in PowerShell console and gets result + * + * @param command the command to execute + * @return response with the output of the command + */ + public static PowerShellResponse executeSingleCommand(String command) { + PowerShell session = null; + PowerShellResponse response = null; + try { + session = PowerShell.openSession(); + + response = session.executeCommand(command); + } catch (PowerShellNotAvailableException ex) { + Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "PowerShell not available", ex); + } finally { + if (session != null) { + session.close(); + } + } + return response; + } + + /** + * Executed the provided PowerShell script in PowerShell console and + * gets result. + * + * @param scriptPath the full paht of the script + * @return response with the output of the command + */ + public PowerShellResponse executeScript(String scriptPath) { + BufferedReader reader = null; + BufferedWriter writer = null; + + File tmpFile = null; + try { + File scriptToExecute = new File(scriptPath); + if (!scriptToExecute.exists()) { + return new PowerShellResponse(true, "Wrong script path: " + scriptToExecute, false); + } + tmpFile = File.createTempFile("psscript_" + new Date().getTime(), ".ps1"); + if (tmpFile == null || !tmpFile.exists()) { + return new PowerShellResponse(true, "Cannot create temp script file", false); + } + + reader = new BufferedReader(new FileReader(scriptToExecute)); + writer = new BufferedWriter(new FileWriter(tmpFile)); + String line; + while ((line = reader.readLine()) != null) { + writer.write(line); + writer.newLine(); + } + //Add end script line + writer.write("Write-Host \"" + END_SCRIPT_STRING + "\""); + } catch (FileNotFoundException fnfex) { + Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "Unexpected error when processing PowerShell script", fnfex); + } catch (IOException ioex) { + Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "Unexpected error when processing PowerShell script", ioex); + } finally { + try { + if (reader != null) { + reader.close(); + } + if (writer != null) { + writer.close(); + } + } catch (IOException ex) { + Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "Unexpected error when processing PowerShell script", ex); + } + } + + this.scriptMode = true; + + return executeCommand(tmpFile.getAbsolutePath()); + } /** * Closes all the resources used to maintain the PowerShell context @@ -196,16 +286,16 @@ public String call() throws Exception { p.getErrorStream().close(); } catch (IOException ex) { Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "Unexpected error when when closing streams", ex); - } + } commandWriter.close(); if (this.threadpool != null) { try { - this.threadpool.shutdownNow(); + this.threadpool.shutdownNow(); this.threadpool.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException ex) { Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "Unexpected error when when shutting thread pool", ex); } - + } this.closed = true; } @@ -223,27 +313,4 @@ private void waitUntilClose(Future task) throws InterruptedException { closingTime += this.waitPause; } } - - /** - * Execute a single command in PowerShell console and gets result - * - * @param command the command to execute - * @return response with the output of the command - */ - public static PowerShellResponse executeSingleCommand(String command) { - PowerShell session = null; - PowerShellResponse response = null; - try { - session = PowerShell.openSession(); - - response = session.executeCommand(command); - } catch (PowerShellNotAvailableException ex) { - Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "PowerShell not available", ex); - } finally { - if (session != null) { - session.close(); - } - } - return response; - } } diff --git a/src/main/java/com/profesorfalken/jpowershell/PowerShellCommandProcessor.java b/src/main/java/com/profesorfalken/jpowershell/PowerShellCommandProcessor.java index 0449feb..38a24d6 100644 --- a/src/main/java/com/profesorfalken/jpowershell/PowerShellCommandProcessor.java +++ b/src/main/java/com/profesorfalken/jpowershell/PowerShellCommandProcessor.java @@ -39,9 +39,11 @@ class PowerShellCommandProcessor implements Callable { private boolean closed = false; private boolean timeout = false; - + + private boolean scriptMode = false; + private final long maxWait; - private final int waitPause; + private final int waitPause; /** * Constructor that takes the output and the input of the PowerShell session @@ -49,12 +51,13 @@ class PowerShellCommandProcessor implements Callable { * @param commandWriter the input to the PowerShell console * @param inputStream the stream needed to read the command output */ - public PowerShellCommandProcessor(String name, InputStream inputStream, long maxWait, int waitPause) { + public PowerShellCommandProcessor(String name, InputStream inputStream, long maxWait, int waitPause, boolean scriptMode) { this.reader = new BufferedReader(new InputStreamReader( inputStream)); this.name = name; this.maxWait = maxWait; this.waitPause = waitPause; + this.scriptMode = scriptMode; } /** @@ -73,6 +76,8 @@ public String call() throws IOException, InterruptedException { } catch (IOException ioe) { Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "Unexpected error reading PowerShell output", ioe); return ioe.getMessage(); + } catch (Exception e) { + Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "Unexpected error reading PowerShell output", e); } return powerShellOutput.toString(); @@ -82,13 +87,25 @@ public String call() throws IOException, InterruptedException { private void readData(StringBuilder powerShellOutput) throws IOException { String line; while (null != (line = this.reader.readLine())) { - powerShellOutput.append(line).append(CRLF); - try { - if (!continueReading() || this.closed) { + + //In the case of script mode it finish when the last line is readed + if (this.scriptMode) { + if (line.equals(PowerShell.END_SCRIPT_STRING)) { break; } - } catch (InterruptedException ex) { - Logger.getLogger(PowerShellCommandProcessor.class.getName()).log(Level.SEVERE, null, ex); + } + + powerShellOutput.append(line).append(CRLF); + + //When not in script mode, it exits when the command is finished + if (!this.scriptMode) { + try { + if (!continueReading() || this.closed) { + break; + } + } catch (InterruptedException ex) { + Logger.getLogger(PowerShellCommandProcessor.class.getName()).log(Level.SEVERE, "Error executing command and reading result", ex); + } } } } @@ -129,7 +146,7 @@ public void close() { public String getName() { return this.name; } - + /** * Return if the execution finished with a timeout * diff --git a/src/test/java/com/profesorfalken/jpowershell/PowerShellTest.java b/src/test/java/com/profesorfalken/jpowershell/PowerShellTest.java index a6d8c71..913c188 100644 --- a/src/test/java/com/profesorfalken/jpowershell/PowerShellTest.java +++ b/src/test/java/com/profesorfalken/jpowershell/PowerShellTest.java @@ -1,5 +1,8 @@ package com.profesorfalken.jpowershell; +import java.io.File; +import java.io.FileWriter; +import java.util.Date; import java.util.HashMap; import java.util.Map; import org.junit.Assert; @@ -11,6 +14,8 @@ * @author Javier Garcia Alonso */ public class PowerShellTest { + + private static final String CRLF = "\r\n"; /** * Test of openSession method, of class PowerShell. @@ -226,11 +231,11 @@ public void testComplexLoop() throws Exception { response = powerShell.executeCommand("Get-WmiObject Win32_BIOS"); System.out.println("BIOS information:" + response.getCommandOutput()); - + response = powerShell.executeCommand("sfdsfdsf"); - + System.out.println("Error:" + response.getCommandOutput()); - + response = powerShell.executeCommand("Get-WmiObject Win32_BIOS"); System.out.println("BIOS information:" + response.getCommandOutput()); @@ -337,7 +342,7 @@ public void testLongLoop() throws Exception { } } } - + /** * Test of long command * @@ -350,17 +355,47 @@ public void testTimeout() throws Exception { PowerShell powerShell = PowerShell.openSession(); PowerShellResponse response = null; try { - response = powerShell.executeCommand("Start-Sleep -s 15"); + response = powerShell.executeCommand("Start-Sleep -s 15"); } finally { powerShell.close(); } - + Assert.assertNotNull(response); Assert.assertTrue("PS error should finish in timeout", response.isTimeout()); + + } + } + + @Test + public void testLongScript() throws Exception { + System.out.println("testLongScript"); + if (OSDetector.isWindows()) { + PowerShell powerShell = PowerShell.openSession(); + Map config = new HashMap(); + config.put("maxWait", "80000"); + PowerShellResponse response = null; + + StringBuilder scriptContent = new StringBuilder(); + scriptContent.append("Write-Host \"First message\"").append(CRLF); + scriptContent.append("$output = \"c:\\10meg.test\"").append(CRLF); + scriptContent.append("(New-Object System.Net.WebClient).DownloadFile(\"http://ipv4.download.thinkbroadband.com/10MB.zip\",$output)").append(CRLF); + scriptContent.append("Write-Host \"Second message\"").append(CRLF); + scriptContent.append("(New-Object System.Net.WebClient).DownloadFile(\"http://ipv4.download.thinkbroadband.com/10MB.zip\",$output)").append(CRLF); + scriptContent.append("Write-Host \"Finish!\"").append(CRLF); + try { + response = powerShell.configuration(config).executeScript(generateScript(scriptContent.toString())); + } finally { + powerShell.close(); + } + + Assert.assertNotNull("Response null!",response); + Assert.assertFalse("Is in error!", response.isError()); + Assert.assertFalse("Is timeout!", response.isTimeout()); + System.out.println(response.getCommandOutput()); } } - + /** * Test of long command * @@ -375,14 +410,32 @@ public void testConfiguration() throws Exception { config.put("maxWait", "1000"); PowerShellResponse response = null; try { - response = powerShell.configuration(config).executeCommand("Start-Sleep -s 10; Get-Process"); + response = powerShell.configuration(config).executeCommand("Start-Sleep -s 10; Get-Process"); } finally { powerShell.close(); } - + Assert.assertNotNull(response); Assert.assertTrue("PS error should finish in timeout", response.isTimeout()); - + + } + } + + private static String generateScript(String scriptContent) throws Exception { + File tmpFile = null; + FileWriter writer = null; + + try { + tmpFile = File.createTempFile("psscript_" + new Date().getTime(), ".ps1"); + writer = new FileWriter(tmpFile); + writer.write(scriptContent); + writer.flush(); + writer.close(); + } finally { + if (writer != null) { + writer.close(); + } } + return (tmpFile != null) ? tmpFile.getAbsolutePath() : null; } }