Ansible Ad Hoc Commands — Run Tasks Without Playbooks

Introduction

Ad hoc commands let you run single Ansible tasks from the command line without writing a playbook. They're perfect for quick checks, one-off changes, and troubleshooting. Think of them as the ssh command on steroids — run any module against any number of hosts in parallel.

Syntax

ansible <pattern> -m <module> -a "<arguments>" [options]
ComponentDescription
patternHost or group to target (all, webservers, db01)
-mModule name (default: command)
-aModule arguments
-iInventory file
-bBecome (sudo)
-uRemote user
-kAsk for SSH password
-KAsk for become password
--limitFurther limit hosts
-fForks (parallelism, default: 5)
-oOne-line condensed output
--checkDry run

Connectivity Check

# Ping all hosts
ansible all -m ping

# Ping a specific group
ansible webservers -m ping

# Ping a single host
ansible db01 -m ping -i inventory.yml

# Ping with SSH password prompt
ansible all -m ping -k

Run Shell Commands

# Default module is 'command' (no shell features)
ansible all -a "uptime"
ansible all -a "df -h"
ansible all -a "free -m"

# Use 'shell' module for pipes, redirects, env vars
ansible all -m shell -a "ps aux | grep nginx | wc -l"
ansible all -m shell -a "echo $HOSTNAME"
ansible all -m shell -a "cat /etc/os-release | head -3"

# Run as root
ansible all -m shell -a "cat /etc/shadow | head -1" -b

File Operations

# Copy a file to remote hosts
ansible all -m copy -a "src=/tmp/config.txt dest=/etc/app/config.txt" -b

# Create a directory
ansible all -m file -a "path=/opt/myapp state=directory mode=0755" -b

# Delete a file
ansible all -m file -a "path=/tmp/junk.log state=absent"

# Change ownership
ansible all -m file -a "path=/var/www owner=www-data group=www-data recurse=yes" -b

# Fetch a file from remote
ansible db01 -m fetch -a "src=/var/log/syslog dest=/tmp/logs/"

Package Management

# Install a package (Debian/Ubuntu)
ansible webservers -m apt -a "name=nginx state=present update_cache=yes" -b

# Install a package (RHEL/CentOS)
ansible webservers -m yum -a "name=httpd state=present" -b

# Install on any distro
ansible all -m package -a "name=curl state=present" -b

# Remove a package
ansible all -m apt -a "name=telnet state=absent" -b

# Upgrade all packages
ansible all -m apt -a "upgrade=dist" -b

Service Management

# Start a service
ansible webservers -m service -a "name=nginx state=started" -b

# Restart a service
ansible webservers -m service -a "name=nginx state=restarted" -b

# Enable a service at boot
ansible webservers -m service -a "name=nginx enabled=yes" -b

# Stop a service
ansible webservers -m service -a "name=nginx state=stopped" -b

User Management

# Create a user
ansible all -m user -a "name=deploy state=present shell=/bin/bash" -b

# Create user with SSH key
ansible all -m user -a "name=deploy generate_ssh_key=yes" -b

# Remove a user
ansible all -m user -a "name=olduser state=absent remove=yes" -b

# Add user to groups
ansible all -m user -a "name=deploy groups=sudo,docker append=yes" -b

Gathering Facts

# Get all facts
ansible db01 -m setup

# Filter specific facts
ansible db01 -m setup -a "filter=ansible_distribution*"
ansible db01 -m setup -a "filter=ansible_memtotal_mb"
ansible db01 -m setup -a "filter=ansible_default_ipv4"

Parallelism and Limiting

# Run on 10 hosts at a time
ansible all -a "uptime" -f 10

# Limit to specific hosts
ansible webservers -a "uptime" --limit "web01,web02"

# Limit with pattern
ansible all -a "uptime" --limit "*.example.com"

# One host at a time (serial)
ansible all -a "systemctl restart nginx" -b -f 1

Output Formats

# One-line condensed output
ansible all -a "uptime" -o

# Verbose output
ansible all -m ping -v
ansible all -m ping -vvv   # Very verbose (connection debugging)

# JSON output (for scripting)
ANSIBLE_STDOUT_CALLBACK=json ansible all -m ping

Dry Run and Diff

# Check mode (dry run)
ansible all -m apt -a "name=nginx state=present" -b --check

# Diff mode (show changes)
ansible all -m copy -a "src=config.txt dest=/etc/app/config.txt" -b --diff

# Both together
ansible all -m copy -a "src=config.txt dest=/etc/app/config.txt" -b --check --diff

Common Patterns

# Reboot all servers (one at a time)
ansible all -m reboot -b -f 1

# Check disk space and alert
ansible all -m shell -a "df -h / | tail -1" -o

# Kill a process
ansible webservers -m shell -a "pkill -f 'stuck_process'" -b

# Test connectivity and latency
ansible all -m shell -a "ping -c 1 google.com | tail -1"

# Distribute SSH keys
ansible all -m authorized_key -a "user=deploy key='{{ lookup('file', '~/.ssh/id_rsa.pub') }}'" -b

# Update /etc/hosts
ansible all -m lineinfile -a "path=/etc/hosts line='192.168.1.100 app.local'" -b

Ad Hoc vs Playbooks

FeatureAd HocPlaybooks
SpeedImmediateWrite first
RepeatabilityManualAutomated
ComplexitySingle taskMulti-task
Version controlNoYes
Error handlingLimitedFull
Best forQuick checksProduction

Troubleshooting

IssueSolution
Host unreachableCheck SSH: ansible all -m ping -vvv
Permission deniedAdd -b for sudo, -K for become password
Module not foundInstall collection: ansible-galaxy collection install ...
Too slowIncrease forks: -f 20
Wrong PythonSet ansible_python_interpreter=/usr/bin/python3

Conclusion

Ad hoc commands are your Swiss Army knife for quick Ansible tasks. Use them for troubleshooting, one-off changes, and exploring your infrastructure. For anything repeatable, graduate to playbooks — but keep ad hoc commands in your toolbox for when you need fast results.