Finding Ansible Modules with ansible-doc
The exam allows documentation, and `ansible-doc` is faster than any of it - it reads the modules actually installed on the machine in front of you, so it can never describe a version you are not running. Three uses cover almost everything: listing to find a module, `-s` for the parameter summary, and the EXAMPLES section for something you can paste.
Ad-hoc Commands and Modules Guide 8 of 45 Beginner
- OSUbuntu 26.04 LTS
- ansible-core2.20.1
- Python3.14.4
- TimeAbout 13 min
- Reviewed23 August 2026
Written against the versions above. `ansible-doc -l` lists every module from every installed collection. Adding a collection name narrows it: `ansible-doc -l ansible.builtin` is the subset you can rely on being present anywhere, which matters when writing something portable.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| ANS-CTL01 | 192.168.0.36 | Ubuntu 26.04 LTS | Ansible Control Node | 2 Core | 3 GB | 50 GB |
Before you start
- A control node with Ansible installed. No network access is needed - the documentation is in the packages.
- Nothing is created or changed by this guide.
-
The configuration this guide assumes
Everything below runs from the home directory on ANS-CTL01, where two files sit side by side.
~/ansible.cfg- found because Ansible looks for./ansible.cfgin the current directory:[defaults] inventory = ./inventory.ini host_key_checking = False remote_user = sysadmin result_format = yamlresult_format = yamlrather than thestdout_callback = yamlthat older material recommends: that callback lived incommunity.generaland was removed in version 12.0.0, so a playbook run against this config errors out with "The 'community.general.yaml' callback plugin has been removed." The built-in option replaces it and produces the same readable output.~/inventory.ini- two groups and a parent group, so host patterns have something to select:[web] ans-a01 [db] ans-b01 [production:children] web db [web:vars] app_port=8080 [all:vars] ansible_python_interpreter=/usr/bin/python3The short names resolve because
/etc/hostson all three machines carries them, and the control node reaches both managed nodes with an ed25519 key and passwordless sudo.If any of this is unfamiliar, build it first: guide 3, guide 4 and guide 5 cover the three pieces in order.
The last two commands are the check worth running before anything else in this path:
pongfrom both hosts, androotwhen escalation is on.bash Example session cat ~/ansible.cfg[defaults]inventory = ./inventory.inihost_key_checking = Falseremote_user = sysadminresult_format = yamlcat ~/inventory.ini[web]ans-a01 [db]ans-b01 [production:children]webdb [web:vars]app_port=8080 [all:vars]ansible_python_interpreter=/usr/bin/python3grep -E "ans-(ctl|a|b)01" /etc/hosts192.168.0.36 ans-ctl01192.168.0.37 ans-a01192.168.0.38 ans-b01ls -l ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pub-rw------- 1 sysadmin sysadmin 411 Aug 23 07:06 /home/sysadmin/.ssh/id_ed25519-rw-r--r-- 1 sysadmin sysadmin 99 Aug 23 07:06 /home/sysadmin/.ssh/id_ed25519.pubansible-inventory --graph@all: |--@ungrouped: |--@production: | |--@web: | | |--ans-a01 | |--@db: | | |--ans-b01ansible all -m ansible.builtin.pingans-a01 | SUCCESS => { "changed": false, "ping": "pong"}ans-b01 | SUCCESS => { "changed": false, "ping": "pong"}ansible all -m ansible.builtin.command -a "id -un" --becomeans-a01 | CHANGED | rc=0 >>rootans-b01 | CHANGED | rc=0 >>rootExpected resultBoth config files as shown, and
pongplusrootfrom both managed nodes.Success conditionYour control node matches the one every command in this guide was run on.
-
How many modules are there
ansible-doc -l | wc -lSeveral thousand, across every installed collection. Narrowed to the one that is always present:
ansible-doc -l ansible.builtin | wc -la few hundred. That subset is the one worth knowing, because
ansible.builtinships with the engine and is available on any control node you are put in front of.The listing is two columns - name and a one-line description - which is what makes it searchable.
bash Example session ansible-doc -l 2>/dev/null | wc -l9451ansible-doc -l ansible.builtin 2>/dev/null | wc -l71ansible-doc -l ansible.builtin 2>/dev/null | head -8ansible.builtin.add_host Add a host (and alternatively a grou...ansible.builtin.apt Manages apt-packagesansible.builtin.apt_key Add or remove an apt keyansible.builtin.apt_repository Add and remove APT repositoriesansible.builtin.assemble Assemble configuration files from fr...ansible.builtin.assert Asserts given expressions are trueansible.builtin.async_status Obtain status of asynchronous taskansible.builtin.blockinfile Insert/update/remove a text block su...Expected resultA total, a builtin count, and the start of the list.
Success conditionYou know how much is installed and which part is portable.
-
Finding one by what it does
The descriptions are the searchable part, so
grepthem:ansible-doc -l | grep -i firewall ansible-doc -l ansible.builtin | grep -iE 'user|group'This is the fastest way to answer 'is there a module for this', which is the question that matters most under time pressure. Reaching for
shellbecause you could not remember a module name is how playbooks end up non-idempotent.Worth knowing where things live: users, groups, files, services and packages are in
ansible.builtin; firewall and SELinux modules are inansible.posix; a great deal else is incommunity.general.bash Example session ansible-doc -l 2>/dev/null | grep -iE "^ansible.posix|firewall" | head -6ansible.posix.acl ...ansible.posix.at Schedule the ex...ansible.posix.authorized_key ...ansible.posix.firewalld ...ansible.posix.firewalld_info ...ansible.posix.mount ...ansible-doc -l ansible.builtin 2>/dev/null | grep -iE "user|group" | head -6ansible.builtin.group Add or remove groupsansible.builtin.group_by Create Ansible groups based on factsansible.builtin.user Manage user accountsExpected resultMatching module names with their descriptions.
Success conditionYou can find a module from a description of the job.
-
Reading one
The full page gives you the description, every parameter, defaults, choices, and which version added what. It is long.
-sgives the part you usually want:ansible-doc -s ansible.builtin.fileA ready-made YAML snippet with every parameter commented. Delete the lines you do not need and you have a valid task. Under exam pressure this is the single most useful form of the command - it is faster than remembering whether the parameter is
pathordest, and it cannot be out of date.bash Example session ansible-doc ansible.builtin.file 2>/dev/null | head -22> MODULE ansible.builtin.file (/usr/lib/python3/dist-packages/ansible/modules/file.py) Set attributes of files, directories, or symlinks and their targets. Alternatively, remove files, symlinks or directories. Many other modules support the same options as the ansible.builtin.file module - including ansible.builtin.copy, ansible.builtin.template, and ansible.builtin.assemble. For Windows targets, use the ansible.windows.win_file module instead. OPTIONS (red indicates it is required): access_time This parameter indicates the time the file's access time should be set to. Should be `preserve' when no modification is required, `YYYYMMDDHHMM.SS' when using default time format, or `now'. Default is `None' meaning that `preserve' is the default for `state=[file,directory,link,hard]' and `now' is default for `state=touch'. default: null type: stransible-doc -s ansible.builtin.file 2>/dev/null | head -20- name: Manage files and file properties file: access_time: # This parameter indicates the time the file's # access time should # be set to. Should # be `preserve' when # no modification is # required, # `YYYYMMDDHHMM.SS' # when using default # time format, or # `now'. Default is # `None' meaning that # `preserve' is the # default for # `state=[file,directory,link,hard]' # and `now' is # default for # `state=touch'. access_time_format: # When used with `access_time', indicates the timeExpected resultThe full page, then the same module as a YAML skeleton.
Success conditionYou can produce a correct task without recalling a parameter name.
-
The examples are the fast path
Every well-written module ends with worked examples:
ansible-doc ansible.builtin.copy | sed -n '/^EXAMPLES/,/^RETURN/p'These are usually closer to what you want than the parameter list, because they show parameters in combination - which ones go together, and which are mutually exclusive.
After EXAMPLES comes RETURN, describing what the module puts into a registered variable. That is the section to read when you are about to use
register:and need to know whether the field isstdout,stdout_linesor something module-specific.bash ansible-doc ansible.builtin.copy 2>/dev/null | sed -n '/^EXAMPLES/,/^RETURN/p' | head -18Expected resultWorked examples from the module itself.
Success conditionYou can copy a working task rather than composing one.
-
Plugins are documented too, and so are short names
Modules are not the only thing with documentation:
ansible-doc -t lookup -l ansible-doc -t filter -l | wc -l-t lookupcoverslookup('file', ...)- the one used in guide 5 - and-t filterlists the Jinja2 filters available in templates. Both are hard to search for online and trivial to list here.Finally, the short name works:
ansible-doc -s copyresolves to
ansible.builtin.copy, and the full page confirms which module it picked. Short names are fine foransible.builtin; for anything else, write the full name, because two collections may define the same short name and the winner depends on configuration.bash Example session ansible-doc -t lookup -l 2>/dev/null | head -6amazon.aws.aws_account_attribute Look up AWS account at...amazon.aws.aws_collection_constants expose various collect...amazon.aws.aws_service_ip_ranges Look up the IP ranges ...amazon.aws.secretsmanager_secret Look up secrets stored...amazon.aws.ssm_parameter gets the value for a S...ansible.builtin.config Display the 'resolved'...ansible-doc -t lookup ansible.builtin.file 2>/dev/null | sed -n '/^EXAMPLES/,$p' | head -8ansible-doc -t filter -l 2>/dev/null | wc -l259ansible-doc -s copy 2>/dev/null | head -6- name: Copy files to remote locations copy: attributes: # The attributes the resulting filesystem object # should have. To get # supported flags # look at the manansible-doc ansible.builtin.copy 2>/dev/null | grep -m1 "^> "> MODULE ansible.builtin.copy (/usr/lib/python3/dist-packages/ansible/modules/copy.py)Expected resultLookup and filter listings, and a short name resolving to a full one.
Success conditionYou can look up any plugin type, not just modules.
Troubleshooting
module not found in paths.Why: It is in a collection that is not installed.
Fix:
ansible-galaxy collection list, then install the collection.The online docs show a parameter your version rejects.
Why: The website documents the latest release.
Fix:Trust
ansible-doc- it reads what is installed.Two collections provide the same short name.
Why: Short names resolve through search order.
Fix:Use the fully qualified name.
You cannot find a module for the job.
Why: It may genuinely not exist.
Fix:
commandorshellwithcreates=/removes=is the honest fallback - see guide 11.