【问题标题】:how to create a powershell remote session from inside a Java program?如何从 Java 程序内部创建 powershell 远程会话?
【发布时间】:2017-03-28 06:04:30
【问题描述】:

我有以下代码可以连接到远程机器并执行命令。如果我为远程机器的每个 Invoke-Command 调用创建一个新会话,它就可以工作。我不想每次使用 Invoke-Command 时都创建一个新会话,因为这不会同时扩展到数百台机器上的数千个命令,并且会话创建本身就是一个很大的开销。我需要一种方法,以便我可以重用 $session powershell 变量中的相同会话对象,以便对远程机器进行多次 Invoke-Command 调用。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class PowerShellSession {

private static String subModule = "PowerShellSession";
String targetIpAddress;
String username;
String password;

public static Object connectPShellLock = new Object();

public PowerShellSession() {}


public void exec(String cmd, String credentials)  { 

    String ex = "Invoke-Command -Session $session -ScriptBlock {" + cmd + "} -Computer " + targetIpAddress;

    String[] args = new String[] { "powershell", ex};
    try {
        execRemote(args);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void close() {
    String command = "Exit-PSSession";
    String[] args = new String[] { "powershell", command};
    try {
        execRemote(args);
    } catch (IOException e) {
        e.printStackTrace();
    }

}

private String getCredentials(String domain, String userName,
        String password) throws IOException {
    String creds = "$PlainPassword ='" + password
            + "'; $SecurePassword = $PlainPassword | ConvertTo-SecureString -AsPlainText -Force;"
            + "$mycred = new-object -typename System.Management.Automation.PSCredential('" + userName + "', $SecurePassword);";
    creds += "$session = New-PSSession -ComputerName " + domain + " -Credential $mycred;";

    String[] args = new String[] { "powershell", creds};
    execRemote(args);
    return creds;
}

private void execRemote(String[] arguments) throws IOException {
    ProcessBuilder builder = new ProcessBuilder(arguments);
    builder.redirectErrorStream(true);
    Process process = builder.start();
    doProcessIO(process);
}

// Do the IO for a passed process
private void doProcessIO(Process p) throws IOException {
    p.getOutputStream().close();
    String line;
    System.out.println("Output:");
    BufferedReader stdout = new BufferedReader(new InputStreamReader(
            p.getInputStream()));
    while ((line = stdout.readLine()) != null) {
        System.out.println(line);
    }
    stdout.close();
    System.out.println("Error:");
    BufferedReader stderr = new BufferedReader(new InputStreamReader(
            p.getErrorStream()));
    while ((line = stderr.readLine()) != null) {
        System.out.println(line);
    }
    stderr.close();
//      System.out.println("Done");
}

public static void main(String[] args) throws IOException {
    PowerShellSession psSession = new PowerShellSession();
    String credentials = psSession.getCredentials("9.120.241.195", "username", "password");
    psSession.targetIpAddress = "9.120.241.195";
    if(!credentials.equals("")) {
        Scanner input = new Scanner(System.in);
        while(true) {
            System.out.print("PS C:\\Windows\\system32> ");
            String cmd = input.nextLine();
            if(cmd.equals("q") || cmd.equals("e") || cmd.equals("quit") || cmd.equals("exit")) break;
            psSession.username = "username";
            psSession.password = "password";
            psSession.exec(cmd, "");
        }
        System.out.println("Finished PowerShell remote session.");
        input.close();
    }
    psSession.close();
}
}

【问题讨论】:

    标签: java powershell remoting winrm


    【解决方案1】:

    请参阅其中涉及的许多逻辑可以帮助您。

    您的会话调用很好;但是你不能直接运行这样的 PS 命令。您必须首先调用 powershell.exe,然后您必须为相应的远程命令提供您想要执行的内容。

    最后你已经执行了你准备的命令。让我分享一个示例代码:

    public String executeScript(String psFileName, Systems system) throws NMAException {
    
            Runtime runtime = Runtime.getRuntime();
            String filePath = ApplicationProperties.getPropertyValue("powershell.scripts.location");
            String command;
    
            switch (psFileName) {
                case "TerminalServersSystemInfo.ps1":
                    command = POWERSHELL + filePath + psFileName + " " + system.getPassword() + " " + system.getUserName()
                            + " " + system.getSystemName();
                    break;
                case "SQLServerInfo.ps1":
                    command = POWERSHELL + filePath + psFileName + " " + system.getSystemName() + " "
                            + system.getUserName() + " " + system.getPassword();
                    break;
                case "MyPS.ps1":
    
                {
                    command = POWERSHELL + filePath + psFileName + " " + system.getSystemName() + " "
                            + system.getUserName()
                            + " " + system.getPassword() + " " + system.getDatabaseName();
                    break;
                }
    
                default:
                    throw new NMAException("not available");
            }
    

    下面是你应该如何在 Java 中形成命令对象,然后你应该执行这个:

    powershell -ExecutionPolicy Bypass -NoLogo -NoProfile -Command {Invoke-command ......}
    

    要触发 PS 文件,您可以使用 -Filepath 开关。

    接下来,这将帮助您执行该操作:

    proc = runtime.exec(command);
                proc.getOutputStream().close();
                InputStream is = proc.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader reader = new BufferedReader(isr);
                StringBuilder sb = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
                reader.close();
                proc.getOutputStream().close();
                LOGGER.info("Command: " + command);
                LOGGER.info("Result:" + sb.toString());
                return sb.toString();
    

    希望它能给你一个衬托。

    【讨论】:

    • 我的要求是创建一个会话并执行多个命令/脚本。在上面的代码中,在每种情况下都传递了凭据,这意味着我们正在创建多个会话。有什么方法可以让我只设置一次凭据,然后执行多个命令/脚本?
    • 您可以创建一个会话变量,您可以在其中传递凭据,然后您可以利用该会话变量来运行多个线程
    【解决方案2】:
    public class PowerShellSession {
        private static String subModule = "PowerShellSession";
        String targetIpAddress;
        String username;
        String password;
    
        public static Object connectPShellLock = new Object();
    
        public PowerShellSession() {}
    
    
        public void exec(String cmd, String credentials)  { 
    
            String ex = credentials +" Invoke-Command -ScriptBlock {" + cmd + "} -ComputerName " + targetIpAddress +" -Credential $mycred";
    
            String[] args = new String[] { "powershell", ex};
            try {
                execRemote(args);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void close() {
            String command = "Exit-PSSession";
            String[] args = new String[] { "powershell", command};
            try {
                execRemote(args);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        private String getCredentials(String domain, String userName,
                String password) throws IOException {
            String creds = "$Username = '"+userName+"';$PlainPassword ='" + password
                    + "'; $SecurePassword = ConvertTo-SecureString -AsPlainText $PlainPassword -Force;"
                    + "$mycred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePassword;";
            //creds += "$session = New-PSSession -ComputerName " + domain + " -Credential $mycred;";
    
            String[] args = new String[] { "powershell", creds};
            execRemote(args);
            return creds;
        }
    
        private void execRemote(String[] arguments) throws IOException {
            ProcessBuilder builder = new ProcessBuilder(arguments);
            builder.redirectErrorStream(true);
            Process process = builder.start();
            doProcessIO(process);
        }
    
        // Do the IO for a passed process
        private void doProcessIO(Process p) throws IOException {
            p.getOutputStream().close();
            String line;
            System.out.println("Output:");
            BufferedReader stdout = new BufferedReader(new InputStreamReader(
                    p.getInputStream()));
            while ((line = stdout.readLine()) != null) {
                System.out.println(line);
            }
            stdout.close();
            System.out.println("Error:");
            BufferedReader stderr = new BufferedReader(new InputStreamReader(
                    p.getErrorStream()));
            while ((line = stderr.readLine()) != null) {
                System.out.println(line);
            }
            stderr.close();
            System.out.println("Done");
        }
    
        public static void main(String[] args) throws IOException {
            PropertiesFileReader propReader = new PropertiesFileReader(System.getProperty("user.dir")+"/cred.properties");
    
            String user = propReader.getPropertyData("user");
            String pass = propReader.getPropertyData("pass");
            String ip_add = propReader.getPropertyData("ip");
    
            PowerShellSession psSession = new PowerShellSession();
            String credentials = psSession.getCredentials(ip_add, user, pass);
            psSession.targetIpAddress = ip_add;//;
    
    
    
            String cmdd = propReader.getPropertyData("command");//"Get-Culture";
            if(!credentials.equals("")) {
    
    
                psSession.exec(cmdd, credentials);
    
                System.out.println("Finished PowerShell remote session.");
    
            }
            psSession.close();
        }
    
    }
    

    【讨论】:

    • @Manjur:我已经修改了你的代码,即第一个代码,现在它现在可以工作了。
    猜你喜欢
    • 2011-03-14
    • 1970-01-01
    • 2013-04-10
    • 2014-11-07
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多