Ansible处理Windows用户重命名时,循环注册结果遇模板语法错误
问题场景
定义的用户账户变量:
user_accounts: - old_name: account1 new_name: account11 - old_name: account2 new_name: account22
通过以下任务查询账户状态并注册结果:
- name: get the state of the users account win_user: name: "{{ item.old_name }}" state: query loop: "{{ user_accounts }}" register: accounts_to_rename - name: debug debug: var: accounts_to_rename
debug结果显示两个账户状态均为present,但执行重命名任务时出现语法错误:
错误的重命名任务:
- name: W2K19.319_L1_Rename_administrator_account win_shell: "Rename-LocalUser -Name '{{ item.old_name }}' -NewName '{{ item.new_name }}'" loop: "{{ user_accounts | flatten(1) }}" when: accounts_to_rename.results[*].state == present
第一次报错:
"msg": "The conditional check 'accounts_to_rename.results[].state == present' failed. The error was: template error while templating string: unexpected ''."
移除[*]后报错:
"msg": "The conditional check 'accounts_to_rename.results.state == present' failed. The error was: error while evaluating conditional (accounts_to_rename.results.state == present): 'list object' has no attribute."
错误原因
accounts_to_rename.results是一个列表,每个元素对应win_user循环执行的一次结果,包含对应账户的state以及原循环项的item信息。直接用results[*].state或results.state都不符合Ansible Jinja2语法:
[*]不是Jinja2的合法语法,无法直接遍历列表属性results是列表对象,本身没有state属性,必须访问列表中的单个元素才能获取state
解决方案
方案1:匹配循环项对应的注册结果
在重命名任务的when条件中,通过当前循环项的old_name匹配注册结果中对应的账户状态:
- name: Rename Windows user accounts win_shell: "Rename-LocalUser -Name '{{ item.old_name }}' -NewName '{{ item.new_name }}'" loop: "{{ user_accounts }}" when: > (accounts_to_rename.results | selectattr('item.old_name', 'equalto', item.old_name) | map(attribute='state') | first) == 'present'
方案2:直接循环注册结果(更简洁)
因为注册结果的每个元素都包含原循环项的item信息,直接循环accounts_to_rename.results即可,无需再单独遍历user_accounts:
- name: Rename Windows user accounts win_shell: "Rename-LocalUser -Name '{{ item.item.old_name }}' -NewName '{{ item.item.new_name }}'" loop: "{{ accounts_to_rename.results }}" when: item.state == 'present'
方案3:使用Ansible原生模块(推荐)
避免使用win_shell,直接用win_user模块的rename参数完成重命名,更符合Ansible的幂等性和最佳实践:
- name: Rename Windows user accounts win_user: name: "{{ item.item.old_name }}" rename: "{{ item.item.new_name }}" state: present loop: "{{ accounts_to_rename.results }}" when: item.state == 'present'
如果不需要预先查询状态,也可以直接用win_user模块,它会自动判断账户是否存在:
- name: Rename Windows user accounts win_user: name: "{{ item.old_name }}" rename: "{{ item.new_name }}" state: present loop: "{{ user_accounts }}"
内容的提问来源于stack exchange,提问作者Marvelous

