114 lines
3.6 KiB
Python
114 lines
3.6 KiB
Python
import paramiko
|
||
import time
|
||
import chardet
|
||
|
||
|
||
class SSHManager:
|
||
def __init__(self, host, username, password, port=22, timeout=30):
|
||
"""
|
||
SSH客户端管理类初始化
|
||
:param host: 目标主机IP [2,6](@ref)
|
||
:param username: 用户名
|
||
:param password: 密码(建议后续改为密钥认证)[8](@ref)
|
||
:param port: SSH端口,默认22 [4](@ref)
|
||
:param timeout: 连接超时时间
|
||
"""
|
||
self.client = paramiko.SSHClient()
|
||
self.host = host
|
||
self.port = port
|
||
self.username = username
|
||
self.password = password
|
||
self.timeout = timeout
|
||
self._set_policy()
|
||
|
||
def _set_policy(self):
|
||
"""设置主机密钥策略(自动添加新主机)[1,4](@ref)"""
|
||
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||
|
||
def connect(self):
|
||
"""建立SSH连接并进行异常处理[5,8](@ref)"""
|
||
try:
|
||
self.client.connect(
|
||
hostname=self.host,
|
||
port=self.port,
|
||
username=self.username,
|
||
password=self.password,
|
||
timeout=self.timeout,
|
||
look_for_keys=False # 禁用密钥查找[4](@ref)
|
||
)
|
||
print(f"成功连接到 {self.host}")
|
||
except paramiko.AuthenticationException:
|
||
raise Exception("认证失败,请检查用户名/密码")
|
||
except paramiko.SSHException as e:
|
||
raise Exception(f"SSH连接错误: {str(e)}")
|
||
except Exception as e:
|
||
raise Exception(f"连接异常: {str(e)}")
|
||
|
||
def execute_command(self, command, get_pty=True):
|
||
"""
|
||
执行远程命令并返回标准化结果
|
||
:param command: 要执行的命令 [6](@ref)
|
||
:param get_pty: 是否分配伪终端(解决部分命令需要TTY的问题)[4](@ref)
|
||
:return: (output, error) 元组
|
||
"""
|
||
if not self.client.get_transport() or not self.client.get_transport().is_active():
|
||
self.connect()
|
||
|
||
try:
|
||
stdin, stdout, stderr = self.client.exec_command(
|
||
command,
|
||
get_pty=get_pty,
|
||
timeout=self.timeout
|
||
)
|
||
|
||
config_list = []
|
||
for line in stdout.readlines():
|
||
line = line.replace('\n', '').replace('\r', '')
|
||
print(line)
|
||
config_list.append(line)
|
||
|
||
return config_list
|
||
|
||
except Exception as e:
|
||
return False
|
||
|
||
def _decode_line(self, line):
|
||
"""自动检测编码并解码[7](@ref)"""
|
||
encoding = chardet.detect(line)['encoding']
|
||
return line.decode(encoding if encoding else 'utf-8', errors='replace')
|
||
|
||
def close(self):
|
||
"""安全关闭连接"""
|
||
if self.client.get_transport() and self.client.get_transport().is_active():
|
||
self.client.close()
|
||
print("SSH连接已关闭")
|
||
|
||
def __enter__(self):
|
||
"""支持上下文管理器[1,6](@ref)"""
|
||
self.connect()
|
||
return self
|
||
|
||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||
"""上下文管理器退出时自动关闭"""
|
||
self.close()
|
||
|
||
|
||
# 使用示例
|
||
if __name__ == "__main__":
|
||
try:
|
||
with SSHManager(
|
||
host='192.168.50.105',
|
||
username='Administrator',
|
||
password='123456'
|
||
) as ssh:
|
||
# 执行单条命令
|
||
output = ssh.execute_command(r'start /B python 远程程序.py')
|
||
|
||
# ssh.execute_command(r'cmd.exe /C start notepad.exe C:\Users\user\Desktop\test.txt')
|
||
|
||
print(output)
|
||
|
||
|
||
except Exception as e:
|
||
print(f"操作失败: {str(e)}")
|