Ansible insists on using PowerShell instead of bash

I’ve encountered a challenging problem while working with Ansible and I wanted to ask for your help and advice.

While running an Ansible role that registers Windows hosts in Zabbix, Ansible insists on using PowerShell. This causes errors because PowerShell is not available on the Zabbix server.

Here is a fragment of the error log:

Task path: /runner/project/windows/roles/zabbix_register_windows_host/tasks/main.yml:12
fatal: [10.10.10.10 → zabbix server]: FAILED! => {
“changed”: false,
“module_stderr”: “/bin/sh: line 1: PowerShell: command not found\n”,
“module_stdout”: “”,
“msg”: “MODULE FAILURE\nSee stdout/stderr for the exact error”,
“rc”: 0
}
…ignoring
redirecting (type: connection) ansible.builtin.httpapi to ansible.netcommon.httpapi
ESTABLISH LOCAL CONNECTION FOR USER: root
EXEC /bin/sh -c 'PowerShell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand vAHQAIAAkAD8AKQAgAHsAIABJAGYAIAAoAEcAZQB0AC0AVgBhAHIAaQBhAGIAbABlACAATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAEUAcgBy…
Using module file /root/.ansible/collections/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py
PUT /root/.ansible/tmp/ansible-local-229g6e_e1u/tmp6dn9lqx6 TO /runner/project/.\AnsiballZ_zabbix_host.ps1
EXEC /bin/sh -c 'PowerShell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand UwBlABfAC4ASQBuAHYAbwBjAGEAdABpAG8AbgBJAG4AZgBvAC4AUABvAHMAaQB0AGkAbwBuAE0AZQBzAHMAYQBnAGUAKQAKAH0ACgBFAGwAcwBl…

What I’ve tried:

Setting ansible_shell_executable: /bin/bash and ansible_shell_type: cmd at the task’s level in the role:


  • name: Set API token
    ansible.builtin.set_fact:
    ansible_zabbix_auth_key: “{{ zabbix_auth_key }}”
    ansible_zabbix_url: “{{ ansible_zabbix_url }}”

  • name: Register Windows host in Zabbix
    vars:
    ansible_network_os: community.zabbix.zabbix
    ansible_connection: httpapi
    ansible_httpapi_port: 443
    ansible_httpapi_use_ssl: true
    ansible_httpapi_validate_certs: false
    ansible_zabbix_url_path: “”
    community.zabbix.zabbix_host:
    host_name: “{{ inventory_hostname }}”
    visible_name: “{{ inventory_hostname }}”
    host_groups:
    - “Windows servers”
    link_templates:
    - “Windows by Zabbix agent”

    status: enabled
    state: present
    ignore_errors: yes
    delegate_to: “{{ ansible_zabbix_url }}”
    become: false

Unfortunately, none of these suggestions solved the problem. Ansible still tries to use PowerShell.

What is important to mention,

  • The playbook is run with ansible_shell_type: powershell at the playbook level and we cannot remove it, because the above role is part of a larger playbook where earlier tasks need to have the PowerShell shell set.

How can I work around this issue and what else can I check? Any help would be greatly appreciated! :pray:

We use Zabbix server 7.0.8 and AWX 24.6.1

Thanks in advance for any advice and suggestions!

I guess this is the error

 delegate_to: “{{ ansible_zabbix_url }}”

just remove it from the task. The community.zabbix.zabbix_host: works against the http API of zabbix itself. There is no need that you leave your host/ansible controle node for that task.

This doesn’t “leave” the control node, it uses the network-style httpapi model where the module always runs on the control node but connects to the target host using HTTP. If they don’t delegate the task the module will try to connect to the original target host instead of the Zabbix host, which will not work.

NOTE: I work on same team as OP

@markuman , using delegate_to is a legitimate way to point the module to Zabbix API URL, as documented here: community.zabbix.zabbix_host module – Create/update/delete Zabbix hosts — Ansible Community Documentation

The problem seems to be here:

redirecting (type: connection) ansible.builtin.httpapi to ansible.netcommon.httpapi
ESTABLISH LOCAL CONNECTION FOR USER: root
EXEC /bin/sh -c 'PowerShell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand

It’s using ansible.netcommon.httpapi, (see reply from @flowerysong), and code is to be executed on control node (note the “sh” command).
But for some reason it’s wrapping the actual task code as PowerShell.

I think what we are looking for is to force it to generate the bash code not PowerShell one, that’s why OP tried to override it with forcing shell type and executable.
Any idea why this didn’t work?

Or maybe we just set it in wrong place/way? What is the proper way to force Ansible to generate sh code?

I’m not familiar with zabbix or ansible.netcommon.httpapi, but have you confirmed the content of “ansible_zabbix_url”

- debug:
    var: ansible_zabbix_url

Your set_fact line is putting the contents of ansible_zabbix_url back in the same variable, unless that is an error made only in your post, and not in your actual playbook.

good point, however this was just edit for this post.

Anyway, this does not affect the issue.

If this is a bug as described, You can try running another play at the same point instead of doing the delegate_to. You’d then iterate through the windows hosts, which I assume are in a group of their own and add them that way. You can register a var to ensure you only add hosts that have completed the play up to that point. You’d have to modify your role to expect that the play is being run with the zabbix host as the original target. Example play without using a role.

- name:
  hosts: <windows hosts>
  tasks:
    ...
    - ansible.builtin.set_fact:
        host_up: true

- name: Add windows hosts to zabbix
  hosts: <zabbix_host>
  vars:
    ansible_network_os: community.zabbix.zabbix
    ansible_connection: httpapi
    ansible_httpapi_port: 443
    ansible_httpapi_use_ssl: true
    ansible_httpapi_validate_certs: false
    ansible_zabbix_url_path: “”
  tasks:
    - name: Register Windows host in Zabbix
      when: 'hostvars[win_hostname]["host_up"] is defined'
      community.zabbix.zabbix_host:
        host_name: “{{ win_hostname }}”
        visible_name: “{{ win_hostname }}”
        host_groups:
        - “Windows servers”
        link_templates:
        - “Windows by Zabbix agent”
        …
        status: enabled
        state: present
      ignore_errors: yes
      become: false
      loop: '{{ groups[<name of windows host groups>] }}'
      loop_control:
        loop_var: 'win_hostname'

- name: Start other tasks of the original play here
  hosts: <windows hosts>
  ...

For parallelism, you can do the above with the windows hosts as the original target still, but change the ansible_shell_type for the var at the play level, and try to do the delegate_to again.

Since you are iterating through the Windows hosts, some of the connection variables could be getting used fot the connection to localhost. Can you post some sanitized inventory? This should not normally be a problem, unless you have explicitly added localhost to your inventory.