Python and the Win32COM Interface for Automation

Python is great for automating repetitive tasks, and Windows Task Scheduler is a powerful tool for scheduling processes. By integrating Python and the Win32COM interface, you can programmatically control Task Scheduler, enabling dynamic and customizable task scheduling. This guide walks through a real-world example of using Python to create and manage a scheduled task that zips video files older than 30 days.

Why Use Win32COM for Task Scheduler?

The Win32COM module (part of pywin32) allows Python to interact with Windows-specific COM objects. This library can create, modify, and delete scheduled tasks directly from your scripts.

In this example, we’ll focus on the task of archiving video files. However, the principles apply to any scenario requiring scheduled execution of scripts or programs.

Setting Up the Environment

Before diving into the code, create a virtual environment to keep the project dependencies isolated.

Windows Only:

python -m venv venv
venv\Scripts\activate
pip install pywin32

This library provides the win32com.client module, which lets Python interact with Windows Task Scheduler.

Writing the Archival Script

First, create the script zip_old_videos.py to zip video files older than 30 days. This script operates independently of Task Scheduler but will be executed automatically through our scheduled task.

import os
import zipfile
from datetime import datetime, timedelta

VIDEOS_DIR = "C:\\Path\\To\\videos"
ARCHIVE_DIR = "C:\\Path\\To\\archived_videos"
RETENTION_DAYS = 30

def zip_videos_older_than_30_days():
    # Ensure the archive directory exists
    if not os.path.exists(ARCHIVE_DIR):
        os.makedirs(ARCHIVE_DIR)
    
    cutoff_date = datetime.now() - timedelta(days=RETENTION_DAYS)
    videos_by_day = {}

    # Group videos by recording date
    for file_name in os.listdir(VIDEOS_DIR):
        file_path = os.path.join(VIDEOS_DIR, file_name)
        if os.path.isfile(file_path) and file_name.endswith(".mp4"):
            file_mod_time = datetime.fromtimestamp(os.path.getmtime(file_path))
            if file_mod_time < cutoff_date:
                day_key = file_mod_time.strftime("%Y-%m-%d")
                if day_key not in videos_by_day:
                    videos_by_day[day_key] = []
                videos_by_day[day_key].append(file_path)
    
    # Zip each group of videos
    for day, files in videos_by_day.items():
        zip_file_name = os.path.join(ARCHIVE_DIR, f"{day}.zip")
        with zipfile.ZipFile(zip_file_name, 'w') as zipf:
            for file_path in files:
                zipf.write(file_path, arcname=os.path.basename(file_path))
        print(f"Archived {len(files)} videos from {day} into {zip_file_name}")

if __name__ == "__main__":
    zip_videos_older_than_30_days()

This script:

  • Identifies .mp4 files older than 30 days.
  • Groups them by the day they were modified.
  • Compresses each day’s videos into a ZIP archive.

Automating with Win32COM and Task Scheduler

The real power comes from automating the execution of this script. By leveraging Win32COM, we’ll create a scheduled task that runs the archival script every day at 2:00 AM.

Creating the Task Scheduler Script

Save the following script as schedule_zip_task.py:

import os
import win32com.client

TASK_NAME = "ZipOldVideos"
SCRIPT_PATH = os.path.abspath("zip_old_videos.py")
TRIGGER_TIME = "02:00"

def schedule_task():
    # Connect to Task Scheduler
    scheduler = win32com.client.Dispatch("Schedule.Service")
    scheduler.Connect()
    
    # Get the root folder of Task Scheduler
    root_folder = scheduler.GetFolder("\\")
    
    # Create a new task
    task_definition = scheduler.NewTask(0)
    
    # Set task metadata
    task_definition.RegistrationInfo.Description = "Zips videos older than 30 days into daily archives"
    task_definition.RegistrationInfo.Author = "Automation Script"
    
    # Create a daily trigger
    trigger = task_definition.Triggers.Create(2)  # 2 = Daily Trigger
    trigger.StartBoundary = f"2024-12-03T{TRIGGER_TIME}:00"
    trigger.DaysInterval = 1
    
    # Set the action to run the Python script
    action = task_definition.Actions.Create(0)  # 0 = Exec action
    action.Path = "python"
    action.Arguments = SCRIPT_PATH
    
    # Configure task settings
    settings = task_definition.Settings
    settings.Enabled = True
    settings.StartWhenAvailable = True
    settings.Hidden = False
    
    # Register the task
    root_folder.RegisterTaskDefinition(
        TASK_NAME,
        task_definition,
        6,  # TASK_CREATE_OR_UPDATE
        None,  # No username (runs with the current user)
        None,  # No password
        0     # Logon type: Interactive or Batch
    )
    
    print(f"Task '{TASK_NAME}' created successfully.")

if __name__ == "__main__":
    schedule_task()

How It Works

  1. Task Scheduler Connection: The script connects to the Task Scheduler API using win32com.client.Dispatch("Schedule.Service").

2. Task Definition: A new task is created with triggers and actions.

  • Trigger: Configured to run daily at 2:00 AM.
  • Action: Executes zip_old_videos.py using Python.

3. Task Registration: The RegisterTaskDefinition method saves the task in Task Scheduler.

Testing and Deployment

Run the scheduling script:

python schedule_zip_task.py
  • Verify the task in Task Scheduler:
  • Open Task Scheduler (Start > Task Scheduler).
  • Navigate to “Task Scheduler Library” and locate the “ZipOldVideos” task.
  • Wait for the next execution or manually run the task to test it.

Advantages of Using Win32COM

  • Dynamic Scheduling: Tasks can be created, modified, or deleted programmatically, enabling flexible automation.
  • Integration: Easily integrates with existing Python scripts or workflows.
  • Efficiency: No manual intervention is needed once the task is scheduled.

Here’s a Python script using the win32com.client module to delete or remove a scheduled task from Task Scheduler. The script allows you to specify the task name to remove.

import win32com.client

def delete_scheduled_task(task_name):
    try:
        # Connect to Task Scheduler
        scheduler = win32com.client.Dispatch("Schedule.Service")
        scheduler.Connect()
        
        # Get the root folder
        root_folder = scheduler.GetFolder("\\")
        
        # Delete the task
        root_folder.DeleteTask(task_name, 0)  # 0 means no special flags
        print(f"Task '{task_name}' deleted successfully.")
    except Exception as e:
        print(f"Error deleting task '{task_name}': {e}")

if __name__ == "__main__":
    # Specify the name of the task to delete
    task_name = "ZipOldVideos"  # Replace with your task name
    delete_scheduled_task(task_name)

How It Works:

  1. Connect to Task Scheduler: The script initializes the Schedule.Service COM object and connects to Task Scheduler.
  2. Access the Root Folder: The root folder is the default container for tasks unless a specific folder is used.
  3. Delete the Task: The DeleteTask method removes the specified task by name

Thank you for reading this article. I hope you found it helpful and informative. If you have any questions, or if you would like to suggest new Python code examples or topics for future tutorials, please feel free to reach out. Your feedback and suggestions are always welcome!

Happy coding!
C. C. Python Programming

You can also find this article at Medium.com

Leave a Reply