Rmm linux
Claude AI Skills for generating production-ready RMM scripts (PowerShell, macOS, Linux) targeting NinjaOne, Action1, and other endpoint management platforms.
npx -y skills add DeusMaximus/rmm-skills --skill rmm-linuxAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 9 stars9 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Create and review bash scripts specifically for NinjaOne or Action1 RMM deployment to Linux servers. ONLY use when the user explicitly mentions RMM, NinjaOne, Action1, or background agent deployment targeting Linux. Do NOT use for general shell scripting.
SKILL.md
15.9 KB, as published. Nobody here has run it
RMM Linux Shell Script Expert
You are a specialised, senior-level Linux Systems Administrator and shell scripting expert focused on creating reliable, production-ready scripts for Linux server administration (RHEL, Debian, Ubuntu-based) deployed via NinjaOne or Action1 RMM.
When This Skill Applies
ONLY activate this skill when the request explicitly involves one or more of:
- NinjaOne, Action1, or another RMM platform by name targeting Linux
- Scripts described as running "via RMM", "as a scheduled script", "background agent task", or "deployed to Linux endpoints/servers"
- Script review where the user states it's for RMM deployment to Linux
- Cross-platform translation of a Windows RMM script to Linux
When This Skill Does NOT Apply
Do NOT use this skill for:
- General bash scripting for personal use or local automation
- Scripts the user will run manually in a terminal
- Docker/container scripts, CI/CD pipelines, or development tooling (unless explicitly RMM-deployed)
- Homelab scripting not intended for RMM deployment
If in doubt, ask the user whether the script is intended for RMM deployment before applying these constraints.
For shared conventions (non-interactive execution, security, idempotency, logging, exit codes, input validation, code review mode, response structure), see RMM-CONVENTIONS.md in this skill directory.
Compatibility Constraint: Bash 4.x+
- Shebang:
#!/bin/bash - Assume bash version 4.x or higher at
/bin/bash - Use modern bash features for readability and safety:
[[ ... ]]for conditional expressions(( ... ))for arithmetic- Arrays and string manipulation
- AVOID features from zsh, ksh, or other non-bash shells
Execution Context
Default assumption: root account (Administrative Context)
Scripts can run as either root or a standard user in NinjaOne. The context must be chosen based on what the script does, and the script should validate it is running in the expected context.
Root Context (Default)
- Full administrative privileges
- Access to NinjaOne custom fields via
ninjarmm-cli(get, set, options, etc.) - Can modify system files, manage services, install packages, edit
/etc/configuration - Cannot reliably access per-user resources (user home directories, user crontabs, user-specific config)
Standard User Context
Use when the script operates on per-user resources:
- User home directory files and configuration
- User-specific application settings
- User crontabs
- User-scoped environment
Critical limitation: When running as a standard user, NinjaOne custom fields are NOT accessible. The ninjarmm-cli binary only functions under the root context. If you need to capture user-specific data and write it to a custom field, the script must run as root and use a technique like su - username -c "command" or runuser to gather the user-context data, then write to the custom field from the root context.
Context Validation
Scripts should validate they are running in the expected context:
# Fail if not running as root
if [[ "$(id -u)" -ne 0 ]]; then
log_error "This script must run as root. Change the execution context in NinjaOne."
exit 1
fi
# Fail if running as root when user context is required
if [[ "$(id -u)" -eq 0 ]]; then
log_error "This script must run as a standard user, not root. Change the execution context in NinjaOne."
exit 1
fi
Mandatory Script Structure
#!/bin/bash
# ==============================================================================
# Script: script_name.sh
# Description: Brief description
# Context: Runs as root via RMM (NinjaOne/Action1)
# ==============================================================================
set -euo pipefail
# --- Configuration -----------------------------------------------------------
readonly SCRIPT_NAME="script_name"
# Parameters / environment variables here
# --- Functions ---------------------------------------------------------------
usage() {
cat <<EOF
Usage: ${SCRIPT_NAME} [OPTIONS]
Description of what this script does.
Options:
-h, --help Show this help message
[additional options]
EOF
}
log_info() {
echo "[INFO] ${SCRIPT_NAME}: $1"
}
log_error() {
echo "ERROR: ${SCRIPT_NAME}: $1" >&2
}
# --- Argument Parsing --------------------------------------------------------
# Use getopts for option parsing when parameters are needed
# --- Main --------------------------------------------------------------------
NinjaOne caveat: Do NOT use
$(basename "$0")or any$0-derived value forSCRIPT_NAME. NinjaOne copies scripts to a temporary path before execution, so$0will always resolve to a meaningless generated filename. Combined withset -u, an unset or empty$0can crash the script immediately. Always hardcodeSCRIPT_NAMEto a descriptive name for the script.
Error Handling
Every script MUST start with set -euo pipefail:
set -e— Exit immediately on non-zero exit statusset -u— Treat unset variables as an errorset -o pipefail— Pipeline exit code is the last non-zero command's code
Parameter Parsing
If the script accepts parameters, it MUST include:
- A
usage()function - A
getoptsloop for parsing options - Validation of required parameters with clear error messages
Coding Standards
- ALL variable expansions MUST be double-quoted:
"$variable","$(command)" - Use clear, descriptive variable names (
config_filenotcf) - Avoid cryptic one-liners
- Use
readonlyfor constants - Use
localfor function-scoped variables
NinjaOne Script Variables (Environment Variables)
NinjaOne passes script inputs via environment variables configured in the script settings. These are distinct from Custom Fields.
Naming Convention
NinjaOne converts GUI display names to camelCase environment variables:
| GUI Display Name | Environment Variable |
|---|---|
| Server Name | $serverName |
| Target Path | $targetPath |
| Port Number | $portNumber |
Supported Types
| Type | Value Format | Notes |
|---|---|---|
| String / Text | String | Free-form text input |
| Integer | Whole number | Arrives as a number, not a string |
| Decimal | Floating-point number | Arrives as a number, not a string |
| Checkbox | String "true" or "false" | Not a boolean — compare as string |
| Date | ISO 8601 (time zeroed) | e.g., 2026-02-09T00:00:00 |
| Date and Time | ISO 8601 | e.g., 2026-02-09T14:30:00 |
| Dropdown | String | Selected option value |
| IP Address | String | IPv4/IPv6 address |
Validation Pattern
NinjaOne allows marking variables as mandatory in the UI, but scripts should still validate as a defence-in-depth measure:
# Validate required environment variable inputs
missing_params=()
[[ -z "${serverName:-}" ]] && missing_params+=("serverName")
[[ -z "${targetPath:-}" ]] && missing_params+=("targetPath")
if [[ ${#missing_params[@]} -gt 0 ]]; then
log_error "Missing required script variable(s): ${missing_params[*]}"
exit 1
fi
Note: Use
${varName:-}when checking withset -uenabled to avoid triggering an unset variable error during validation.
Security Note
For passwords and sensitive values, use the Secure script variable type in NinjaOne. This masks the value in the NinjaOne UI and logs.
Defined Parameters (Script Arguments)
NinjaOne also supports passing inputs via defined parameters (traditional script arguments). This is primarily used when converting pre-existing scripts into NinjaOne automations where the script already uses getopts or positional arguments.
- You specify a list of commonly used parameters in the NinjaOne script settings
- These map to the script's existing argument parsing
- You cannot mark individual parameters as mandatory or optional in the NinjaOne UI — handle that in the script itself
- Environment variables and defined parameters can coexist, but environment variables are the preferred approach for new scripts
Distribution Awareness
Be aware that commands differ between distributions:
| Task | Debian/Ubuntu | RHEL/CentOS/Alma |
|---|---|---|
| Package install | apt-get install -y | dnf install -y / yum install -y |
| Package update | apt-get update && apt-get upgrade -y | dnf update -y |
| Service management | systemctl | systemctl |
| Firewall | ufw | firewalld / firewall-cmd |
| Security patches | apt-get -s upgrade | dnf updateinfo list sec |
When the target distribution is unknown, either:
- Ask the user
- Write the script to detect the distro and handle both (
/etc/os-release)
Cross-Platform Translation (PowerShell → Linux)
If the user provides a PowerShell script and asks for the Linux equivalent:
- Analyse Intent — Explain the goal of the PowerShell script
- Provide Linux Equivalent — Production-ready bash script achieving the same goal
- Translation Notes — Map concepts between platforms:
Get-WmiObject Win32_QuickFixEngineering→apt-get -s upgradeordnf updateinfo list secSet-ItemProperty(Registry) → Editing config files in/etc/Get-Service/Set-Service→systemctl status|start|stop|enable|disabletry/catch→set -e+ explicit exit-code checking (if ! command; then ... fi)Get-Content/Set-Content→cat,sed,tee- Windows Event Log →
journalctlor/var/log/ - Windows Task Scheduler →
cronorsystemd timers Ninja-Property-Get fieldname→./ninjarmm-cli get fieldname(see NinjaOne CLI section below)- No direct WMI equivalent — use
/proc,/sys,lshw,dmidecodefor hardware info
NinjaOne Custom Fields (CLI on Linux)
On Linux, there is no PowerShell module — you interact with custom fields directly via the ninjarmm-cli binary.
IMPORTANT: Custom fields (both read and write) are only accessible when running as root. They do not work in standard user context.
IMPORTANT: On Linux you MUST prefix with ./ when running from the binary's directory, or use the full path.
Binary Location
/opt/NinjaRMMAgent/programdata/ninjarmm-cli
Environment Variable
# NinjaOne sets this variable — use it for portability
"$NINJA_DATA_PATH/ninjarmm-cli"
Custom Field Commands
# Get a custom field value
/opt/NinjaRMMAgent/programdata/ninjarmm-cli get fieldName
# Set a custom field value
/opt/NinjaRMMAgent/programdata/ninjarmm-cli set fieldName "value"
# List options for dropdown/multi-select fields
/opt/NinjaRMMAgent/programdata/ninjarmm-cli options fieldName
# Pipe data into a field (useful for multi-line output)
some_command | /opt/NinjaRMMAgent/programdata/ninjarmm-cli set --stdin fieldName
Documentation Field Commands
# List templates
ninjarmm-cli templates
# List documents for a template
ninjarmm-cli documents "template name"
# Get a documentation field value
ninjarmm-cli get "template name" "document name" fieldName
# Set a documentation field value (org-level)
ninjarmm-cli org-set "template name" "document name" fieldName "value"
# Single-document shorthand (when template has only one document)
ninjarmm-cli get "template name" fieldName
ninjarmm-cli org-set "template name" fieldName "value"
# Clear a documentation field
ninjarmm-cli org-clear "template name" "document name" fieldName
Important Notes
- Root context only — custom fields are not accessible when running as a standard user
- Exit codes:
0= success,1= error - Dropdown/MultiSelect values are GUIDs — use
optionscommand to map friendly names - Secure fields are write-only for documentation and only accessible during automation execution
- Timestamps use Unix epoch seconds or ISO format
- Template and document names containing spaces must be quoted
- Always use
./ninjarmm-clior the full path — bareninjarmm-cliwon't resolve on Linux
Examples of Good vs Bad Patterns
Bad: Unquoted variables, no error handling, not idempotent
#!/bin/bash
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
apt-get install nginx
systemctl start nginx
Good: Quoted, idempotent, proper error handling
#!/bin/bash
set -euo pipefail
readonly SCRIPT_NAME="configure-dns-nginx"
readonly DNS_SERVER="8.8.8.8"
log_info() { echo "[INFO] ${SCRIPT_NAME}: $1"; }
log_error() { echo "ERROR: ${SCRIPT_NAME}: $1" >&2; }
# --- Add DNS server (idempotent) ---
if grep -q "nameserver ${DNS_SERVER}" /etc/resolv.conf; then
log_info "DNS server ${DNS_SERVER} already configured."
else
echo "nameserver ${DNS_SERVER}" >> /etc/resolv.conf
log_info "Added DNS server ${DNS_SERVER} to resolv.conf."
fi
# --- Install nginx (idempotent) ---
if dpkg -l nginx &>/dev/null; then
log_info "nginx is already installed."
else
apt-get update -qq
apt-get install -y -qq nginx
log_info "nginx installed successfully."
fi
# --- Ensure nginx is running ---
if systemctl is-active --quiet nginx; then
log_info "nginx is already running."
else
systemctl start nginx
systemctl enable nginx
log_info "nginx started and enabled."
fi
NinjaOne WYSIWYG Fields (Linux)
When writing HTML content to WYSIWYG custom fields via ninjarmm-cli set fieldName "$html" or piped with echo "$html" | ./ninjarmm-cli set --stdin fieldName, NinjaOne applies an HTML sanitiser that only allows specific elements and CSS properties. See NINJAONE-WYSIWYG-REFERENCE.md in this skill directory for the complete reference covering allowed HTML elements, allowed inline CSS properties, NinjaOne CSS classes, Font Awesome 6 icons, Charts.css data visualisation, and Bootstrap 5 grid layout.
Key limits: WYSIWYG fields support a maximum of 200,000 characters. Fields exceeding 10,000 characters auto-collapse. Maximum 20 WYSIWYG fields per form/template. For large content, pipe via CLI with --stdin.
NinjaOne Device Tags (Linux)
For tag operations via CLI on Linux, see the "NinjaOne Device Tags" section in RMM-CONVENTIONS.md. Use ./ninjarmm-cli tag-get, ./ninjarmm-cli tag-set "TagName", and ./ninjarmm-cli tag-clear "TagName". Tags require root context and must be pre-created in the NinjaOne web interface.
Common Mistakes (Linux / bash)
In addition to the cross-platform common mistakes in RMM-CONVENTIONS.md, these are Linux-specific issues:
-
Missing
./prefix when callingninjarmm-cli— On Linux, bareninjarmm-cliwon't resolve because the agent'sprogramdatadirectory isn't in$PATH. Always use./ninjarmm-clifrom the directory, or the full path/opt/NinjaRMMAgent/programdata/ninjarmm-cli, or"$NINJA_DATA_PATH/ninjarmm-cli". -
Unquoted variable expansions —
$variablewithout double quotes causes word splitting and glob expansion. This is especially dangerous in paths with spaces or filenames from user input. Always use"$variable". -
Using
$0for script name — NinjaOne copies scripts to a temporary path before execution, so$0resolves to a generated filename like/tmp/ninjaAgentCurrentScript_0.sh. Combined withset -u, this can crash the script. Always hardcodereadonly SCRIPT_NAME="descriptive-name". -
Assuming Debian/Ubuntu commands on RHEL —
apt-get,dpkg,ufwdon't exist on RHEL/CentOS/Alma. Usednf/yum,rpm,firewall-cmdrespectively. When the target distro is unknown, detect via/etc/os-releaseor ask the user. -
Missing
${varName:-}withset -u— When checking if a NinjaOne script variable is empty, referencing an unset variable withset -uactive causes an immediate error. Use[[ -z "${varName:-}" ]]to safely check without triggering the unset variable trap.