在某些場景下,需要在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秒。