Introduction
The "Unhandled exception while executing module win_user" error is one of the more confusing Ansible errors because it doesn't clearly tell you what's wrong. The root cause is almost always that the password you're setting doesn't meet Windows password complexity requirements. This article explains the error, Windows password policy, and multiple solutions.
The Error
Problematic Playbook
---
- name: Create Windows user
hosts: windows
tasks:
- name: Create local user
ansible.windows.win_user:
name: example
password: password
state: present
Error Output
TASK [Create local user] **************
An exception occurred during task execution. The error was:
fatal: [WindowsServer]: FAILED! => {
"changed": false,
"msg": "Unhandled exception while executing module: Exception calling
\"SetPassword\" with \"1\" argument(s): \"The password does not meet
the password policy requirements. Check the minimum password length,
password complexity and password history requirements.\r\n\""
}
Understanding Windows Password Policy
Windows Server (and domain-joined workstations) enforce password complexity by default:
| Requirement | Default Setting |
|---|---|
| Minimum length | 8 characters (Server 2022: 14 for new installs) |
| Complexity | Enabled |
| History | Remember 24 passwords |
| Maximum age | 42 days |
| Minimum age | 1 day |
Complexity Requirements
When enabled, passwords must contain characters from 3 of 4 categories:
- Uppercase letters (A-Z)
- Lowercase letters (a-z)
- Digits (0-9)
- Special characters (!@#$%^&* etc.)
Additionally:
- Cannot contain the username or parts of the full name
- Must meet minimum length
Solutions
Solution 1: Use a Complex Password
---
- name: Create Windows user
hosts: windows
tasks:
- name: Create local user with complex password
ansible.windows.win_user:
name: deploy_user
password: "Str0ng!P@ssw0rd#2026"
password_never_expires: true
state: present
groups:
- Administrators
Solution 2: Generate Passwords with Ansible
---
- name: Create user with generated password
hosts: windows
tasks:
- name: Generate random password
ansible.builtin.set_fact:
user_password: "{{ lookup('password', '/dev/null length=20 chars=ascii_letters,digits,punctuation') }}"
delegate_to: localhost
- name: Create user
ansible.windows.win_user:
name: deploy_user
password: "{{ user_password }}"
state: present
- name: Save password to vault
ansible.builtin.copy:
content: "{{ user_password }}"
dest: "/tmp/{{ inventory_hostname }}_deploy_password.txt"
mode: "0600"
delegate_to: localhost
Solution 3: Use Ansible Vault for Passwords
# Create encrypted variable
# ansible-vault encrypt_string 'C0mpl3x!Pass#2026' --name 'user_password'
---
- name: Create user with vaulted password
hosts: windows
vars:
user_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
6262653733...
tasks:
- name: Create local user
ansible.windows.win_user:
name: deploy_user
password: "{{ user_password }}"
state: present
Solution 4: Check Policy Before Creating User
---
- name: Create user with policy awareness
hosts: windows
tasks:
- name: Get current password policy
ansible.windows.win_shell: |
$policy = Get-ADDefaultDomainPasswordPolicy -ErrorAction SilentlyContinue
if (-not $policy) {
$policy = net accounts | Select-String "Minimum password length"
}
$policy | ConvertTo-Json
register: password_policy
changed_when: false
failed_when: false
- name: Display password policy
ansible.builtin.debug:
var: password_policy.stdout_lines
- name: Create user with compliant password
ansible.windows.win_user:
name: deploy_user
password: "{{ complex_password }}"
state: present
Common win_user Operations
Create User with Full Options
- name: Create full user account
ansible.windows.win_user:
name: deploy_user
fullname: "Deploy Service Account"
description: "Ansible-managed service account"
password: "{{ vault_deploy_password }}"
password_never_expires: true
user_cannot_change_password: true
account_disabled: false
state: present
groups:
- Remote Desktop Users
- Administrators
Update Existing User Password
- name: Update user password
ansible.windows.win_user:
name: deploy_user
password: "{{ new_password }}"
update_password: always # always (default) or on_create
state: present
Remove a User
- name: Remove user account
ansible.windows.win_user:
name: old_user
state: absent
Create Multiple Users
- name: Create multiple users
ansible.windows.win_user:
name: "{{ item.name }}"
password: "{{ item.password }}"
groups: "{{ item.groups }}"
state: present
loop:
- name: web_admin
password: "W3b@dm1n!2026"
groups: ['Administrators']
- name: db_reader
password: "Db#R3ad3r!2026"
groups: ['Remote Desktop Users']
- name: deploy_svc
password: "D3pl0y$vc!2026"
groups: ['Administrators']
no_log: true # hide passwords from output
Other Causes of win_user Exceptions
WinRM Connection Issues
fatal: [server]: UNREACHABLE! => {
"msg": "winrm connection error"
}
Fix: Verify WinRM is configured:
# inventory
[windows]
win01 ansible_host=192.168.1.100
[windows:vars]
ansible_user=Administrator
ansible_password="{{ vault_win_password }}"
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_winrm_server_cert_validation=ignore
ansible_port=5986
User Already Exists with Different Properties
# Use update_password: on_create to only set password on first creation
- name: Create user (don't reset existing password)
ansible.windows.win_user:
name: existing_user
password: "{{ initial_password }}"
update_password: on_create
state: present
Domain vs Local Users
# Local user (default)
- name: Create local user
ansible.windows.win_user:
name: local_admin
password: "{{ password }}"
state: present
# Domain user — use win_domain_user instead
- name: Create domain user
microsoft.ad.user:
name: domain_admin
password: "{{ password }}"
upn: domain_admin@example.com
state: present
Password Complexity Cheat Sheet
# ❌ Fails complexity — only lowercase
password: simplepassword
# ❌ Fails complexity — only 2 categories (lower + digit)
password: password123
# ❌ Fails length — too short
password: P@ss1
# ✅ Passes — 3+ categories, 12+ chars
password: "Str0ng!Pass2026"
# ✅ Passes — all 4 categories
password: "C0mpl3x#P@ss!"
# ✅ Passphrase style — long, meets all requirements
password: "Ansible-Manages-Windows-2026!"
Best Practices
- Always use Ansible Vault for passwords — never hardcode in plaintext
- Use
no_log: trueon tasks that handle passwords - Set
update_password: on_createto avoid resetting passwords on every run - Test passwords locally first with
net user testuser P@ss /addon Windows - Generate passwords with the
passwordlookup plugin for service accounts - Document password policy in your project README for team awareness
Related Articles
- Ansible user Module Guide
- Ansible Vault Guide
- Ansible Windows Automation
- How to Change User Password
Conclusion
The "Unhandled exception while executing module win_user" error is caused by passwords that don't meet Windows complexity requirements. Use passwords with 12+ characters containing uppercase, lowercase, digits, and special characters. Store passwords in Ansible Vault, use no_log: true, and consider generating random passwords with the password lookup plugin for service accounts.