How to Backup Excel Macros Before Any Conversion
(Never Lose VBA Again)
Most macro loss happens in the 90 seconds before conversion. Someone opens a converter, drags in the file, downloads the result, and moves on. The macros vanish silently. No error. No warning. Just gone.
The fix is a 2-minute pre-conversion backup routine. Do it once before every format change and you'll never lose VBA code again. This guide gives you three methods: manual (Excel built-in), scripted (Python), and automated (one-click batch).
Method 1 — Manual Backup (Excel VBA Editor)
This method works without any scripts or third-party tools. Takes 2-5 minutes per file.
- Open the XLSM file in Excel
- Open the VBA Editor: Alt + F11
- In the Project Explorer (left panel), expand your workbook's project
- For each module/class/form, right-click → Export File
- Save to a folder named
[workbook-name]_vba_backup_YYYY-MM-DD
| Project item | File extension | Contains |
|---|---|---|
| Standard Module | .bas | Sub and Function procedures |
| Class Module | .cls | Class definitions, properties, methods |
| UserForm | .frm + .frx | .frm = layout code; .frx = binary control data |
| ThisWorkbook | .cls | Workbook-level event handlers |
| Sheet1, Sheet2… | .cls | Sheet-level event handlers (often missed!) |
Worksheet_Change and Worksheet_SelectionChange. These are easy to overlook in the Project Explorer and are almost never exported by automated tools.
Method 2 — Python Script (Automated Extract)
For more than 3 files, do this programmatically. The script below uses only the standard library for the ZIP extraction part, with an optional oletools enhancement for readable source code.
Option A — Extract vbaProject.bin (fast, any file)
"""
vba_backup.py — Extract VBA binary from XLSM for archiving
No dependencies beyond stdlib. Run before any format conversion.
Usage: python vba_backup.py workbook.xlsm
"""
import sys, zipfile, shutil
from pathlib import Path
from datetime import date
def backup_vba(xlsm_path):
p = Path(xlsm_path).resolve()
if not p.exists():
print(f"Error: {p} not found"); return
today = date.today().isoformat()
backup_dir = p.parent / f"{p.stem}_vba_backup_{today}"
backup_dir.mkdir(exist_ok=True)
# Copy original XLSM to backup
shutil.copy2(p, backup_dir / p.name)
print(f"Original archived: {backup_dir / p.name}")
# Extract vbaProject.bin
found = False
with zipfile.ZipFile(p, 'r') as z:
for entry in z.namelist():
if 'vbaProject' in entry:
z.extract(entry, backup_dir)
print(f"VBA binary extracted: {entry}")
found = True
if not found:
print("No VBA found in this file — safe to convert without backup")
else:
print(f"Backup complete: {backup_dir}")
print("To restore: re-import vbaProject.bin via the MacroKit restore script")
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: python vba_backup.py ")
sys.exit(1)
backup_vba(sys.argv[1])
Option B — Extract readable source code (requires oletools)
# pip install oletools
from oletools.olevba import VBA_Parser
def extract_vba_source(xlsm_path, output_dir):
"""Extract VBA source code as readable .bas/.cls files."""
from pathlib import Path
out = Path(output_dir)
out.mkdir(exist_ok=True)
vba_parser = VBA_Parser(xlsm_path)
if not vba_parser.detect_vba_macros():
print("No VBA macros detected")
return
for (filename, stream_path, vba_filename, vba_code) in vba_parser.extract_macros():
# Determine extension from stream path
ext = '.cls' if 'Class' in stream_path else '.bas'
safe_name = vba_filename.replace('/', '_').replace('\\', '_')
out_file = out / f"{safe_name}{ext}"
out_file.write_text(vba_code, encoding='utf-8')
print(f"Extracted: {out_file.name} ({len(vba_code)} chars)")
vba_parser.close()
# Example usage:
extract_vba_source("report-automation.xlsm", "vba_backup_2026-04-15")
Method 3 — Pre-Conversion Checklist (for teams)
If you're working with others or running a regular conversion process, use this checklist before any format change:
- Run Macro Inspector on file — confirm VBA modules present
- Count modules, classes, and forms (document the number)
- Export vbaProject.bin using vba_backup.py
- Export readable source with oletools (optional but recommended)
- Copy original XLSM to archive folder with date suffix
- Confirm backup folder size > 0 bytes
- Only then: proceed with format conversion
- After conversion: verify converted file opens without errors
- Note which features will be broken (VBA-dependent formulas, buttons, etc.)
Where to Store Macro Backups
| Storage option | Pros | Cons |
|---|---|---|
| Local folder (same directory) | Fast, zero setup | Lost if drive fails, not searchable |
| Dated subfolder | Clear versioning | Still local-only |
| Git repository | Full history, diff-able VBA code, searchable | Requires git setup, .frx binaries not diff-able |
| SharePoint / OneDrive | Automatic version history | Macros blocked in online edit; only useful as backup |
| Dedicated archive ZIP | Single file to move around | No easy browsing without extraction |
.bas and .cls files in a git repository. VBA is plain text — you can diff modules, see who changed what, and roll back to any version. The .frx binary (UserForm controls) can't be diffed but should still be committed for restore purposes.
Restoring Macros After a Bad Conversion
If you have a backup and need to restore:
- Open the converted file in Excel
- Save As → XLSM (must be XLSM to accept macros)
- Open VBA Editor (Alt+F11)
- File → Import File → select each .bas / .cls from your backup
- For UserForms: place .frm and .frx in the same folder, import the .frm
- Test all macros — update any references that changed during conversion
If you only have the vbaProject.bin binary (not readable source), use the oletools library to extract the source from the binary before re-importing.
Automating Backups System-Wide
For teams that run regular conversions, automate the backup step so it can't be forgotten:
#!/bin/bash
# pre-convert-hook.sh — Run before any XLSM conversion
# Add to your conversion pipeline as a required step
FILE="$1"
if [[ "$FILE" == *.xlsm ]] || [[ "$FILE" == *.xls ]]; then
echo "Macro-capable file detected. Running backup..."
python3 vba_backup.py "$FILE"
if [ $? -ne 0 ]; then
echo "ERROR: Backup failed. Aborting conversion."
exit 1
fi
echo "Backup complete. Proceeding with conversion."
fi
Complete pre-conversion workflow kit
MacroKit includes the full backup script, pre-conversion checklist, restore guide, and batch conversion workflow — everything you need to handle XLSM conversions without ever losing a line of VBA code.
Get MacroKit — $9Or check if your file has macros first: Free Macro Inspector →