关于python:关于winrm远程ps登录执行出现中文乱码和乱码问题及其解决办法

10次阅读

共计 2399 个字符,预计需要花费 6 分钟才能阅读完成。

pyhton 的 winrm 库提供了命令行近程连贯的性能,能够实现近程登录并进行执行指令的性能:
1. 远端登录

import winrm
auth = (username, password)
shell = winrm.Session(host_ip, auth=auth, transport='ntlm')
          

当然,如果想实现远端连贯,客户端和服务端都要进行 winrm 服务的开启和设置,具体请参考:

https://www.jianshu.com/p/ac0…


2. 执行命令
winrm 作为面向 window 近程连贯的库,提供了两种执行命令的执行形式,cmd 命令和 ps 命令,两种命令还是有区别的,例如 ps 的命令间接用 cmd 跑就会报错,二者的区别笔者借鉴了网上的说法:

powershell 能够看作 cmd 的超集,所有的常用命令诸如 dir, cd, ipconfig 等在 powershell 中都能间接应用。但背地的实现形式是齐全不同的,powershell 基于齐全的面向对象,它通过给函数和对象“起别名”的形式来反对这些旧的命令

具体二者的区别感兴趣的能够去深究,看各位需要。
执行命令很简略,间接用已生成的 shell 对象去调用对应的办法就好

res = shell.run_ps('ipconfig')
res = shell.run_cmd('ipconfig')

想要获取命令返回的内容,能够间接
res.std_out.decode()
res 还有其余参数,如状态码等,须要的能够间接应用


3. 返回后果呈现中文乱码问题
办法一:
首先需明确是不是呈现在回显回来时编码呈现问题

import chardet
print(chartdet.detect(res.std_out))

查看编码类型

间接 decode print 进去的编码类型,例如 print 进去的是 gb2312,那么就应用
res.std_out.decode('gb2112')

办法二:
如果不是输入的时候有问题,那就要思考发送命令的时候是不是有问题
首先,应该确保出问题的命令是否能跑,能够通过近程连贯到对应的服务器,手动跑一下,powershell 近程登录能够参考:https://blog.csdn.net/weixin_…
如果确定命令失常,可能是源码的问题了。
跑到 wirm 的源码里看看状况,我这里的版本是 pywinrm 0.4.2

  def run_cmd(self, command, args=()):
        # TODO optimize perf. Do not call open/close shell every time
        shell_id = self.protocol.open_shell()
        command_id = self.protocol.run_command(shell_id, command, args)
        rs = Response(self.protocol.get_command_output(shell_id, command_id))
        self.protocol.cleanup_command(shell_id, command_id)
        self.protocol.close_shell(shell_id)
        return rs

    def run_ps(self, script):
        """base64 encodes a Powershell script and executes the powershell
        encoded script command
        """
        # must use utf16 little endian on windows
        encoded_ps = b64encode(script.encode('utf_16_le')).decode('ascii')
        rs = self.run_cmd('powershell -encodedcommand {0}'.format(encoded_ps))
        if len(rs.std_err):
            # if there was an error message, clean it it up and make it human
            # readable
            rs.std_err = self._clean_error_msg(rs.std_err)
        return rs

重点察看这两个函数,咱们能够看到,当你执行 run_ps 时,他会通过转码后间接调用 run_cmd,所以这是不是能够认为 ps 命令通过转码后就能够跑到 cmd 执行呢?这个只是一个猜想,有待钻研。呈现中文问题乱码的问题可能也是呈现在这个转码上!
通过 debug 能够看到,咱们输出的命令的 condepage 为 936,而库默认的编码为 437,这就会使输出的命令呈现乱码景象,当初要做的就是对立编码。
第一步:继承 winrm.Session 这个类,并进行重写 run_cmd

    def run_cmd(self, command, args=()):
        # TODO optimize perf. Do not call open/close shell every time
        shell_id = self.protocol.open_shell(codepage=936)
        command_id = self.protocol.run_command(shell_id, command, args)
        rs = winrm.Response(self.protocol.get_command_output(shell_id, command_id))
        self.protocol.cleanup_command(shell_id, command_id)
        self.protocol.close_shell(shell_id)
        return rs

第二步:在执行命令前设置好 shell 的编码

shell.protocol.open_shell(codepage='936')

重写调用 run_ps 和 run_cnd 时留神调用你改写的类的办法,不然重写就没意义了,这样就能够保障输出命令时,编码对立。

正文完
 0