Export-OneNote.ps1
|
<#PSScriptInfo .VERSION 1.4.1 .GUID b9742b5d-5b71-4a08-bbfe-635827e34076 .AUTHOR Jan-Hendrik Peters .COMPANYNAME Jan-Hendrik Peters .COPYRIGHT Jan-Hendrik Peters, 2023 .TAGS OneNote Markdown Graph .LICENSEURI https://raw.githubusercontent.com/nyanhp/freeing-onenote/main/LICENSE .PROJECTURI https://github.com/nyanhp/freeing-onenote .ICONURI .EXTERNALMODULEDEPENDENCIES MiniGraph,MarkdownPrince .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .PRIVATEDATA #> #Requires -Module MiniGraph #Requires -Module MarkdownPrince <# .SYNOPSIS This script exports one or more OneNote notebooks to markdown .DESCRIPTION This script exports one or more OneNote notebooks to markdown using the Graph API and an Entra App Registration. The script requires the following modules to be installed: - MiniGraph - MarkdownPrince .PARAMETER TenantId The tenant id to use for the Graph API. Defaults to 'Common'. .PARAMETER OneNoteAppClientId The client id of the app registration to use for the Graph API. Defaults to '812899b7-584c-4812-8aee-11d3e164d58b', which is managed by the author. .PARAMETER User The user to use for the Graph API. Defaults to 'me'. Use string like user/GUID to request notebooks from other users if the permissions are set correctly. .PARAMETER Notebook The name of the notebook to export. Can be specified multiple times. If not specified, all notebooks will be exported. .PARAMETER All If specified, all notebooks will be exported. .PARAMETER Path The path to export the notebooks to. If the path does not exist, it will be created. .EXAMPLE ./Export-OneNote.ps1 -Notebook 'My Notebook' -Path "$home/freedomfromproprietaryformats" #> [CmdletBinding(DefaultParameterSetName = 'Notebook')] param ( [Parameter(ParameterSetName = 'Notebook')] [Parameter(ParameterSetName = 'All')] [string] $TenantId = 'Common', # Use mine or create your own [Parameter(ParameterSetName = 'Notebook')] [Parameter(ParameterSetName = 'All')] [string] $OneNoteAppClientId = '812899b7-584c-4812-8aee-11d3e164d58b', [string] $User = 'me', [Parameter(Mandatory = $true, ParameterSetName = 'Notebook')] [string[]] $Notebook, [Parameter(Mandatory = $true, ParameterSetName = 'All')] [switch] $All, [Parameter(Mandatory = $true, ParameterSetName = 'Notebook')] [Parameter(Mandatory = $true, ParameterSetName = 'All')] $Path, [switch] $UseDeviceCode ) if ($UseDeviceCode.IsPresent) { Connect-GraphDeviceCode -TenantId $TenantId -ClientId $OneNoteAppClientId } else { Connect-GraphBrowser -TenantId $TenantId -ClientId $OneNoteAppClientId -Scopes User.Read, Notes.Read, Notes.Read.All } Set-GraphEndpoint -Type beta $notebooks = if ($All.IsPresent) { Invoke-GraphRequest -Query "$($User)/onenote/notebooks" } else { $Notebook | ForEach-Object { Invoke-GraphRequest -Query "$($User)/onenote/notebooks?`$filter=displayName eq '$($_ -replace "'", "''")'" } } if (-not (Test-Path $Path)) { $null = New-Item -Path $Path -ItemType Directory -Force } $mg = Get-Module -Name MiniGraph $token = & $mg { $script:token } Write-Verbose -Message "Exporting $($notebooks.count) notebooks to $Path" $allPages = [System.Collections.ArrayList]::new() $apiCount = 1 foreach ($book in $notebooks) { $apiCount++ Write-Verbose -Message "Exporting notebook $($book.displayName)" $sections = Invoke-GraphRequest -Query "$($User)/onenote/notebooks/$($book.id)/sections" foreach ($section in $sections) { $apiCount++ Write-Verbose -Message "Exporting section $($section.displayName)" [array]$pages = Invoke-GraphRequest -Query "$($User)/onenote/sections/$($section.id)/pages" | ForEach-Object { $_ | Add-Member -NotePropertyName Notebook -NotePropertyValue $book.displayName -PassThru | Add-Member -NotePropertyName Section -NotePropertyValue $section.displayName -PassThru } $allPages.AddRange($pages) } } # One call per page at least, if ($allPages.Count -gt (400 - $apiCount)) { $duration = [timespan]::FromHours($allPages.Count / 400) Write-Warning -Message "Microsoft imposes a limit of 400 requests per hour. You have $($allPages.Count) pages to export, so it will likely take $duration to finish." } foreach ($page in $allPages) { $bookPath = Join-Path -Path $Path -ChildPath ($page.Notebook -replace '[\\\/\:\*\?\"\<\>\|]', '_') $sectionPath = Join-Path -Path $bookPath -ChildPath ($page.Section -replace '[\\\/\:\*\?\"\<\>\|]', '_') if (-not (Test-Path -Path $sectionPath)) { $null = New-Item -Path $sectionPath -ItemType Directory -Force } Write-Verbose -Message "Exporting page $($page.title)" $sanitizedTitle = $page.title -replace '[\\\/\:\*\?\"\<\>\|]', '_' $pagePath = Join-Path -Path $sectionPath -ChildPath "$($page.createdDateTime.ToString('yyyy-MM-dd'))_$($sanitizedTitle).md" $content = Invoke-GraphRequest -Query "$($User)/onenote/pages/$($page.id)/content" $imgCount = 0 foreach ($image in $content.SelectNodes("//img")) { $header = @{ Authorization = "Bearer $token" } $imgName = '{0}_{1:d10}.png' -f $sanitizedTitle, $imgCount $imgPath = Join-Path -Path $sectionPath -ChildPath resources if (-not (Test-Path -Path $imgPath)) { $null = New-Item -Path $imgPath -ItemType Directory -Force } Invoke-RestMethod -Method Get -Uri $image.'data-fullres-src' -Headers $header -OutFile (Join-Path $imgPath $imgName) $image.src = [uri]::EscapeUriString(('./resources/{1}' -f $section.displayName, $imgName)) $imgCount++ } $content.OuterXml | ConvertFrom-HTMLToMarkdown -DestinationPath $pagePath -Format } |