在某些场景下,需要在Java程序中使用Powershell进行终端交互,这种情况下当然可以直接使用自带的Runtime来完成:
Runtime.getRuntime().exec("powershell.exe Get-Item");
但是这种只适合需要单条指令的情况,而存在多条指令时,无法保证前后指令的关联性。这里介绍一个第三方的类库:jPowershell
Maven中引入如下依赖:
<dependency> <groupId>com.profesorfalken</groupId> <artifactId>jPowerShell</artifactId> <version>3.1.1</version> </dependency>
接下来,在程序中就可以通过如下方式获取到一个Powershell的实例:
PowerShell session = PowerShell.openSession();
PowerShell对象提供了如下的基础方法:
configuration(Map<String,String> arg0) |
指定配置对象 | void | 修改默认配置时使用 |
openSession() |
PowerShell | 启动一个PowerShell会话 | |
openSession(String arg0) |
指定PowerShell终端的路径 | PowerShell | 启动一个PowerShell会话 |
executeCommand(String arg0) |
Powershell指令 | PowerShellResponse | 执行一条PowerShell指令 |
executeSingleCommand() |
Powershell指令 | PowerShellResponse | 执行单一PowerShell指令(无会话模式) |
executeCommandAndChain(String arg0,PowerShellResponseHandler.. arg1) |
PowerShell指令,Response处理器 | PowerShell | 执行一条PowerShell指令并对其Response进行处理 |
handleResponse(PowerShellResponseHandler arg0,PowerShellResponse arg1) |
Response处理器,Response | void | 使用指定Response处理器处理响应 |
isLastCommandInError() |
boolean | 最后一条指令是否出错 | |
executeScript(String arg0) |
脚本路径 | PowerShellResponse | 执行指定的脚本 |
executeScript(String arg0, String arg1) | 脚本路径,执行参数 | PowerShellResponse | 传入参数执行指定脚本 |
executeScript(BufferedReader arg0) | 脚本缓冲对象 | PowerShellResponse | 从缓冲对象中执行脚本 |
executeScript(BufferedReader arg0, String arg1) | 脚本缓冲对象,执行参数 | PowerShellResponse | 传入参数执行缓冲对象中的脚本 |
close() | void | 关闭会话 | |
closeAndWait(Future<String> arg0) | 异步对象列表 | boolean | 等待异步对象列表中全部Task完成后关闭会话 |
checkState() | void | 检查当前会话状态 |
获取到的session对象是一个新的Powershell会话实例,可以通过下述方式来执行指令:
String readContext = "Get-Content D:\\1.sql"; session.executeCommand("$user = \""+username+"\""); session.executeCommand("$password = ConvertTo-SecureString \"" +password + "\" -AsPlainText -Force"); session.executeCommand("$credential = New-Object System.Management.Automation.PSCredential($user,$password)"); response = session.executeCommand("Invoke-Command -ComputerName " + server + " -Credential $credential -ScriptBlock {" + readContext + "}"); System.out.println(response.getCommandOutput().length());
上述代码中,首先定义了两个shell变量,$user和$password,而后通过调用System.Management.Automation.PSCredential构造了一个$credential对象,再将其作为-Credential的值传入下一条指令中,完成远程Invoke-Command进行文件内容长度的读取。
每一条session.executeCommand()都会返回一个PowerShellResponse对象,可以通过调用这个对象的getCommandOutput()方法来获取命令输出。注意看日志最后的数字:
public class PowerShell implements AutoCloseable { private static final Logger logger = Logger.getLogger(PowerShell.class.getName()); private Process p; private long pid = -1L; private PrintWriter commandWriter; private boolean closed = false; private ExecutorService threadpool; private static final String DEFAULT_WIN_EXECUTABLE = "powershell.exe"; private static final String DEFAULT_LINUX_EXECUTABLE = "powershell"; private int waitPause = 5; private long maxWait = 10000L; private File tempFolder = null; private boolean scriptMode = false; public static final String END_SCRIPT_STRING = "--END-JPOWERSHELL-SCRIPT--"; private PowerShell() { } public PowerShell configuration(Map<String, String> config) { try { this.waitPause = Integer.valueOf(config != null && config.get("waitPause") != null ? (String)config.get("waitPause") : PowerShellConfig.getConfig().getProperty("waitPause")); this.maxWait = Long.valueOf(config != null && config.get("maxWait") != null ? (String)config.get("maxWait") : PowerShellConfig.getConfig().getProperty("maxWait")); this.tempFolder = config != null && config.get("tempFolder") != null ? this.getTempFolder((String)config.get("tempFolder")) : this.getTempFolder(PowerShellConfig.getConfig().getProperty("tempFolder")); } catch (NumberFormatException var3) { logger.log(Level.SEVERE, "Could not read configuration. Using default values.", var3); } return this; } }
Powershell提供了一个configuration()方法,这个方法接受一个Map类型的配置参数,并将内容解析后代替默认参数。我们主要关注的是maxWait的值。通过成员定义可以看出,默认的maxWait的值就是10000毫秒,也就是10秒。因此,可以通过如下代码来使其支持更长时间指令的调用:
PowerShell session = PowerShell.openSession(); Map<String,String> configMap = new HashMap<>(); configMap.put("maxWait","600000"); session.configuration(configMap);
这样就把指令的最长等待时间设置为了600秒。