当前位置: 首页 > article >正文

使用java批量生成Xshell session(*.xsh)文件

背景

工作中需要管理多套环境, 有时需要同时登陆多个节点, 且每个环境用户名密码都一样, 因此需要一个方案来解决动态的批量登录问题.

XShell

Xshellsession管理功能:

  1. 提供了包括记住登录主机、用户名、密码及登录时执行命令或脚本(js,py,vbs)的功能

  2. session被存储在xsh文件中, 默认的存储在%USERPROFILE%\Documents\NetSarang Computer\7\Xshell\Sessions文件夹下

  3. 使用xshell可以直接打开存储在xsh文件中的用户登录信息, 比如: /d/Program_Files/Xshell/Xshell 192.168.31.6.xsh

  4. xsh文件使用UTF-16LE编码

  5. xsh采用与ini相同的格式进行配置

  6. xsh有许多配置项, 这里列举比较重要的:

    1. [CONNECTION].Host: 登录用户名

    2. [CONNECTION:AUTHENTICATION].UserName: 登录用户名

    3. [CONNECTION:AUTHENTICATION].Password: 登录密码, 使用XShell自有加解密算法, 因此在生成时需要先根据加解密算法生成加密后的密码, 参考how-does-Xmanager-encrypt-password1, 我通过pyinstaller -F XShellCryptoHelper.py将其打包为exejava使用

    4. [CONNECTION:AUTHENTICATION].UseInitScript: 是否使用登录脚本, 1表示开启, 0表示不使用

      XShell同时提供了与expect一样的交互功能, 可以和脚本共同使用, 但由于脚本本身具备这种功能, 并且移植性好, 所以本文不考虑expect

    5. [CONNECTION:AUTHENTICATION].ScriptPath: 登录脚本存储位置

需求

通过java生成一个/d/test.xsh文件(能生成一个就能生成N个), 并且在登录的同时执行一个python脚本, 效果如下:

在这里插入图片描述

所需信息:

  1. 用户名root

  2. 密码test@2023

  3. 登录主机192.168.31.6

  4. 执行脚本D:\init.py:

    def Main():
    	# 等待root用户登录成功
    	xsh.Screen.WaitForString('#')
    	xsh.Screen.Send("echo hello word\r")
    

思路

XShell提供了一个默认的session配置文件: %USERPROFILE%\Documents\NetSarang Computer\7\Xshell\Sessions\default:

  1. 读取它, 并且根据关键字一一替换:
    1. Host= -> Host=192.168.31.6
    2. UserName= -> UserName=root
    3. Password= -> Password=xxx, 这里根据自己生成的密码密文进行替换
    4. UseInitScript=0 -> UseInitScript=1
    5. ScriptPath= -> ScriptPath=D:\init.py
  2. 使用UTF-16LE进行编码并保存在/d/test.xsh
  3. 使用XShell /d/test.xsh进行测试, 成功登录并且打印出hello world即可

实现

使用java17进行编码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class Xsh {
    private static final String XSHELL_CRYPTO_HELPER_LOCATION = "D:/XShellCryptoHelper.exe";
    private static final String[] ENCRYPT_CMD = new String[]{"cmd", "/c", XSHELL_CRYPTO_HELPER_LOCATION, "-e", "test@2023"};
    private static final String DEFAULT_SESSION_LOCATION = System.getenv("USERPROFILE") + "\\Documents\\NetSarang Computer\\7\\Xshell\\Sessions\\default";

    private static final String TEST_XSH_LOCATION = "D:\\test.xsh";

    private static final String[] RUN_XSHELL_CMD = new String[]{"cmd", "/k", "start D:\\Program_Files\\Xshell\\XShell.exe " + TEST_XSH_LOCATION};

    public static void main(String[] args) throws IOException, InterruptedException {
        String xshContent = Files.readAllLines(Paths.get(DEFAULT_SESSION_LOCATION), StandardCharsets.UTF_16LE).stream().map(line -> {
            if (line == null || line.isBlank()) {
                return line;
            }
            return switch (line.trim()) {
                case "Host=" -> "Host=192.168.31.6";
                case "UserName=" -> "UserName=root";
                case "Password=" -> "Password=" + encrypt();
                case "UseInitScript=0" -> "UseInitScript=1";
                case "ScriptPath=" -> "ScriptPath=D:\\init.py";
                default -> line;
            };
        }).collect(Collectors.joining(System.lineSeparator()));

        Path path = Paths.get(TEST_XSH_LOCATION);
        Files.deleteIfExists(path);
        Files.writeString(path, xshContent, StandardCharsets.UTF_16LE);
        CompletableFuture.runAsync(() -> {
            try {
                Runtime.getRuntime().exec(RUN_XSHELL_CMD);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
        TimeUnit.SECONDS.sleep(3);
    }


    private static String encrypt() {
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        try {
            Process process = Runtime.getRuntime().exec(ENCRYPT_CMD);
            process.waitFor();
            is = process.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
            // 只有一行输出
            return br.readLine();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                br.close();
                isr.close();
                is.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

参考

  1. Using Script

  1. 本项目原作者很长时间没有更新, 本来不支持7.*版本的加密, 我参考XDecrypt项目对其进行了补充, 当前已支持XShell全系列加解密!! ↩︎


http://www.kler.cn/a/154579.html

相关文章:

  • hive表名重命名、rename重命名
  • 无人机检测车辆——多目标检测
  • 基于rk356x u-boot版本功能分析及编译相关(三)Makefile分析
  • JavaSE常用API-日期(计算两个日期时间差-高考倒计时)
  • 自动驾驶仿真:软件在环(SIL)测试详解(精简版入门)
  • Ubuntu 18 EDK2 环境编译
  • Unity对接后台和加载图片
  • 4.4-Docker bridge0详解
  • oracle FUNCTION(任意两个时间 之间的工作小时)
  • 游戏被流量攻击会有什么样的影响,该用什么样的防护方式去处理
  • 07-原型模式-C语言实现
  • 2022年9月6日 Go生态洞察:Go的漏洞管理新支持
  • 基于Cocos2D-X框架闯关游戏的设计
  • acwing算法基础之贪心--排序不等式、绝对值不等式和推公式
  • 【LeetCode热题100】【双指针】移动零
  • Asp.Net Core Web Api内存泄漏问题
  • 阿里云域名解析到非默认端口处理方式
  • Uniapp Vue3 基础到实战 教学视频
  • 计算机毕业设计 基于Web的铁路订票管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
  • Kafka常见面试题
  • 苹果mac屏幕投屏镜像工具AirServer2024
  • uni-app x生成的安卓包,安装时,提示不兼容。解决方案
  • JTag 提取NXP固件脚本示例
  • 使用wininet下载一个网页
  • 进程间通信 管道
  • 用两个队列实现栈