關于winrm遠程ps登錄執(zhí)行出現(xiàn)中文亂碼問題及其解決辦法

pyhton的winrm庫提供了命令行遠程連接的功能,可以實現(xiàn)遠程登錄并進行執(zhí)行指令的功能:
1.遠端登錄

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

當然,如果想實現(xiàn)遠端連接,客戶端和服務端都要進行winrm服務的開啟和設置,詳細請參考:

http://www.itdecent.cn/p/ac095497bad4


2.執(zhí)行命令
winrm作為面向window遠程連接的庫,提供了兩種執(zhí)行命令的執(zhí)行方式,cmd命令和ps命令,兩種命令還是有區(qū)別的,例如ps的命令直接用cmd跑就會報錯,二者的區(qū)別筆者借鑒了網(wǎng)上的說法:

powershell 可以看作 cmd 的超集,所有的常用命令諸如dir, cd, ipconfig等在 powershell 中都能直接使用。但背后的實現(xiàn)方式是完全不同的,powershell 基于完全的面向?qū)ο?,它通過給函數(shù)和對象“起別名”的方式來支持這些舊的命令

具體二者的區(qū)別感興趣的可以去深究,看各位需求。
執(zhí)行命令很簡單,直接用已生成的shell對象去調(diào)用對應的方法就好

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

想要獲取命令返回的內(nèi)容,可以直接
res.std_out.decode()
res還有其他參數(shù),如狀態(tài)碼等,需要的可以直接使用


3.返回結果出現(xiàn)中文亂碼問題
方法一:
首先需明確是不是出現(xiàn)在回顯回來時編碼出現(xiàn)問題

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

查看編碼類型

直接decode print出來的編碼類型,例如print出來的是gb2312 ,那么就使用
res.std_out.decode('gb2112')

方法二:
如果不是輸出的時候有問題,那就要考慮發(fā)送命令的時候是不是有問題
首先,應該確保出問題的命令是否能跑,可以通過遠程連接到對應的服務器,手動跑一下,powershell 遠程登錄可以參考:https://blog.csdn.net/weixin_40943540/article/details/89344265
如果確定命令正常,可能是源碼的問題了。
跑到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

重點觀察這兩個函數(shù),我們可以看到,當你執(zhí)行 run_ps時,他會通過轉碼后直接調(diào)用run_cmd,所以這是不是可以認為ps命令通過轉碼后就可以跑到cmd執(zhí)行呢?這個只是一個猜測,有待研究。出現(xiàn)中文問題亂碼的問題可能也是出現(xiàn)在這個轉碼上!
通過debug可以看到,我們輸入的命令的condepage為936,而庫默認的編碼為437,這就會使輸入的命令出現(xiàn)亂碼現(xiàn)象,現(xiàn)在要做的就是統(tǒng)一編碼。
第一步:繼承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

第二步:在執(zhí)行命令前設置好shell的編碼

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

重寫調(diào)用run_ps和run_cnd時注意調(diào)用你改寫的類的方法,不然重寫就沒意義了,這樣就可以保證輸入命令時,編碼統(tǒng)一。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容