如何通过Python代码开启AWS Windows EC2的WSMan AllowUnencrypted解决pywinrm执行失败
解决方案:pywinrm连接AWS Windows EC2的配置问题
先解决SSL版本错误问题
你用https://访问5985端口是错误的——WinRM的5985是HTTP非加密端口,5986才是HTTPS加密端口。把endpoint的协议改成http://就能解决这个SSL错误:
protocol = Protocol( endpoint=f"http://{ec2_instance.public_dns_name}:5985/wsman", transport="ntlm", username="Administrator", password="Password", server_cert_validation="ignore", )
核心需求:自动开启WinRM的AllowUnencrypted和Basic Auth
问题的本质是:如果不先配置这两个参数,pywinrm根本无法通过Basic auth连接实例执行命令。所以需要在实例可连接之前就完成配置,推荐两种方案:
方案1:EC2实例启动时用用户数据自动配置
创建EC2实例时,添加以下PowerShell用户数据,实例启动后会自动执行配置:
<powershell> # 开启Basic认证 Set-Item -Force WSMan:\localhost\Service\auth\Basic $true # 允许非加密连接 Set-Item -Force WSMan:\localhost\Service\AllowUnencrypted $true # 重启WinRM服务使配置生效 Restart-Service WinRM </powershell>
配置完成后,直接用Basic auth连接即可:
import winrm session = winrm.Session( ec2_instance.public_dns_name, auth=(user_name, password), transport='basic', server_cert_validation='ignore' ) result = session.run_ps("hostname") print(result.std_out.decode('utf-8'))
方案2:用AWS SSM Run Command给已存在的实例配置
如果实例已经创建,不想重启,用AWS Systems Manager的Run Command远程执行配置脚本,无需手动登录实例。用boto3实现的示例代码:
import boto3 import time ssm_client = boto3.client('ssm', region_name='你的AWS区域') # 发送配置命令 response = ssm_client.send_command( InstanceIds=[ec2_instance.instance_id], DocumentName='AWS-RunPowerShellScript', Parameters={ 'commands': [ 'Set-Item -Force WSMan:\\localhost\\Service\\auth\\Basic $true', 'Set-Item -Force WSMan:\\localhost\\Service\\AllowUnencrypted $true', 'Restart-Service WinRM' ] } ) # 等待命令执行完成 command_id = response['Command']['CommandId'] while True: invocation = ssm_client.get_command_invocation( CommandId=command_id, InstanceId=ec2_instance.instance_id ) if invocation['Status'] in ['Success', 'Failed']: break time.sleep(5)
执行完成后,再用pywinrm的Basic auth或NTLM方式连接即可正常执行命令。
NTLM连接的正确示例
如果坚持使用NTLM,确认实例WinRM已开启NTLM认证(默认开启),使用以下代码:
from winrm.protocol import Protocol protocol = Protocol( endpoint=f"http://{ec2_instance.public_dns_name}:5985/wsman", transport="ntlm", username="Administrator", password="Password", server_cert_validation="ignore", ) # 执行命令流程 shell_id = protocol.open_shell() command_id = protocol.run_command(shell_id, 'hostname') std_out, std_err, status_code = protocol.get_command_output(shell_id, command_id) print(f"输出:{std_out.decode('utf-8')}") print(f"错误:{std_err.decode('utf-8')}") # 清理资源 protocol.cleanup_command(shell_id, command_id) protocol.close_shell(shell_id)
内容的提问来源于stack exchange,提问作者Praveen Tata
相关产品推荐
相关产品推荐

