在某些场景下,需要在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()方法来获取命令输出。注意看日志最后的数字:

当然,在某些情况下,调用的指令执行时间会很长,在默认情况下,Powershell实例只会等待10秒钟,如果10秒钟之后还没有返回值,就直接跳到下一条继续执行了。这种情况下,可以通过配置Powershell的实例来修改等待时间。来看源码:

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秒。