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
- 命令行启动
C:\WINDOWS\system32> winrm quickconfig
- 直接启动 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