winrm的全称是Windows Remote Management,翻译就是windows的远程管理,说白了就是通过网络http请求在对windows进行管理,由于我之前是用python开发,所以此次我记录的使用python的pywinrm模块来实现对windows的远程访问。

        winrm这个模块windows是自带的,但是好像默认功能是关闭的,需要去命令行执行命令开启这个功能,具体命令是啥也忘记了,不过网上应该能搜到,有很多。我这里主要记录的是pywinrm这个模块的时间笔记。

        我们一般使用的是winrm模块向远程主机执行命令行命令,主要实现远程对账户的控制命令,我另外一篇文章有写哪些命令来完成账户的远程控制:命令行管理账户,此时就会存在cmd命令和PowerShell命令,一般python的winrm模块里面存在此封装,如下所示

import winrm
shell="net user"
s = winrm.Session(ip, auth=(username, password), transport='ntlm')  # 远程连接windows
r = s.run_ps(shell) #是powershell命令就执行此函数
r = s.run_cmd(shell) #是命令行提示符cmd命令就执行此函数

上面代码里面有两个执行命令的函数,一个是run_ps,一个是run_cmd,分别对应执行PowerShell的命令和cmd的命令,这两个命令,其实背后都是调用Protocol,然后进行了封装,我测试了,好像运行起来速度有点慢,而且有些命令还执行有问题,然后我就自己重构了Protocol类,让这个类既可以支持PowerShell命令,又可以支持cmd命令。一般情况下Protocol默认只支持cmd命令的。我的源码如下:

from winrm.protocol import Protocol
from base64 import b64encode

class NewProtocol(Protocol):
    def run_command_ps(self, newshell_id, newcommand):
        encoded_ps = b64encode(newcommand.encode('utf_16_le')).decode('ascii')
        newcmd = 'powershell -encodedcommand {0}'.format(encoded_ps)
        return self.run_command(shell_id=newshell_id, command=newcmd)

#上面NewProtocol类是我重构的Protocol类,下面有实例怎么调用


class PowerShellCmdClass():
    def __init__(self,assitsip,adminname,adminpd):
        self.end_point = "http://%s:5985/wsman" % assitsip
        self.adminname = adminname
        self.adminpd = adminpd
        self.p = None
        self.shell_id = None
        self.command_id = None
        
    def initconnect(self):
        try:
            self.p = NewProtocol(
                endpoint=self.end_point,
                transport='ntlm',
                username=self.adminname,
                password=self.adminpd,
                server_cert_validation='ignore')
            self.shell_id = self.p.open_shell()  # 打开shell
            return 0
        except Exception as e:
            return -1

    def cmdtest(self):
        try:
            cmd = "net user" #命令行提示符cmd柯执行的命令
            self.command_id = self.p.run_command(self.shell_id, cmd)
            std_out, std_err, status_code = self.p.get_command_output(self.shell_id, self.command_id)  # 获取返回结果
            # print(status_code)
            #print(str(std_out, 'utf-8'))
            return status_code
        except Exception as e:
            return -1

    def powershelltest(self):
        try:
            cmd = "Get-ACL -Path C:\Users" #PowerShell才能执行的命令
            self.command_id = self.p.run_command_ps(self.shell_id, cmd)
            std_out, std_err, status_code = self.p.get_command_output(self.shell_id, self.command_id)  # 获取返回结果
            # print(status_code)
            #print(str(std_out, 'utf-8'))
            return status_code
        except Exception as e:
            return -1

    
    def freeinit(self):
        self.p.cleanup_command(self.shell_id, self.command_id)
        self.p.close_shell(self.shell_id)  # 关闭shell
        
        
# 测试程序
newcmd = UserCmdClass("192.168.10.192","admin","1") #参数为远程主机ip地址、管理账户和管理员账户密码
newcmd .initconnect()
newcmd .cmdtest()
newcmd .powershelltest()
newcmd .freeinit

在上面的源码中可以看到,我重构了Protocol类,让其多了一个功能为run_command_ps的函数,此函数支持PowerShell命令的远程调用,我测试了这run_command_ps和run_command发送的命令,速度很快,比run_ps和run_cmd要好用一些。