pywinrm 批量管理 Windows

作者:JunLan 发布时间: 2025-12-22 阅读量:9 评论数:0

Ansible To Windows

安装软件的组策表位置:\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\企业微信

D:\Users\011582>reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\企业微信" /v DisplayVersion

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\企业微信
    DisplayVersion    REG_SZ    4.1.38.6011

官网手册:https://docs.ansible.org.cn/ansible/latest/os_guide/windows_winrm.html

pywinrm

pywinrm 是一个基于requests库,用于 Windows 远程管理 (WinRM) 服务的 Python 客户端(库)。它允许您从任何可以运行 Python 的机器上调用目标 Windows 机器上的命令。

常用 pywinrm 相关的 Ansible 模块:

# 列出所有已加载的 Windows 模块
  ansible-doc -t module -l | grep '^ansible.windows.'

    win_ping	测试 Windows 主机连接性
    win_command	执行 CMD 命令
    win_shell	执行 PowerShell 命令
    win_copy	复制文件到 Windows
    win_get_url	下载文件到 Windows
    win_package	安装/卸载 MSI 或 EXE 软件
    win_service	管理 Windows 服务
    win_reboot	重启 Windows 主机

# 查看模块的用法
 ansible-doc win_whoami

WinRM

WinRM(Windows Remote Management) 是 Windows 使用的远程管理协议,用于与另一台服务器进行远程通信。它是一种基于 SOAP 的协议,通过 HTTP/HTTPS 进行通信,并包含在所有最新的 Windows 操作系统中。自 Windows Server 2012 起,WinRM 默认启用,但在大多数情况下,需要额外的配置才能将 WinRM 与 Ansible 一起使用。

Ansible 使用 pywinrm 包通过 WinRM 与 Windows 服务器通信。它不是 Ansible 包默认安装的。

准备工作

widnows 启用 winrm 服务

启动winrm

  1. 命令行启动
C:\WINDOWS\system32> winrm quickconfig
  1. 直接启动 Windows Remote Management (WS-Management) 服务

验证启用成功

PS C:\Windows\system32> netstat -ano | findstr 598
  TCP    0.0.0.0:5985           0.0.0.0:0              LISTENING       4

PS C:\Windows\system32> Get-Service winrm

Status   Name               DisplayName
------   ----               -----------
Running  winrm              Windows Remote Management (WS-Manag...

PS C:\Windows\system32> winrm g winrm/config
Config
    MaxEnvelopeSizekb = 500
    MaxTimeoutms = 60000
    MaxBatchItems = 32000
    MaxProviderRequests = 4294967295
    Client
        NetworkDelayms = 5000
        URLPrefix = wsman
        AllowUnencrypted = false
        Auth
            Basic = true
            Digest = true
            Kerberos = true
            Negotiate = true
            Certificate = true
            CredSSP = false
        DefaultPorts
            HTTP = 5985
            HTTPS = 5986
        TrustedHosts = *
    Service
        RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)
        MaxConcurrentOperations = 4294967295
        MaxConcurrentOperationsPerUser = 1500
        EnumerationTimeoutms = 240000
        MaxConnections = 300
        MaxPacketRetrievalTimeSeconds = 120
        AllowUnencrypted = false
        Auth
            Basic = false
            Kerberos = true
            Negotiate = true
            Certificate = false
            CredSSP = false
            CbtHardeningLevel = Relaxed
        DefaultPorts
            HTTP = 5985
            HTTPS = 5986
        IPv4Filter = *
        IPv6Filter = *
        EnableCompatibilityHttpListener = false
        EnableCompatibilityHttpsListener = false
        CertificateThumbprint
        AllowRemoteAccess = true
    Winrs
        AllowRemoteShellAccess = true
        IdleTimeout = 7200000
        MaxConcurrentUsers = 2147483647
        MaxShellRunTime = 2147483647
        MaxProcessesPerShell = 2147483647
        MaxMemoryPerShellMB = 2147483647
        MaxShellsPerUser = 2147483647
        
# 查看启用了哪些认证方式
C:\WINDOWS\system32> winrm get winrm/config/service/auth
Auth
    Basic = false
    Kerberos = true
    Negotiate = true
    Certificate = false
    CredSSP = false
    CbtHardeningLevel = Relaxed
    
C:\WINDOWS\system32> winrm set winrm/config/service/auth @{Basic="true"}
C:\WINDOWS\system32> winrm set winrm/config/service @{AllowUnencrypted="true"}
Restart-Service WinRM

安装 pywinrm 模块

# rocky 默认没有安装 pip 工具
dnf install python-pip -y && pip install pywinrm

安装 ansible 软件

dnf install epel-release -y && dnf install ansible -y && ansible --version

测试使用

编辑主机清单

[root@localhost ~]# vim /etc/ansible/hosts
[test]
10.1.74.23  ansible_connection=winrm ansible_port=5985 ansible_winrm_transport=ntlm ansible_user='snimay\011582' ansible_password='!Major'

[root@localhost ~]# ansible all --list
  hosts (1):
    10.1.74.23

验证成功连接 windows 主机

ansible all -m win_whoami

[root@localhost ~]# ansible test -m win_ping
10.1.74.23 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

# 获取远程主机的主机名
[root@localhost ~]# ansible test -m win_shell -a "hostname"
10.1.74.23 | CHANGED | rc=0 >>
IT-001016

# 结束远程主机进程
[root@localhost ~]# ansible all -m win_command -a "taskkill /IM fdm.exe /F"
10.1.74.23 | CHANGED | rc=0 >>
SUCCESS: The process "fdm.exe" with PID 28796 has been terminated.

ansible.cfg

[root@localhost ~]# vim /etc/ansible/ansible.cfg
[defaults]
transport = winrm
remote_user = snimay
ask_pass = True

rclone配置

挂载smb共享到ansible主机,用于拷贝文件到远程主机安装。

拉取 rclone 镜像
mkdir -p /data/rclone/ && cd /data/rclone/ && docker run --rm rclone/rclone:1.70.2 version
添加 smb 存储
[root@localhost rclone]# docker run --rm -it -v /data/rclone:/config/rclone rclone/rclone:1.70.2 config
2025/07/01 09:09:00 NOTICE: Config file "/config/rclone/rclone.conf" not found - using defaults
No remotes found, make a new one?
n) New remote
s) Set configuration password
q) Quit config
n/s/q> n

Enter name for new remote.
name> smbshare

Option Storage.
Type of storage to configure.
Choose a number from below, or type in your own value.
49 / SMB / CIFS
   \ (smb)
Storage> 49

Option host.
SMB server hostname to connect to.
E.g. "example.com".
Enter a value.
host> 10.1.90.3

Option user.
SMB username.
Enter a value of type string. Press Enter for the default (root).
user> 011582

Option port.
SMB port number.
Enter a signed integer. Press Enter for the default (445).
port>

Option pass.
SMB password.
Choose an alternative below. Press Enter for the default (n).
y) Yes, type in my own password
g) Generate random password
n) No, leave this optional password blank (default)
y/g/n> y
Enter the password:
password:
Confirm the password:
password:

Option domain.
Domain name for NTLM authentication.
Enter a value of type string. Press Enter for the default (WORKGROUP).
domain> snimay

Option spn.
Service principal name.
Rclone presents this name to the server. Some servers use this as further
authentication, and it often needs to be set for clusters. For example:
    cifs/remotehost:1020
Leave blank if not sure.
Enter a value. Press Enter to leave empty.
spn>

Option use_kerberos.
Use Kerberos authentication.
If set, rclone will use Kerberos authentication instead of NTLM. This
requires a valid Kerberos configuration and credentials cache to be
available, either in the default locations or as specified by the
KRB5_CONFIG and KRB5CCNAME environment variables.
Enter a boolean value (true or false). Press Enter for the default (false).
use_kerberos>

Edit advanced config?
y) Yes
n) No (default)
y/n>

Configuration complete.
Options:
- type: smb
- host: 10.1.90.3
- user: 011582
- pass: *** ENCRYPTED ***
- domain: snimay
Keep this "smbshare" remote?
y) Yes this is OK (default)
e) Edit this remote
d) Delete this remote
y/e/d>

Current remotes:

Name                 Type
====                 ====
smbshare             smb

e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> q

[root@localhost rclone]# cat rclone.conf
[smbshare]
type = smb
host = 10.1.90.3
user = 011582
pass = vGoYLiD5bBU3iuZG46KNn90HXQZgcw
domain = snimay
compose.yaml
cat << 'EOF' > compose.yaml
services:
  rclone:
    cap_add:
      - SYS_ADMIN  # 允许容器执行许多系统管理操作,比如挂载文件系统。
    command: >  # >符号是一个 YAML 的多行字符串指示符,允许写多行命令。
      mount smbshare: /mnt --allow-other --vfs-cache-mode writes --allow-non-empty --log-level NOTICE
    container_name: rclone
    devices:
      - /dev/fuse  # 将宿主机的 `/dev/fuse` 设备映射到容器中,rclone mount 需要 /dev/fuse 设备才能正常工作。
    environment:
      TZ: Asia/Shanghai
    image: rclone/rclone:1.70.2
    restart: unless-stopped
    security_opt:  # 设置容器的安全选项
      - apparmor:unconfined  #  AppArmor 是一个 Linux 安全模块,可以限制进程的权限。 unconfined 表示不对容器进行任何 AppArmor 限制
    volumes:
      - /opt/smb_share:/mnt:rshared
      - ./rclone.conf:/config/rclone/rclone.conf
EOF
运行 rclone
 docker compose down && docker compose up -d
验证挂载
[root@localhost ~]# ls -l /opt/smb_share/番山常用软件/WeCom/
总用量 1346654
-rw-r--r--. 1 root root 552822432  6月 23 09:31 WeCom_4.1.38.6006.exe
-rw-r--r--. 1 root root 826150912  7月  2 15:15 WeCom_4.1.38.6006.msi

[root@localhost ~]# df -Th
文件系统          类型       容量    已用  可用   已用%     挂载点
smbshare:     fuse.rclone  1.0P     0  1.0P    0%   /opt/smb_share

远程安装软件

安装企业微信

playbook 文件(yaml)

cat << 'EOF' > /root/test.yaml
- name: 复制文件到 C:\tmp
  hosts: all  # 替换为你的主机组名
  tasks:
    - name: 确保目标目录存在
      win_file:
        path: C:\tmp
        state: directory  # 自动创建目录(如果不存在)

    - name: 复制 WeCom 安装包
      win_copy:
        src: /opt/smb_share/番山常用软件/WeCom/WeCom_4.1.38.6006.exe
        dest: C:\tmp\WeCom_4.1.38.6006.exe

    - name: 安装 WeCom
      win_package:
        path: C:\tmp\WeCom_4.1.38.6006.exe
        arguments:  # 可选,命令行参数,例如 "/S" 表示静默安装
          - "/S"
        #  - "/D=C:\Program Files\WeCom" #自定义安装目录
        state: present  # 确保已安装
        # product_id:  # 如果是 MSI,可以指定 product_id 来进行升级/卸载作
EOF

执行 playbook

ansible-playbook /root/test.yaml

评论