Automation Scripts — Bash, Python, PowerShell
In this tutorial, you'll learn about Automation Scripts. We cover key concepts, practical examples, and best practices.
Automation scripts replace repetitive manual tasks with reliable, repeatable processes — whether you are renaming hundreds of files, deploying servers, or scanning for security threats across thousands of endpoints.
What You'll Learn
In this tutorial, you'll learn Bash scripting for Linux automation (file operations, process management, CRON), Python for cross-platform tasks (file processing, API automation, data pipelines), PowerShell for Windows administration (WMI/CIM, registry, Active Directory), and how to choose the right tool and schedule scripts with CRON, Task Scheduler, and CI/CD triggers.
Why It Matters
A single well-written automation script saves hours of manual work each week. System administrators, DevOps engineers, and security analysts who can automate their workflows are 10x more productive than those who perform tasks manually.
Real-World Use
Durga Antivirus Pro uses a suite of automation scripts for daily tasks: a Bash script that downloads, verifies, and imports new malware signatures; a Python script that scans S3 buckets for exposed credentials and reports findings to a Slack channel; and a PowerShell script that audits Windows endpoints for missing security patches.
flowchart LR A[Automation Scripts] --> B[Bash] A --> C[Python] A --> D[PowerShell] B --> E[Linux Admin] B --> F[CRON Jobs] C --> G[Cross-platform Tasks] C --> H[Data Pipelines] C --> I[API Integrations] D --> J[Windows Admin] D --> K[Active Directory] D --> L[Registry + WMI]
Bash Scripting for Linux Automation
File Processing with Error Handling
#!/bin/bash
# Script: rotate-logs.sh — Compress and archive logs older than 7 days
LOG_DIR="/var/log/scanner"
ARCHIVE_DIR="/var/log/archive"
RETENTION_DAYS=7
TIMESTAMP=$(date +%Y%m%d)
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
if [ ! -d "$LOG_DIR" ]; then
log "ERROR: Log directory $LOG_DIR does not exist"
exit 1
fi
mkdir -p "$ARCHIVE_DIR"
find "$LOG_DIR" -name "*.log" -type f -mtime +$RETENTION_DAYS -print0 | \
while IFS= read -r -d '' file; do
gzip "$file"
mv "${file}.gz" "$ARCHIVE_DIR/"
log "Archived: $file"
done
log "Log rotation complete"
Expected output: Log files older than 7 days are compressed with gzip and moved to the archive directory. Each archived file is logged with a timestamp.
CRON Schedule Integration
# Run every day at 3:00 AM
0 3 * * * /usr/local/bin/rotate-logs.sh >> /var/log/rotate-logs.log 2>&1
# Run security updates check every Monday at 4 AM
0 4 * * 1 /usr/local/bin/check-security-updates.sh
# Run health check every 5 minutes
*/5 * * * * /usr/local/bin/health-check.sh
Expected behavior: CRON executes each script at its scheduled time. Output (including errors) is redirected to log files for auditing and debugging.
Python for Cross-Platform Automation
API Automation with Error Handling
#!/usr/bin/env python3
"""check-endpoints.py — Verify API endpoints are healthy"""
import json
import sys
import urllib.request
import urllib.error
ENDPOINTS = [
"https://api.dodabrowser.com/health",
"https://api.dodazip.com/v1/health",
"https://api.durga-antivirus.com/health",
]
def check_endpoint(url: str) -> dict:
try:
req = urllib.request.Request(url, method="GET")
with urllib.request.urlopen(req, timeout=10) as response:
return {
"url": url,
"status": response.status,
"body": response.read().decode()[:200],
"error": None,
}
except urllib.error.HTTPError as e:
return {"url": url, "status": e.code, "body": None, "error": str(e)}
except urllib.error.URLError as e:
return {"url": url, "status": None, "body": None, "error": str(e.reason)}
def main():
results = [check_endpoint(url) for url in ENDPOINTS]
failures = [r for r in results if r["status"] != 200]
print(json.dumps(results, indent=2))
if failures:
print(f"\nFAILURES: {len(failures)} endpoints returned non-200")
sys.exit(1)
print("\nAll endpoints healthy")
if __name__ == "__main__":
main()
Expected output: JSON array with each endpoint's status code and response body (first 200 chars). If any endpoint returns non-200, the script exits with code 1 and lists failures.
File Processing with pandas
#!/usr/bin/env python3
"""merge-logs.py — Merge and analyze CSV log files"""
import pandas as pd
import glob
import sys
def merge_logs(pattern: str) -> pd.DataFrame:
files = glob.glob(pattern)
if not files:
print(f"No files matching: {pattern}", file=sys.stderr)
sys.exit(1)
dataframes = [pd.read_csv(f) for f in files]
merged = pd.concat(dataframes, ignore_index=True)
return merged
def analyze_scans(df: pd.DataFrame) -> None:
summary = df.groupby("status").agg(
count=("file_hash", "count"),
avg_size=("file_size", "mean"),
).reset_index()
print("Scan Summary by Status:")
print(summary.to_string(index=False))
threats = df[df["threat_detected"] == True]
print(f"\nThreats detected: {len(threats)}")
print("Top threats:")
print(threats["threat_name"].value_counts().head(5).to_string())
if __name__ == "__main__":
df = merge_logs("scanner_logs_*.csv")
analyze_scans(df)
Expected output: Grouped summary of scan statuses with counts and average file sizes. Number of detected threats and top 5 threat names with counts. Empty DataFrames cause early exit with a clear message.
PowerShell for Windows Administration
System Audit Script
# audit-system.ps1 — Audit Windows security settings
$report = @()
# Check Windows Defender status
$defender = Get-MpComputerStatus
$report += [PSCustomObject]@{
Check = "Real-time Protection"
Status = $defender.RealTimeProtectionEnabled
}
# Check installed updates
$updates = Get-HotFix | Where-Object {$_.InstalledOn -gt (Get-Date).AddDays(-30)}
$report += [PSCustomObject]@{
Check = "Recent Updates (30 days)"
Status = "$($updates.Count) updates installed"
}
# Check firewall rules
$firewall = Get-NetFirewallProfile -Profile Domain,Public,Private
foreach ($profile in $firewall) {
$report += [PSCustomObject]@{
Check = "Firewall: $($profile.Name)"
Status = if ($profile.Enabled) { "Enabled" } else { "DISABLED" }
}
}
$report | Format-Table -AutoSize
$report | Export-Csv -Path "security-audit-$((Get-Date).ToString('yyyyMMdd')).csv" -NoTypeInformation
Expected output: Formatted table showing real-time protection status, recent update count, and firewall status for each profile. CSV exported for further analysis. Any DISABLED items indicate security gaps.
Scheduled Task Creation
# Schedule the audit script to run weekly
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-File C:\Scripts\audit-system.ps1"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At "6:00AM"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount
Register-ScheduledTask -TaskName "Weekly Security Audit" `
-Action $action -Trigger $trigger -Principal $principal
Expected behavior: The PowerShell script runs every Monday at 6 AM as the SYSTEM account. The audit CSV is saved to the script's directory with the current date in the filename.
Scripting Language Comparison
| Language | Platform | Best For | Scheduling | Package Ecosystem |
|---|---|---|---|---|
| Bash | Linux/macOS | File ops, process mgmt, pipes | CRON | apt/yum (system packages) |
| Python | All | Data processing, APIs, cross-platform | CRON, Task Scheduler | pip (PyPI, 400k+ packages) |
| PowerShell | Windows (also Linux/macOS) | Windows admin, AD, registry, WMI | Task Scheduler | PSGallery (PowerShell Gallery) |
| Node.js | All | Web scraping, API automation | CRON, pm2 | npm (2M+ packages) |
Common Errors
- Not handling edge cases in Bash — Unset variables cause silent failures. Use
set -uto error on unset variables andset -eto exit on any command failure. - Python script fails with encoding errors on non-ASCII filenames — Always use
encoding="utf-8"when opening files, and usepathlibinstead ofos.pathfor cross-platform path handling. - PowerShell execution policy blocking scripts — By default, PowerShell restricts script execution. Use
Set-ExecutionPolicy RemoteSigned -Scope CurrentUserto allow local scripts. - Hardcoding paths and credentials — Use environment variables (Bash/Python), config files (Python), or secure strings (PowerShell) instead of hardcoding paths, passwords, and API keys.
- Not testing scripts in a sandbox first — A script that deletes files in production should first be tested in a sandbox with
--dry-runor-WhatIfflags. Always validate before destructive operations.
Practice Questions
When should you use Python over Bash for automation? Python is better for complex logic, cross-platform compatibility, data processing (CSV, JSON, XML), API integrations, and any task requiring third-party libraries.
How do you pass arguments to a Bash script? Use
$1,$2, etc. for positional arguments,$@for all arguments, and$#for the argument count. Usegetoptsfor named flags.What is the PowerShell equivalent of
grepin Bash?Select-String(alias:sls). Example:Get-Content log.txt | Select-String "error"is equivalent togrep "error" log.txt.How do you schedule a Python script to run daily? On Linux: CRON. On Windows: Task Scheduler. Cross-platform: schedule library in Python, or systemd timers on Linux.
Challenge
Write a tri-lingual automation suite: a Bash script that finds and archives files older than 30 days (with dry-run mode), an equivalent Python script that also generates a summary report as a CSV, and an equivalent PowerShell script that audits Windows servers. Compare the implementations and note platform-specific considerations.
Mini Project: Automated Threat Detection Pipeline
Build an automated pipeline that simulates Durga Antivirus Pro's threat intelligence workflow:
- Bash script: Download the latest threat feed CSV from a mock URL, verify the file checksum, and extract it
- Python script: Parse the CSV, cross-reference against a local database of known signatures, identify new threats not yet in the database, and generate a report
- PowerShell script (Windows): Check if any new threats correspond to running processes on the system and quarantine them
- Schedule the pipeline: CRON on Linux (every 4 hours), Task Scheduler on Windows (daily)
- Add logging: each step writes to a centralized log file with timestamps and exit codes
- Add alerting: if a critical threat is found, send a notification via email (or Slack webhook)
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro