From afa90f3678711de111252dd83b86b9c227a09be5 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 13 Oct 2026 18:28:29 +0200 Subject: [PATCH 1/2] Fix: Fix images of subpages or identically-named pages of a Section overwriting each other With `$medialocation = 1` (default), the images of all of a notebook's pages are saved in the notebook's `media` folder, named after the page's Section and name, e.g. `mysection-mypage-image1.png`. So subpages with the same name (e.g. `Exercise` under two different pages) and identically-named pages of a Section got the same image names, and the images of one page overwrote the images of the other. Both pages then showed the same images. Now image names include the page's parent pages and the postfix of identically-named pages, i.e. the `.md` file's path within the notebook, e.g. `mysection-mypage-mysubpage-image1.png`. Image names of first level pages that are not identically-named are unchanged. Co-Authored-By: Claude Opus 5.5 --- ConvertOneNote2MarkDown-v2.Tests.ps1 | 22 ++++++++++++++++++++++ ConvertOneNote2MarkDown-v2.ps1 | 12 +++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/ConvertOneNote2MarkDown-v2.Tests.ps1 b/ConvertOneNote2MarkDown-v2.Tests.ps1 index 72d1ae7..5fe3bb0 100644 --- a/ConvertOneNote2MarkDown-v2.Tests.ps1 +++ b/ConvertOneNote2MarkDown-v2.Tests.ps1 @@ -885,6 +885,27 @@ Describe 'New-SectionGroupConversionConfig' -Tag 'Unit' { } } + It "Should generate unique media file names for each page, even for subpages and identically-named pages of a Section" { + foreach ($medialocation in 1, 2) { + $params['Config']['medialocation']['value'] = $medialocation + foreach ($fakeHierarchy in @( (Get-FakeOneNoteHierarchy), (Get-FakeOneNoteHierarchyWithDuplicatePageNames) )) { + $params['SectionGroups'] = $fakeHierarchy.Notebooks.Notebook + $result = @( New-SectionGroupConversionConfig @params 6>$null ) + + # Media file names must be unique within each media folder + $result | Group-Object { [io.path]::combine( $_['mediaPath'], $_['mediaNamePrefix'] ) } | Where-Object { $_.Count -gt 1 } | ForEach-Object { $_.Name } | Should -Be $null + } + } + + # Media file names of first level pages that are not identically-named are unchanged + $params['Config']['medialocation']['value'] = 1 + $params['SectionGroups'] = (Get-FakeOneNoteHierarchy).Notebooks.Notebook + $result = @( New-SectionGroupConversionConfig @params 6>$null ) + foreach ($pageCfg in @( $result | Where-Object { $_['pageLevel'] -eq 1 } )) { + $pageCfg['mediaNamePrefix'] | Should -Be $pageCfg['pathFromRootCompat'] + } + } + It "Should honor config notesdestpath" { if ($env:OS -match 'windows') { $params['Config']['notesdestpath']['value'] = 'D:\foo\bar' @@ -1760,6 +1781,7 @@ Describe 'Convert-OneNotePage' -Tag 'Unit' { Assert-MockCalled -CommandName Get-ChildItem -Times 1 -Scope It Assert-MockCalled -CommandName Move-Item -Times 1 -Scope It + Assert-MockCalled -CommandName Move-Item -ParameterFilter { (Split-Path $Destination -Leaf) -eq "$( $params['ConversionConfig']['mediaNamePrefix'] )-image.jpg" } -Times 1 -Scope It } It "Does not halt conversion if renaming image(s) fails" { diff --git a/ConvertOneNote2MarkDown-v2.ps1 b/ConvertOneNote2MarkDown-v2.ps1 index 3668cba..e96e824 100644 --- a/ConvertOneNote2MarkDown-v2.ps1 +++ b/ConvertOneNote2MarkDown-v2.ps1 @@ -861,6 +861,12 @@ Function New-SectionGroupConversionConfig { $cfg['notesBaseDirectory'] } $pageCfg['mediaPath'] = [io.path]::combine( $pageCfg['mediaParentPath'], 'media' ) + $pageCfg['mediaNamePrefix'] = if ($config['medialocation']['value'] -eq 2) { + $pageCfg['filePathRelUnderscore'] + }else { + # The media of all of a notebook's pages are saved in the same folder, so the prefix includes the page's parent pages and the postfix of identically-named pages, i.e. the .md file's path. Or else e.g. subpages with the same name would overwrite each other's media + "$( $sectionCfg['pathFromRoot'] )$( [io.path]::DirectorySeparatorChar )$( $pageCfg['filePathRel'] )" | Remove-InvalidFileNameChars + } $pageCfg['mediaParentPathPandoc'] = [io.path]::combine( $pageCfg['tmpPath'] ).Replace( [io.path]::DirectorySeparatorChar, '/' ) # Pandoc outputs paths in markdown with with front slahes after the supplied , e.g. '/media/image.png'. So let's use a front-slashed supplied mediaPath $pageCfg['mediaPathPandoc'] = [io.path]::combine( $pageCfg['tmpPath'], 'media').Replace( [io.path]::DirectorySeparatorChar, '/' ) # Pandoc outputs paths in markdown with with front slahes after the supplied , e.g. '/media/image.png'. So let's use a front-slashed supplied mediaPath $pageCfg['docxExportFilePath'] = if ($config['docxNamingConvention']['value'] -eq 1) { @@ -1241,11 +1247,7 @@ Function Convert-OneNotePage { foreach ($image in $images) { # Rename Image try { - $newimageName = if ($config['medialocation']['value'] -eq 2) { - "$( $pageCfg['filePathRelUnderscore'] )-$($image.BaseName)$($image.Extension)" - }else { - "$( $pageCfg['pathFromRootCompat'] )-$($image.BaseName)$($image.Extension)" - } + $newimageName = "$( $pageCfg['mediaNamePrefix'] )-$($image.BaseName)$($image.Extension)" $newimagePath = [io.path]::combine( $pageCfg['mediaPath'], $newimageName ) "Moving image: $( $image.FullName ) to $( $newimagePath )" | Write-Verbose if (!$config['dryRun']['value']) { From ab5375524e70c494654fe07911ef194deda0d965 Mon Sep 17 00:00:00 2001 From: Elias Date: Wed, 14 Oct 2026 10:05:34 +0200 Subject: [PATCH 2/2] Fix: Fix wrong destination path in error when renaming an image fails The error showed the result of the previous `New-Item` or `Move-Item` call (e.g. the `media` folder) instead of the image's destination path, making it impossible to tell which file name failed. Co-Authored-By: Claude Opus 5.5 --- ConvertOneNote2MarkDown-v2.Tests.ps1 | 4 ++-- ConvertOneNote2MarkDown-v2.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ConvertOneNote2MarkDown-v2.Tests.ps1 b/ConvertOneNote2MarkDown-v2.Tests.ps1 index 5fe3bb0..c12496a 100644 --- a/ConvertOneNote2MarkDown-v2.Tests.ps1 +++ b/ConvertOneNote2MarkDown-v2.Tests.ps1 @@ -1784,12 +1784,12 @@ Describe 'Convert-OneNotePage' -Tag 'Unit' { Assert-MockCalled -CommandName Move-Item -ParameterFilter { (Split-Path $Destination -Leaf) -eq "$( $params['ConversionConfig']['mediaNamePrefix'] )-image.jpg" } -Times 1 -Scope It } - It "Does not halt conversion if renaming image(s) fails" { + It "Does not halt conversion if renaming image(s) fails, and reports the image's destination path" { Mock Move-Item { throw } $err = Convert-OneNotePage @params 6>$null 2>&1 - $err.Exception.Message | Select-Object -First 1 | Should -match 'Failed to rename image' + $err.Exception.Message | Select-Object -First 1 | Should -match "Failed to rename image .+ to $( [regex]::Escape([io.path]::combine( $params['ConversionConfig']['mediaPath'], "$( $params['ConversionConfig']['mediaNamePrefix'] )-image.jpg" )) )\." } It "Markdown Mutation: Rename page image references in markdown to unique names" { diff --git a/ConvertOneNote2MarkDown-v2.ps1 b/ConvertOneNote2MarkDown-v2.ps1 index e96e824..a07ce22 100644 --- a/ConvertOneNote2MarkDown-v2.ps1 +++ b/ConvertOneNote2MarkDown-v2.ps1 @@ -1254,7 +1254,7 @@ Function Convert-OneNotePage { $item = Move-Item -Path "$( $image.FullName )" -Destination $newimagePath -Force -ErrorAction Stop -PassThru } }catch { - Write-Error "Failed to rename image $( $image.FullName ) to $( $item.FullName ). Exception: $( $_.Exception.Message )" -ErrorAction Continue + Write-Error "Failed to rename image $( $image.FullName ) to $( $newimagePath ). Exception: $( $_.Exception.Message )" -ErrorAction Continue } # Mutate markdown content with new image references try {