2025 has been all about automations. Everyone keeps talking about how you can automate one thing or another using tools like n8n, Zapier, Huginn, or Make. But people forget how easy it is to automate almost anything with good old Python (no, really). I run tiny scripts on my Mac and Windows machines to handle tasks that would normally eat up hours during the week, and I genuinely save a lot of time because of them.

👁 PowerShell and Windows PowerShell
6 PowerShell scripts to automate and speed up your workflow

When you work through the CLI you save a lot of time. Here are PowerShell scripts to speed your workflow.

Clean the mess that is the inbox

When you don't want to deal with all that mess

This tiny script connects to your email inbox through IMAP and handles the boring work of removing or archiving messages you no longer need. You can tell it to look for unread messages older than a certain number of days, and it will quietly move them to your archive so your inbox feels lighter.

It is especially handy if you get dozens of promotional emails each day and have no interest in clearing them one by one. Since it runs through IMAP, it works the same way across most email providers.

#!/usr/bin/env python3
"""
clean_inbox.py
Archive or delete emails older than N days that match a simple filter.
Usage:
python clean_inbox.py your-email@example.com app-password --days 30 --archive
"""
import imaplib, email, sys, argparse, datetime

parser = argparse.ArgumentParser()
parser.add_argument('email')
parser.add_argument('password')
parser.add_argument('--imap', default='imap.gmail.com')
parser.add_argument('--days', type=int, default=30)
parser.add_argument('--archive', action='store_true', help='Move to [Gmail]/All Mail (Gmail)')
parser.add_argument('--delete', action='store_true', help='Delete instead of archive')
args = parser.parse_args()

cutoff = (datetime.datetime.utcnow() - datetime.timedelta(days=args.days)).strftime("%d-%b-%Y")
M = imaplib.IMAP4_SSL(args.imap)
M.login(args.email, args.password)
M.select("INBOX")
typ, data = M.search(None, '(BEFORE "{}")'.format(cutoff))
ids = data[0].split()
print(f"Found {len(ids)} messages before {cutoff}")
if not ids:
M.logout(); sys.exit()

if args.delete:
for i in ids: M.store(i, '+FLAGS', '\\Deleted')
M.expunge()
print("Deleted messages.")
elif args.archive:
# Gmail special: move to All Mail by copying then deleting from INBOX
for i in ids:
M.copy(i, '[Gmail]/All Mail')
M.store(i, '+FLAGS', '\\Deleted')
M.expunge()
print("Archived messages.")
else:
print("No action specified. Use --archive or --delete.")
M.logout()

Back up files to cloud storage

It saves time when you have scattered files

This script gives you an easy way to push files to any S3-compatible storage provider. You point it at a folder, and it uploads all files inside it to your cloud bucket. It saves time when you have scattered files that you want off your machine, or when you just need a quick backup of work documents, PDFs, or screenshots.

The script only focuses on uploading and keeps things minimal, which makes it ideal for daily or weekly backups. If you prefer services like Wasabi or DigitalOcean Spaces, it still works because it uses the same S3-style operations.

#!/usr/bin/env python3
"""
s3_backup.py
Sync a local folder to S3 bucket (uploads new or changed files).
Usage:
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
python s3_backup.py /path/to/folder bucket-name prefix
"""
import boto3, os, sys, hashlib
from pathlib import Path

local = Path(sys.argv[1])
bucket = sys.argv[2]
prefix = sys.argv[3] if len(sys.argv) > 3 else ''

s3 = boto3.client('s3')
def md5(path):
h=hashlib.md5()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(8192), b''): h.update(chunk)
return h.hexdigest()

for p in local.rglob('*'):
if p.is_file():
key = (prefix + '/' + str(p.relative_to(local))).lstrip('/')
# quick check: compare sizes; skip if same size and same etag not checked here
s3.upload_file(str(p), bucket, key)
print("Uploaded", key)

Sort the screenshots

Because we all have too many of them

Screenshots tend to spread across your system in places like the desktop and downloads folder. This script finds them, identifies them by common naming patterns, and moves them into a single, tidy destination folder sorted by date. I no longer have to hunt for a screenshot I took earlier because everything sits inside a clean folder structure.

You can also use a dry run mode that shows what will be moved before you allow any changes. It is quick to run, works on any platform, and is one of those small tools that immediately make your system feel less cluttered. If you take a lot of screenshots for work, this one script will save you hours of searching and sorting.

#!/usr/bin/env python3
"""
screenshot_sorter.py
Usage:
python screenshot_sorter.py --src ~/Downloads --src ~/Desktop --dest ~/Pictures/Screenshots --dry-run
"""
import argparse, shutil, re
from pathlib import Path
from datetime import datetime

p = argparse.ArgumentParser()
p.add_argument('--src', action='append', default=[str(Path.home() / 'Downloads'), str(Path.home() / 'Desktop')])
p.add_argument('--dest', default=str(Path.home() / 'Pictures' / 'Screenshots'))
p.add_argument('--dry-run', action='store_true')
p.add_argument('--days', type=int, default=365)
args = p.parse_args()

patterns = re.compile(r'screen(sho?t)?t|screenshot|スクリーンショット|截圖', re.I)
exts = {'.png','.jpg','.jpeg','.webp','.bmp','.tiff'}

for s in args.src:
for f in Path(s).rglob('*'):
if f.is_file() and f.suffix.lower() in exts and patterns.search(f.name):
mtime = datetime.fromtimestamp(f.stat().st_mtime)
destdir = Path(args.dest) / mtime.strftime('%Y-%m-%d')
destdir.mkdir(parents=True, exist_ok=True)
target = destdir / f.name
if args.dry_run:
print("DRY", f, "->", target)
else:
i = 1
while target.exists():
target = destdir / (f.stem + f"_{i}" + f.suffix)
i += 1
shutil.move(str(f), str(target))
print("Moved", f, "->", target)

Rename files in bulk

Doing it by hand is painful

When you need to rename a batch of files, doing it by hand is painful. This script gives you two options. You can rename files using a pattern that matches part of the original name, or you can simply rename everything in sequence. It is a solution for situations like cleaning up a folder of photos, reorganizing assets for a project, or fixing inconsistent filenames. Since it uses regular expressions, you can get as advanced as you want, but you also have the option to keep things very basic.

#!/usr/bin/env python3
"""
bulk_rename.py
Usage:
python bulk_rename.py /path/to/folder --pattern "IMG_(\d+)" --replace "photo_\\1" --ext .jpg
Or simple sequence:
python bulk_rename.py /path/to/folder --seq "photo" --ext .png
"""
import argparse, re
from pathlib import Path

ap = argparse.ArgumentParser()
ap.add_argument('folder')
ap.add_argument('--pattern')
ap.add_argument('--replace')
ap.add_argument('--seq')
ap.add_argument('--ext', default='')
args = ap.parse_args()
folder = Path(args.folder)

if args.pattern and args.replace:
rx = re.compile(args.pattern)
for f in folder.iterdir():
if f.is_file():
m = rx.search(f.name)
if m:
new = rx.sub(args.replace, f.name)
f.rename(folder / new)
print("Renamed", f.name, "->", new)
elif args.seq:
i = 1
for f in sorted(folder.iterdir()):
if f.is_file():
ext = args.ext or f.suffix
new = f"{args.seq}_{i}{ext}"
f.rename(folder / new)
print("Renamed", f.name, "->", new)
i += 1
else:
print("No action. Provide --pattern/--replace or --seq.")

Arrange files and folders

Bring some order to your files

This script checks every file inside a folder and moves it into a matching category based on its extension. Images go into an Images folder, documents go into Docs, spreadsheets move to Spreadsheets, and so on. Anything that does not match falls into an Others folder. It is perfect for cleaning a messy downloads folder or preparing a directory for long-term storage. You bring some order to your files with one small command instead of dragging and dropping everything by hand.

#!/usr/bin/env python3
"""
arrange_it.py
Usage:
python arrange_it.py /path/to/folder
"""
import sys
from pathlib import Path

mapping = {
'Images': {'.png','.jpg','.jpeg','.gif','.webp','.bmp','.tiff'},
'Docs': {'.pdf','.docx','.doc','.txt','.md','.odt','.rtf'},
'Spreadsheets': {'.xls','.xlsx','.csv'},
'Archives': {'.zip','.tar','.gz','.rar','.7z'},
'Scripts': {'.py','.sh','.js','.ps1'},
'Videos': {'.mp4','.mkv','.mov','.webm','.avi'}
}

root = Path(sys.argv[1] if len(sys.argv)>1 else '.').expanduser()
for f in root.iterdir():
if f.is_file():
moved=False
for folder, exts in mapping.items():
if f.suffix.lower() in exts:
dest = root / folder
dest.mkdir(exist_ok=True)
target = dest / f.name
i=1
while target.exists():
target = dest / (f.stem + f"_"+str(i) + f.suffix)
i += 1
f.replace(target)
print("Moved", f.name, "->", dest.name + '/' + target.name)
moved=True
break
if not moved:
dest = root / 'Others'
dest.mkdir(exist_ok=True)
f.replace(dest / f.name)
print("Moved", f.name, "-> Others/" + f.name)

Save your clipboard as text file

Everything is saved in plain text

If you copy a lot of text during the day, you probably lose track of important snippets. This script watches your clipboard and saves every new item into a daily text file. It lets you go back and find anything you copied earlier, whether it was a note, a link, or a chunk of code. The idea is to give you a simple personal history of your clipboard without needing a heavy clipboard manager. Everything is saved in plain text inside a folder that you can sync or archive. For writers, developers, and researchers, it becomes a quiet assistant that helps you recover things you would normally lose.

#!/usr/bin/env python3
"""
clip_save.py
Run it in your terminal or as a background process. It appends new clipboard items to daily file.
Usage:
python clip_save.py
"""
import time, os
from datetime import datetime
import pyperclip

out = os.path.expanduser('~/clipboard_history')
os.makedirs(out, exist_ok=True)
last = None
while True:
try:
txt = pyperclip.paste()
except Exception:
txt = ''
if txt and txt != last:
last = txt
fn = os.path.join(out, datetime.now().strftime('%Y-%m-%d') + '.txt')
with open(fn, 'a', encoding='utf-8') as f:
f.write(f"\n\n[{datetime.now().isoformat()}]\n{txt}\n")
print("Saved to", fn)
time.sleep(1.5)

Python is easy to learn

Learning Python is easy, and once you get the basics down, it can be a real game-changer for you as a PC user. You can use it to automate parts of your workflow or plug it into the apps you already use to make them more powerful. For example, you can even boost your productivity in Excel by bringing Python into the mix.

👁 An image showing a laptop displaying the Python Package Index website on a web browser.
5 Python scripts anyone can use to boost their productivity

If you've heard of Python but don't know where to start with it, these five scripts can help boost your productivity.