Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions Config/Get-OneNotePublishConfiguration.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function Export-OneNoteConfigCheckKeyValue {

if ($Type -eq "Path") {
if ((Test-Path -Path $Value) -ne $true) {
New-Dir -Path $path
New-Dir -Path $Value
}
$Config | Add-Member -Force -Type NoteProperty -Name $Key -Value $Value.Trim()
}
Expand Down Expand Up @@ -85,7 +85,8 @@ function Get-OneNotePublishConfiguration {
$TagPath = Join-Path -Path $config.ExportRootPath -ChildPath "_tags"
New-Dir -Path $TagPath
# delete the tag items on each run since otherwise they will be appended to
(Get-ChildItem -Path $config.ExportRootPath -Recurse -Filter '*.tag.html').Fullname | Remove-Item
$tagFiles = (Get-ChildItem -Path $config.ExportRootPath -Recurse -Filter '*.tag.html' -ErrorAction SilentlyContinue).Fullname
if ($null -ne $tagFiles) { $tagFiles | Remove-Item }

$config | Add-Member -Type NoteProperty -Name PublishFormats -Value (Get-OneNotePublishFormats) -Force -PassThru |
Add-Member -Type NoteProperty -Name pandocMdFormats -Value (Get-PandocMDOutputFormats) -Force -PassThru |
Expand All @@ -98,6 +99,19 @@ function Get-OneNotePublishConfiguration {
}
}
}
else {
foreach($exportFormat in $config.ExportFormat) {
if (-not ($config.PublishFormats -contains $exportFormat)) {
$pandocPath = (Get-Command pandoc -ErrorAction SilentlyContinue).Source
if ($null -ne $pandocPath) {
$config | Add-Member -Type NoteProperty -Name 'Pandoc' -Value $pandocPath -Force
}
else {
Write-Host "Pandoc not found in PATH and AutoDownloadPandoc is False. Markdown export will fail." -ForegroundColor Red
}
}
}
}

foreach($exportFormat in $config.ExportFormat) {
if ($config.PandocMdFormats -contains $exportFormat) {
Expand Down
4 changes: 2 additions & 2 deletions Config/publish.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ ExportRootPath = e:\\exportonenote3
#
# if you select a markdown format docx is always added automagically
#
ExportFormat = pdf, htm, docx, doc, one, markdown
ExportFormat = pdf, html, docx, doc, one, markdown

#
# If already OneNote Published files should be overwritten or not
Expand All @@ -108,7 +108,7 @@ OverWriteAttachments = False
# AutoDownload Pandoc if needed, if you already have this installed you can
# set it to false
#
AutoDownloadPandoc = True
AutoDownloadPandoc = False

#
# Only applicable to Markdown:
Expand Down
12 changes: 11 additions & 1 deletion ExportOneNoteHierarchy.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@
.NOTES
- make sure to have the OneNote Client open
- edit the config.cfg file with preferences
- requires Windows PowerShell 5.1 (OneNote COM doesn't work in PS 7+)
#>

# Re-launch in Windows PowerShell 5.1 if running in PS 7+
if ($PSVersionTable.PSVersion.Major -ge 6) {
Write-Host "OneNote COM requires Windows PowerShell 5.1. Re-launching..."
powershell.exe -ExecutionPolicy Bypass -File $MyInvocation.MyCommand.Path
exit $LASTEXITCODE
}

(Get-ChildItem -Path "$PSScriptRoot\Modules" -Recurse -Filter '*.psm1' -Verbose).FullName | ForEach-Object { Import-Module $_ -Force }
(Get-ChildItem -Path "$PSScriptRoot\ScriptModules" -Recurse -Filter '*.psm1' -Verbose).FullName | ForEach-Object { Import-Module $_ -Force }
(Get-ChildItem -Path "$PSScriptRoot\Config" -Recurse -Filter '*.psm1' -Verbose).FullName | ForEach-Object { Import-Module $_ -Force }

$config = Get-OneNotePublishConfiguration -Path "$PSScriptRoot\Config\publish.cfg"
Publish-OneNoteHierarchyPages -Config $config

Publish-OneNoteHierarchyPages -Config $config
2 changes: 1 addition & 1 deletion Modules/OneNote/Application/OneNoteGetPageContent.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function Get-OneNotePageInsertedFileObjects {
$name = $insertedFile.InsertedFile.preferredName | Remove-InvalidFileNameCharsInsertedFiles
$destination = Join-Path -Path $AttachmentsPath -ChildPath $name
$destinationExists = Test-Path -Path $destination
if (($true -eq $destinationExists -and $Config.OverwriteAttachments -eq $true) -or ($false -eq $destinationExists)) {
if (($true -eq $destinationExists -and $OverwriteAttachments -eq $true) -or ($false -eq $destinationExists)) {
New-Item -Path $AttachmentsPath -ItemType "directory" -Force | Out-Null
# not completely safe but works for me:
if ($destination.Length -gt 259) {
Expand Down
7 changes: 4 additions & 3 deletions Modules/OneNote/Hierarchy/OneNoteHierarchy.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ function Get-OneNoteHierarchy {
try {
[xml]$ObjectId = $null
$OneNote = New-Object -ComObject OneNote.Application
$OneNote.GetHierarchy("", [Microsoft.Office.InterOp.OneNote.HierarchyScope]::hsPages, [ref]$ObjectId)
[string]$xmlString = ""
$OneNote.GetHierarchy("", 4, [ref]$xmlString)
$ObjectId = [xml]$xmlString
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($OneNote) | Out-Null
Remove-Variable OneNote
return $ObjectId
}
catch
{
catch {
Throw
}
}
151 changes: 151 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# OneNote Exporter

A PowerShell-based tool that exports all OneNote notebooks to various file formats via the OneNote COM API. Designed for bulk extraction of OneNote content into files suitable for AI knowledge base ingestion, backup, or migration.

## What It Does

- Exports all open OneNote notebooks (sections, section groups, and pages) to one or more output formats
- Extracts page attachments (embedded files) to a dedicated `_attachments` folder
- Collects OneNote tags (e.g., To Do items) and exports them as HTML summaries
- Converts exported DOCX files to Markdown via Pandoc with configurable options
- Preserves the notebook/section/page hierarchy as a directory structure
- Renames images in Markdown output with unique, descriptive filenames
- Produces a timestamped log of each export run

## Supported Export Formats

| Format | Extension | Description |
|--------|-----------|-------------|
| one | .one | OneNote format |
| onepkg | .onepkg | OneNote package |
| mht | .mht | Web page archive (MHTML) |
| pdf | .pdf | PDF |
| xps | .xps | XML Paper Specification |
| docx | .docx | Microsoft Word (modern) |
| doc | .doc | Microsoft Word (classic) |
| emf | .emf | Enhanced Metafile |
| htm | .htm | HTML with images |

### Pandoc Markdown Formats

| Format | Description |
|--------|-------------|
| markdown | Pandoc extended Markdown |
| markdown_mmd | MultiMarkdown |
| markdown_phpextra | PHP Markdown Extra |
| markdown_strict | Original Markdown |
| commonmark | CommonMark |
| commonmark_x | CommonMark with extensions |
| gfm | GitHub Flavored Markdown |
| markdown_github | GitHub Markdown with extensions |

Markdown formats require Pandoc. If a markdown format is selected, DOCX is automatically included as an intermediate step.

## Requirements

- Windows PowerShell 5.1 (the script auto-relaunches in 5.1 if started from PowerShell 7+)
- Microsoft OneNote desktop (Office 2013/2016/365 — the COM API version, not the Store app)
- OneNote must be running with notebooks open
- [Pandoc](https://pandoc.org/) installed and in PATH (only required for Markdown export)

## Usage

1. Edit `Config/publish.cfg` with your preferences
2. Open OneNote and ensure your notebooks are loaded
3. Run one of the two commands. Windows PowerShell usually blocks running of scripts.

```powershell
.\ExportOneNoteHierarchy.ps1
```

```powershell
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\ExportOneNoteHierarchy.ps1
```

## Configuration

Edit `Config/publish.cfg`:

```ini
# Output directory
ExportRootPath = e:\\exportonenote3

# Formats to export (comma-separated)
ExportFormat = markdown

# Overwrite existing exported files
Overwrite = False

# Overwrite existing attachments
OverWriteAttachments = False

# Auto-download Pandoc if not installed
AutoDownloadPandoc = False

# Markdown options
MdClearSpaces = True
MdClearEscape = True
MdCentralMediaPath = True
MdAddYaml = True
```

## Output Structure

```text
<ExportRootPath>/
├── <format>/ # One folder per export format
│ └── <Notebook>/
│ └── <Section>/
│ └── <Page>.<ext>
├── _attachments/ # Embedded file attachments
│ └── <Notebook>/
│ └── <Section>/
│ └── <Page>/
├── _tags/ # Tag summaries as HTML
│ └── <TagName>.tag.html
└── ExportOneNote_<timestamp>.log
```

## Project Structure

```text
ExportOneNoteHierarchy.ps1 # Entry point
Config/
publish.cfg # User configuration
Get-OneNotePublishConfiguration.psm1 # Config parser and validator
Modules/
Config/Config.psm1 # Generic config file reader
IO/FileOperations.psm1 # File/directory helpers
OneNote/
Application/
OneNotePublish.psm1 # COM publish calls
OneNoteGetPageContent.psm1 # Page content and attachment extraction
Hierarchy/
OneNoteHierarchy.psm1 # GetHierarchy COM call
OneNoteNotebook*.psm1 # Notebook/collection accessors
OneNoteSection*.psm1 # Section/collection accessors
OneNotePage*.psm1 # Page/collection accessors
Pandoc/
Pandoc.psm1 # Pandoc download and invocation
Invoke-MDFilters.psm1 # Post-conversion Markdown cleanup
ScriptModules/
Publish-OneNoteHierarchyPages.psm1 # Main orchestration loop
Get-OneNotePageCollectionFromHierarchy.psm1 # Hierarchy traversal
Get-OneNotePublishPaths.psm1 # Output path generation
Publish-OneNotePageAttachments.psm1 # Attachment export
Publish-OneNoteTags.psm1 # Tag export
Get-OneNoteTags.psm1 # Tag extraction from page XML
ConvertTo-MdFromDocx.psm1 # Pandoc DOCX-to-MD conversion
```

## Known Limitations

- Encrypted sections/pages cannot be exported
- The OneNote COM API does not work in PowerShell 7+ (uses .NET Core which lacks proper COM marshaling for OneNote)
- Very long page names (>259 characters) are truncated to avoid Windows path limits
- Collapsed page sub-hierarchies are exported normally (they are not skipped)

## Credits

Forked from [SjoerdV/ConvertOneNote2MarkDown](https://github.com/SjoerdV/ConvertOneNote2MarkDown) with input from [nixsee/ConvertOneNote2MarkDown](https://github.com/nixsee/ConvertOneNote2MarkDown).
2 changes: 1 addition & 1 deletion ScriptModules/Get-OneNotePageCollectionFromHierarchy.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function Get-OneNotePageCollectionFromHierarchy {
#>
try {
$hierarchy = Get-OneNoteHierarchy
$notebookCollection = Get-OneNoteNoteBookCollection -Hierarchy $hierarchy
$notebookCollection = Get-OneNoteNotebookCollection -Hierarchy $hierarchy
$TagsTable = @{}
return Get-OneNotePageCollectionFromNotebookCollection -NotebookCollection $notebookCollection -TagsTable $TagsTable
}
Expand Down
4 changes: 1 addition & 3 deletions ScriptModules/Publish-OneNoteHierarchyPages.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ function Publish-OneNoteHierarchyPages {
param (
[PSCustomObject]$Config
)
$Config

$enrichedPageCollection, $tagsTable = Get-OneNotePageCollectionFromHierarchy
Write-Host "Done fetching pages. Fetched $($pageCollection.count) pages" -ForegroundColor Green
Write-Host "Done fetching pages. Fetched $($enrichedPageCollection.count) pages" -ForegroundColor Green
Publish-OneNoteTags -Config $Config -TagsTable $tagsTable
foreach ($page in $enrichedPageCollection) {
$OutputEncoding = [ System.Text.Encoding]::UTF8
Expand Down