Extract every object from a Microsoft Access .accdb (or .mdb) file to plain text and zip the result.
This is a faithful dumper. It runs SaveAsText on every form, report, query, macro, and module, captures table schemas and relationships separately, and produces a single zip file. It does not parse, transform, or interpret what it extracts — that's a job for downstream tooling.
The tool is the customer-side half of Runway, a structured Access migration product. The bundle it produces is uploaded to Runway, where the actual analysis happens. The original .accdb never leaves your machine.
- Windows. This tool uses Microsoft Access via COM automation, which is Windows-only.
- Microsoft Access — the full product. You need an installation of Microsoft Access (Office 2016 or later, or the standalone Access app). The free Access Database Engine redistributable is not sufficient: it ships only the data engine and OLE DB providers, not the
Access.ApplicationCOM server that this tool drives viaSaveAsText. Symptom of the wrong install:Microsoft Access is not installed or is not COM-accessible. - PowerShell 7 or later. Install from https://aka.ms/powershell if you don't have it. The pre-installed Windows PowerShell 5.1 will not work — invoke with
pwsh, notpowershell. - Trust access to the VBA project object model must be enabled in Access. See Troubleshooting for what that means and why it's off by default.
If your VBA project is locked for viewing, the tool will refuse to run; unlock it (or remove the lock password) and try again.
From a PowerShell 7 prompt:
pwsh ./src/Extract-AccessApp.ps1 -Source C:\apps\my-app.accdb -OutputDir C:\bundlesIf the database has an open password:
pwsh ./src/Extract-AccessApp.ps1 -Source C:\apps\my-app.accdb -OutputDir C:\bundles -Password hunter2If you omit -Password and the database is encrypted, you'll be prompted interactively. Prefer the prompt for any case where you don't want the password ending up in shell history — see Troubleshooting → Database password handling below.
To suppress progress output (errors and warnings still print):
pwsh ./src/Extract-AccessApp.ps1 -Source C:\apps\my-app.accdb -OutputDir C:\bundles -QuietOn success the script prints the bundle path and a summary of object counts, then exits 0. On failure it prints a single descriptive error and exits with one of the codes listed under Exit codes below.
A single zip file named <source-name>-<utc-timestamp>.zip in your output directory. Inside:
manifest.json # bundle metadata, file checksums, host info
forms/ # one .txt per form
reports/ # one .txt per report
queries/ # one .txt per query
macros/ # one .txt per macro
modules/ # one .txt per module
tables.json # all table schemas (no data)
relationships.json # foreign keys and referential integrity rules
references.json # VBA library references
properties.json # database and project properties
The .txt files are the raw output of Access's SaveAsText command. The .json files are extracted via DAO and the Access object model. The manifest.json records every file in the bundle with its SHA-256 and size, host details (OS, PowerShell version, Access version and bitness), and any structured warnings the run produced.
Empty object types still get their folder, so the layout is predictable — an app with no macros has an empty macros/ directory.
- Table data. Schemas only. No rows.
- Data macros (table-level triggers, Access 2010+).
- Custom ribbons.
- Switchboard table contents.
- Anything that requires Access to be writable. The source file is opened read-only where the API allows.
If you need any of these, raise an issue.
Before running the extractor, copy your .accdb to a fresh filename and do not open it in Microsoft Access. Access's Trust Center protects you from running active content in databases it doesn't yet recognise; the extractor depends on that protection to keep your AutoExec macro from running during extraction. If you open the copied file in Access and click "Enable Content", that protection is removed for that file path, and AutoExec will run every time the extractor opens it — potentially modifying your data, prompting for input, or causing other side effects.
Recommended workflow:
- Copy your source
.accdbto a new filename (for examplemy-app-extract.accdb). - Run the extractor against the copy.
- Delete the copy when done.
The error messages below are the exact strings the tool prints when something goes wrong. Search for the message you saw.
You're on Windows PowerShell 5.1. Install PowerShell 7 from https://aka.ms/powershell and invoke with pwsh, not powershell.
This tool runs on Windows only. Microsoft Access COM automation is not available on other platforms.
The Access COM stack only ships on Windows. There is no Linux or macOS workaround.
The check tries New-Object -ComObject Access.Application. It fails when:
- Microsoft Access isn't installed at all.
- Only the Access Database Engine redistributable is installed. The Engine ships the data engine and OLE DB providers but not the
Access.Applicationautomation server. You need full Access (Office 2016+, Microsoft 365, or the standalone Access app). - A bitness mismatch — for example, 32-bit Office on a 64-bit Windows where COM lookup is going to the wrong hive. Reinstalling Access from the standard installer normally fixes this.
The tool builds the bundle in $env:TEMP before zipping. If that directory is missing or read-only (rare on properly configured systems), set $env:TEMP to a writable location and re-run.
The path you passed to -Source doesn't exist. Quote the path if it contains spaces.
Another process — usually Access itself — is holding the file with an exclusive lock. Close Access (or any other application that has the file open) and re-run.
The tool only handles Access database files. Renaming a non-Access file to have one of those extensions will not make this work; the open will fail later anyway.
A zero-byte file isn't a database. Restore from backup.
The directory either doesn't exist (the tool will try to create it but failed) or your account can't write there. Pick a different -OutputDir or fix the permissions.
The tool requires at least 3× the source file's size on the output drive (rough headroom for the temp working directory plus the final zip). Free up space or pick a different -OutputDir.
The bundle filename embeds a one-second-resolution UTC timestamp, so the only way to hit this is to re-run within the same second. Wait a second and retry.
You ran non-interactively (e.g. from a CI environment) without supplying the password. Pass -Password <value>, or run interactively to be prompted.
The password you supplied is wrong. The tool exits with code 2.
The database is corrupt, locked exclusively by another process, in an unsupported format, or otherwise unopenable. The COM error is shown verbatim. Exit code 2.
Could not access the VBA project model. Either the VBA project is locked or the Access Trust Center has "Trust access to the VBA project object model" disabled.
This error covers two distinct cases that look the same to us:
-
Trust setting disabled (most common). Microsoft ships Access with "Trust access to the VBA project object model" off by default, and that's deliberate — it's a security boundary. When the setting is on, any Office automation client can read or modify VBA source in any database that user opens. Macro malware uses this to inspect, exfiltrate, or backdoor VBA code at scale, so Microsoft treats lowering it as a per-machine security decision rather than a default.
This extractor only reads a single property (
VBProjects(1).Protection) to check whether the VBA project is locked. It does not modify any VBA code. Even so, you should treat the setting as something you turn on while running this tool and turn off afterwards, especially on machines that open arbitrary Access files from email or downloads.To enable it: Open Access. File → Options → Trust Center → Trust Center Settings → Macro Settings → check Trust access to the VBA project object model → OK. Re-run the extractor. Turn it off the same way when you're done.
-
VBA project genuinely locked. Open the database in Access, go to Tools → VBAProject Properties → Protection, untick "Lock project for viewing" (and clear the password if there is one). Save, then re-run. If you don't know the lock password, ask whoever built the database — there's no supported way to recover it.
Same case (2) as above, when the trust setting is on but the project itself is locked. Unlock and retry.
-Password is a plain [string] parameter in v1, not a [SecureString]. Two practical implications:
- The password ends up in PSReadLine's command history if you don't clear it. To avoid that, omit
-Passwordand let the tool prompt you interactively (the prompt usesRead-Host -AsSecureStringand never stores the value anywhere). The interactive prompt path is the recommended way to pass passwords for ad-hoc runs. - When automating, prefer environment variables, secret managers, or piping the password into
-Passwordfrom a source you control, and clear PSReadLine history after the run if your shell saves it.
A future release may accept [SecureString] directly; for v1, the behaviour above is the right trade-off because Microsoft Access's OpenCurrentDatabase takes a plain BSTR password at the COM boundary anyway.
Successful runs can still emit warnings into manifest.json without failing. The closed list:
BITNESS_MISMATCH— PowerShell and Access are different bitnesses (e.g. 64-bit pwsh, 32-bit Access). Most COM operations work, but some may behave unexpectedly. Match the bitnesses if you see oddities.NAME_SANITISED— an object name contained characters invalid in a filename and was rewritten. The original name is preserved infiles[].original_name.NAME_COLLISION— two objects produced the same sanitised filename; the second got a_2(or_3, etc.) suffix.LINKED_TABLE_REDACTED— a linked table's connection string contained aPWD/Passwordvalue, which was replaced with<redacted>before being written totables.json.LINKED_TABLE_UNREACHABLE— a linked table's source location couldn't be verified at extraction time. The metadata is still captured.EMPTY_OBJECT— an object existed in Access butSaveAsTextproduced an empty file. Often indicates a corrupt object that should be inspected in Access.
| Code | Meaning |
|---|---|
0 |
Success. Bundle written. |
1 |
A prerequisite check failed. The full list is printed under "Prerequisite checks failed:". |
2 |
The source database could not be opened (wrong password supplied, file locked by another process, or corruption). |
3 |
Extraction or manifest assembly failed mid-run. |
4 |
Zipping the bundle failed. |
The tool runs entirely on your machine. Nothing is uploaded, called home, or transmitted by this script. The bundle is yours to inspect, store, or upload to Runway as you choose.
The bundle contains your application's structure — forms, reports, VBA source, table schemas, relationships, references, properties — but never your data (no rows). It can still contain identifying material in property values, form captions, or VBA strings; inspect any extracted bundle in any text editor before sharing.
Linked-table connection strings are recorded in tables.json with their PWD / Password values redacted to <redacted>. The redaction is regex-based and conservative; treat the bundle as sensitive material regardless.
MIT. See LICENSE for the full text. Copyright (c) 2026 Data Partners Consulting Ltd.
The repository layout:
.
├── CLAUDE.md # standing project context
├── SPEC.md # engineering specification
├── README.md # this file
├── LICENSE # MIT
├── src/
│ ├── Extract-AccessApp.ps1 # entry script
│ └── *.ps1 # one function per file (helpers + extractors)
├── tests/
│ ├── fixtures/ # sample .accdb files (gitignored)
│ └── *.Tests.ps1 # Pester 5 tests
└── docs/
├── quirks.md # Access COM and PowerShell platform notes
└── testing-gaps.md # deliberately skipped tests, with reasons
Tests run with Pester 5:
Install-Module Pester -Force -SkipPublisherCheck
Invoke-Pester ./testsSee SPEC.md for the bundle format contract and CLAUDE.md for the project's standing principles.