Schedule Python Scripts to Run Automatically: Complete Guide
You've built a Python script that saves hours of work. But you still have to remember to run it. Every day. Or every Monday. Or the first of each month.
That's not true automation. Let's fix it.
Today you'll learn to schedule scripts to run automatically—no human intervention required.
What You'll Learn
- Using Task Scheduler on Windows
- Using cron on macOS/Linux
- Python-based scheduling with schedule library
- Running scripts at startup
- Handling errors and logging for unattended execution
Prerequisites
- Python 3.8 or higher
- A Python script you want to schedule
- Administrator access to your computer
The Problem
Manual script execution means:
- You have to remember to run it
- If you're sick, on vacation, or busy—it doesn't run
- Timing is inconsistent
- You waste time on routine execution
The Solution
System schedulers that run your scripts automatically:
- Windows: Task Scheduler
- macOS/Linux: cron
- Cross-platform: Python schedule library or systemd
Method 1: Windows Task Scheduler
Task Scheduler is built into Windows and perfect for automation.
Step 1: Find Your Python Path
First, we need to know where Python is installed:
1where python
Copy the path (e.g., C:\Users\YourName\AppData\Local\Programs\Python\Python311\python.exe)
Step 2: Create the Scheduled Task
- Press
Win + R, typetaskschd.msc, press Enter - Click Create Basic Task in the right panel
- Name: "Daily Report Generator" (or whatever describes your script)
- Description: "Runs the Python report script every day at 8 AM"
- Click Next
Step 3: Set the Trigger
- Choose when: Daily, Weekly, or Monthly
- Set the start time (e.g., 8:00 AM)
- For daily: set recurrence (every 1 day)
- Click Next
Step 4: Set the Action
- Select Start a program
- Click Next
- Program/script: Paste your Python path
C:\Users\YourName\AppData\Local\Programs\Python\Python311\python.exe - Add arguments: Full path to your script
"C:\Scripts\my_automation.py" - Start in (optional): Your script's directory
C:\Scripts - Click Next, then Finish
Step 5: Configure Additional Settings
- Find your task in Task Scheduler Library
- Right-click → Properties
- General tab: Check "Run whether user is logged on or not"
- Conditions tab: Uncheck "Start only if computer is on AC power" for laptops
- Settings tab: Check "Run task as soon as possible after a scheduled start is missed"
Testing Your Task
Right-click the task → Run to test immediately.
Method 2: macOS/Linux with cron
Cron is the standard scheduler for Unix systems.
Step 1: Open the Crontab Editor
1crontab -e
This opens your personal crontab in the default editor (usually nano or vim).
Step 2: Understand Cron Syntax
* * * * * command │ │ │ │ │ │ │ │ │ └── Day of week (0-7, where 0 and 7 are Sunday) │ │ │ └──── Month (1-12) │ │ └────── Day of month (1-31) │ └──────── Hour (0-23) └────────── Minute (0-59)
Step 3: Add Your Schedule
Common schedule examples:
1# Run every day at 8:00 AM20 8 * * * /usr/bin/python3 /home/user/scripts/my_script.py34# Run every Monday at 9:00 AM50 9 * * 1 /usr/bin/python3 /home/user/scripts/weekly_report.py67# Run every hour80 * * * * /usr/bin/python3 /home/user/scripts/hourly_check.py910# Run every 15 minutes11*/15 * * * * /usr/bin/python3 /home/user/scripts/monitor.py1213# Run first day of every month at midnight140 0 1 * * /usr/bin/python3 /home/user/scripts/monthly_report.py1516# Run Monday through Friday at 6 PM170 18 * * 1-5 /usr/bin/python3 /home/user/scripts/end_of_day.py
Step 4: Save and Verify
Save the crontab (in nano: Ctrl+O, Enter, Ctrl+X)
Verify your crontab:
1crontab -l
Important: Use Full Paths
Cron runs in a minimal environment. Always use:
- Full path to Python:
/usr/bin/python3 - Full path to your script:
/home/user/scripts/my_script.py
Find your Python path:
1which python3
Cron Output and Logging
By default, cron sends output via email. Redirect to a log file instead:
10 8 * * * /usr/bin/python3 /home/user/scripts/my_script.py >> /home/user/logs/my_script.log 2>&1
The 2>&1 redirects errors to the same file.
Method 3: Python schedule Library
For cross-platform scheduling or when you need more control:
1pip install schedule
Basic Usage
1#!/usr/bin/env python32"""3Scheduled Task Runner - Run functions on a schedule.4Author: Alex Rodriguez5"""67import schedule8import time9from datetime import datetime101112def job_daily_report():13 """Example job: Generate daily report."""14 print(f"[{datetime.now()}] Running daily report...")15 # Your automation code here161718def job_hourly_check():19 """Example job: Hourly system check."""20 print(f"[{datetime.now()}] Running hourly check...")21 # Your automation code here222324def job_weekly_backup():25 """Example job: Weekly backup."""26 print(f"[{datetime.now()}] Running weekly backup...")27 # Your automation code here282930# Schedule the jobs31schedule.every().day.at("08:00").do(job_daily_report)32schedule.every().hour.do(job_hourly_check)33schedule.every().monday.at("06:00").do(job_weekly_backup)3435# Also supports:36# schedule.every(10).minutes.do(job)37# schedule.every().wednesday.at("13:15").do(job)38# schedule.every().day.at("10:30:00").do(job) # With seconds394041def main():42 """Run the scheduler."""43 print("Scheduler started. Press Ctrl+C to exit.")44 print(f"Scheduled jobs: {len(schedule.get_jobs())}")4546 for job in schedule.get_jobs():47 print(f" - {job}")4849 while True:50 schedule.run_pending()51 time.sleep(60) # Check every minute525354if __name__ == "__main__":55 main()
Running schedule as a Service
The schedule library requires the Python script to keep running. Use it with:
Windows: Run as a background service with pythonw.exe
Linux/macOS: Run with nohup or as a systemd service
1# Keep running after terminal closes2nohup python3 scheduler.py &
Making Scripts Robust for Unattended Execution
When scripts run without supervision, they need proper error handling and logging.
Add Logging
1#!/usr/bin/env python32"""3Robust Automation Script - With logging and error handling.4Author: Alex Rodriguez5"""67import logging8import sys9from datetime import datetime10from pathlib import Path111213# Set up logging14def setup_logging(log_file=None):15 """Configure logging for unattended execution."""1617 if log_file is None:18 # Log to script directory19 script_dir = Path(__file__).parent20 log_file = script_dir / "automation.log"2122 logging.basicConfig(23 level=logging.INFO,24 format='%(asctime)s - %(levelname)s - %(message)s',25 handlers=[26 logging.FileHandler(log_file),27 logging.StreamHandler(sys.stdout) # Also print to console28 ]29 )3031 return logging.getLogger(__name__)323334def main():35 """Main function with error handling."""36 logger = setup_logging()3738 logger.info("=" * 50)39 logger.info("Script started")4041 try:42 # Your automation code here43 logger.info("Processing data...")4445 # Example: Simulate work46 result = process_data()47 logger.info(f"Processing complete: {result}")4849 logger.info("Script completed successfully")5051 except FileNotFoundError as e:52 logger.error(f"File not found: {e}")53 sys.exit(1)5455 except PermissionError as e:56 logger.error(f"Permission denied: {e}")57 sys.exit(1)5859 except Exception as e:60 logger.exception(f"Unexpected error: {e}")61 sys.exit(1)626364def process_data():65 """Example processing function."""66 return "100 records processed"676869if __name__ == "__main__":70 main()
Add Email Notifications for Failures
1import smtplib2from email.mime.text import MIMEText345def send_error_notification(error_message, script_name):6 """Send email when script fails."""78 sender = "alerts@yourcompany.com"9 recipient = "admin@yourcompany.com"1011 msg = MIMEText(f"""12 Script Failure Alert1314 Script: {script_name}15 Time: {datetime.now()}16 Error: {error_message}1718 Please investigate.19 """)2021 msg['Subject'] = f"[ALERT] Script Failed: {script_name}"22 msg['From'] = sender23 msg['To'] = recipient2425 try:26 with smtplib.SMTP('smtp.yourcompany.com', 587) as server:27 server.starttls()28 server.login(sender, "password")29 server.send_message(msg)30 except Exception as e:31 logging.error(f"Could not send alert email: {e}")323334# In your main() function:35try:36 # Your code37 pass38except Exception as e:39 logger.exception(f"Script failed: {e}")40 send_error_notification(str(e), "my_script.py")41 sys.exit(1)
The Complete Robust Script Template
1#!/usr/bin/env python32"""3Scheduled Automation Script Template4Author: Alex Rodriguez56A robust template for scripts that run unattended on a schedule.7Includes logging, error handling, and optional notifications.8"""910import logging11import os12import sys13from datetime import datetime14from pathlib import Path1516# Configuration17SCRIPT_NAME = "automation_script"18LOG_RETENTION_DAYS = 3019ENABLE_EMAIL_ALERTS = False20ALERT_EMAIL = "admin@company.com"212223def setup_logging():24 """Set up logging with rotation."""25 # Create logs directory26 log_dir = Path(__file__).parent / "logs"27 log_dir.mkdir(exist_ok=True)2829 # Log file with date30 log_file = log_dir / f"{SCRIPT_NAME}_{datetime.now():%Y%m%d}.log"3132 # Configure logging33 logging.basicConfig(34 level=logging.INFO,35 format='%(asctime)s | %(levelname)-8s | %(message)s',36 datefmt='%Y-%m-%d %H:%M:%S',37 handlers=[38 logging.FileHandler(log_file, encoding='utf-8'),39 logging.StreamHandler(sys.stdout)40 ]41 )4243 logger = logging.getLogger(SCRIPT_NAME)4445 # Clean old logs46 cleanup_old_logs(log_dir)4748 return logger495051def cleanup_old_logs(log_dir, days=LOG_RETENTION_DAYS):52 """Remove log files older than specified days."""53 import time5455 cutoff = time.time() - (days * 86400)5657 for log_file in log_dir.glob("*.log"):58 if log_file.stat().st_mtime < cutoff:59 log_file.unlink()606162def send_alert(subject, message):63 """Send an alert email (implement based on your email setup)."""64 if not ENABLE_EMAIL_ALERTS:65 return6667 # Add your email sending code here68 # See our email automation guide for full implementation69 pass707172def validate_environment():73 """Check that required resources are available."""74 logger = logging.getLogger(SCRIPT_NAME)7576 # Example: Check required directories exist77 required_dirs = ["data", "output"]78 script_dir = Path(__file__).parent7980 for dir_name in required_dirs:81 dir_path = script_dir / dir_name82 if not dir_path.exists():83 logger.warning(f"Creating missing directory: {dir_path}")84 dir_path.mkdir(exist_ok=True)8586 # Example: Check required files exist87 # required_files = ["config.json"]88 # for file_name in required_files:89 # if not (script_dir / file_name).exists():90 # raise FileNotFoundError(f"Required file missing: {file_name}")9192 return True939495def run_automation():96 """97 Main automation logic.9899 CUSTOMIZE THIS FUNCTION for your specific task.100 """101 logger = logging.getLogger(SCRIPT_NAME)102103 # Your automation code goes here104 logger.info("Starting automation task...")105106 # Example steps:107 # 1. Read input data108 logger.info("Step 1: Reading input data")109 # data = read_input()110111 # 2. Process data112 logger.info("Step 2: Processing data")113 # results = process(data)114115 # 3. Save output116 logger.info("Step 3: Saving output")117 # save_output(results)118119 # Return summary120 return {121 "status": "success",122 "records_processed": 100,123 "output_file": "output/results.xlsx"124 }125126127def main():128 """Main entry point with full error handling."""129130 # Initialize logging131 logger = setup_logging()132133 logger.info("=" * 60)134 logger.info(f"STARTING: {SCRIPT_NAME}")135 logger.info(f"Time: {datetime.now()}")136 logger.info("=" * 60)137138 exit_code = 0139140 try:141 # Validate environment142 validate_environment()143144 # Run the automation145 result = run_automation()146147 # Log success148 logger.info("-" * 60)149 logger.info("COMPLETED SUCCESSFULLY")150 logger.info(f"Result: {result}")151 logger.info("-" * 60)152153 except FileNotFoundError as e:154 logger.error(f"File not found: {e}")155 send_alert(f"[ERROR] {SCRIPT_NAME}", f"File not found: {e}")156 exit_code = 1157158 except PermissionError as e:159 logger.error(f"Permission denied: {e}")160 send_alert(f"[ERROR] {SCRIPT_NAME}", f"Permission denied: {e}")161 exit_code = 1162163 except Exception as e:164 logger.exception(f"Unexpected error: {e}")165 send_alert(f"[CRITICAL] {SCRIPT_NAME}", f"Unexpected error: {e}")166 exit_code = 1167168 finally:169 logger.info(f"Script finished with exit code: {exit_code}")170 logger.info("=" * 60 + "\n")171172 sys.exit(exit_code)173174175if __name__ == "__main__":176 main()
How to Run This Script
Windows Task Scheduler Setup
- Save the script as
C:\Scripts\automation_script.py - Open Task Scheduler
- Create Basic Task with these settings:
- Program:
C:\Users\You\AppData\Local\Programs\Python\Python311\python.exe - Arguments:
"C:\Scripts\automation_script.py" - Start in:
C:\Scripts
- Program:
Linux/macOS Cron Setup
1# Edit crontab2crontab -e34# Add line (runs every day at 8 AM):50 8 * * * /usr/bin/python3 /home/user/scripts/automation_script.py
Common Issues & Solutions
| Issue | Solution |
|---|---|
| Script doesn't run | Check full paths for Python and script |
| "ModuleNotFoundError" | Install packages for the correct Python version |
| Permission denied | Run as administrator or check file permissions |
| Script runs but no output | Check working directory; use absolute paths |
| Missed schedules | Check "Run as soon as possible after missed" setting |
Taking It Further
Run at System Startup
Windows: Create a .bat file in the Startup folder:
1@echo off2pythonw.exe "C:\Scripts\my_script.py"
Linux: Add to /etc/rc.local or create a systemd service
Create a Systemd Service (Linux)
1# /etc/systemd/system/my-automation.service2[Unit]3Description=My Python Automation4After=network.target56[Service]7Type=simple8User=youruser9WorkingDirectory=/home/youruser/scripts10ExecStart=/usr/bin/python3 /home/youruser/scripts/scheduler.py11Restart=always1213[Install]14WantedBy=multi-user.target
Enable it:
1sudo systemctl enable my-automation2sudo systemctl start my-automation
Conclusion
Your Python scripts shouldn't need babysitting. With proper scheduling, error handling, and logging, they become truly autonomous tools that work for you around the clock.
Start with one script. Get it running reliably on a schedule. Then expand to more. Before long, you'll have an army of automated processes handling your routine tasks while you focus on work that matters.
True automation runs itself.
Set it and forget it.
Sponsored Content
Interested in advertising? Reach automation professionals through our platform.
