PowerShell & OneNote: Seiten (Vorlagen) kopieren

Neulich erhielt ich von einem Leser eine sehr interessante Anfrage zum Thema ‘Seite aus Vorlage erstellen’.
Da ich bisher noch keinen Weg gefunden habe, eine “OneNote Seitenvorlage” als neue Seite einzufügen, verwende ich folgenden Workaround:
Zuerst lege ich einen neuen Abschnitt “Vorlagen” an, um dort eine Seite als Vorlage mit dem gewünschten Inhalt zu erstellen. Der Inhalt dieser Seite lässt sich dann in die neu erstellte Seite kopieren.

Vorlagen-Abschnitt
# div. Vorbereitungen
$NotebookName = 'MeinNotizbuch'
$TemplateSectionName = 'Vorlagen'
$TemplatePageTitle = 'Vorlage Tagesplaner'

$TargetSectionName = 'MeineNotizen'
$TargetPageTitle = 'Seite aus Vorlage erstellt'

# OneNote Struktur einlesen und Vorlage suchen
[void][reflection.assembly]::LoadWithPartialName("Microsoft.Office.Interop.Onenote")
$OneNote = New-Object Microsoft.Office.Interop.Onenote.ApplicationClass

[Xml]$ONXml = $Null
$Onenote.GetHierarchy($Null, [Microsoft.Office.InterOp.OneNote.HierarchyScope]::hsPages, [ref]$ONXml)

$MyNotebook = $ONXml.Notebooks.Notebook | where name -eq $NoteBookName
$MyTemplateSection = $MyNotebook.Section | where name -eq $TemplateSectionName
$MyTemplatePage = $MyTemplateSection.Page | where name -eq $TemplatePageTitle

[ref]$TemplatePageXML = ''
$OneNote.GetPageContent($MyTemplatePage.ID,[ref]$TemplatePageXML,[Microsoft.Office.Interop.OneNote.PageInfo]::piAll)
$null = [Reflection.Assembly]::LoadWithPartialName('System.Xml.Linq')

# neue Seite erstellen
$MyTargetSection = $MyNotebook.Section | where name -eq $TargetSectionName
[ref]$newpageID = ''
$OneNote.CreateNewPage($MyTargetSection.ID,[ref]$newpageID,[Microsoft.Office.Interop.OneNote.NewPageStyle]::npsBlankPageWithTitle)

# Inhalt der Vorlage auslesen und kopieren
[String]$NewContent = $TemplatePageXML.Value
$NewContent = $NewContent.Replace($MyTemplatePage.ID, $newpageID.Value)

$null = [Reflection.Assembly]::LoadWithPartialName('System.Xml.Linq')
$NewDoc = [System.Xml.Linq.XDocument]::Parse($NewContent)
$Nodes = $NewDoc.Descendants()

# da jedes Objekt eine eigene ID hat, muss diese vor dem einfügen entfernt werden
foreach ($Node in $Nodes) {
  if ($Node.Attribute("objectID") -ne $null) {
    $Node.Attributes("objectID").Remove()
  }
}

# neuen Notiztitel setzen
[string]$NewContent = $NewDoc.ToString()
$NewContent = $NewContent.Replace($TemplatePageTitle,$TargetPageTitle)

# neu erstellte Seite updaten
$onenote.UpdatePageContent($NewContent)
Notizen Abschnitt mit der kopierten Seite
Print Friendly, PDF & Email

PowerShell & OneNote: ein Tagebuch erstellen

Ich nutze für meine täglichen Notizen ein “OneNote-Tagebuch”, welches als Notizbuch-Name das jeweilige Jahr trägt. Dieses hat 12 Abschnitte – für jeden Monat einen – und jeweils pro (Arbeits-)Tag eine Seite:

OneNote-Tagebuch
OneNote Tagebuch

Da es überhaupt keinen Spaß macht, so ein Tagebuch jedes Jahr manuell anzulegen, habe ich mir folgendes PowerShell-Script dafür gebastelt:

#requires -Version 3.0

$Year = '2017'
$NotebookPath = "https://d.docs.live.net/0123456789abcdef/Dokumente/$($Year)/"

# Notizbuch alternativ lokal speichern
#$NotebookPath = "C:\Temp\$($Year)"

# neues Notizbuch erstellen
$OneNote = New-Object -ComObject OneNote.Application
$Scope = [Microsoft.Office.Interop.OneNote.HierarchyScope]::hsNotebooks
[ref]$xml = ""
$OneNote.OpenHierarchy($NotebookPath, "", $xml, "cftNotebook")

# für jeden Monat einen neuen Abschnitt anlegen
1..12 | % {
    $Month = "{0:00}" -f $_
    $SectionPath = $NotebookPath + $Month + '.one'

    # neuen Abschnitt erstellen
    [ref]$xmlSection = ""
    $OneNote.OpenHierarchy($SectionPath, "", $xmlSection, "cftSection")

    # für jeden Arbeitstag (Montag - Freitag) im jeweiligen Monatsabschnitt eine Seite erstellen
    1..([DateTime]::DaysInMonth($Year, $Month)) | % {
        $Day = Get-Date -Year $Year -Month $Month -Day $PSItem -Hour 0 -Minute 0 -Second 0
        $Tag = $Day.Date.Day.ToString('D2')
        $Jahr = $Year.Substring(2, 2)
        $SiteName = "$($Tag).$($Month).$($Year) "

        Switch ($Day.DayOfWeek) {
            { $_ -eq 'Monday' } { $SiteName += 'Mo' }
            { $_ -eq 'Tuesday' } { $SiteName += 'Di' }
            { $_ -eq 'Wednesday' } { $SiteName += 'Mi' }
            { $_ -eq 'Thursday' } { $SiteName += 'Do' }
            { $_ -eq 'Friday' } { $SiteName += 'Fr' }
            default { $SiteName = '' }
        }

        if ($SiteName) {
            Write-Host $SiteName

            [ref]$newpageID = ''
            $OneNote.CreateNewPage($xmlSection.Value, [ref]$newpageID, [Microsoft.Office.Interop.OneNote.NewPageStyle]::npsBlankPageWithTitle)

            [ref]$NewPageXML = ''
            $OneNote.GetPageContent($newpageID.Value, [ref]$NewPageXML, [Microsoft.Office.Interop.OneNote.PageInfo]::piAll)

            $null = [Reflection.Assembly]::LoadWithPartialName('System.Xml.Linq')
            $xDoc = [System.Xml.Linq.XDocument]::Parse($NewPageXML.Value)

            $title = $xDoc.Descendants() | Where-Object -Property Name -Like -Value '*}T'

            if (-not $title)
                { throw 'Fehler: kann Titel der neuen OneNote Seite nicht auslesen' }

            # Seitentitel anpassen
            $title.Value = "$SiteName"
            Write-Verbose -Message "Seitentitel ändern"
            $onenote.UpdatePageContent($xDoc.ToString())
        }
    }
}

So kann ich auch Jahre später noch nachvollziehen, wann ich was gemacht habe oder an welchem Datum es welches Problem mit einem bestimmten System gab…

Print Friendly, PDF & Email

PowerShell & OneNote: Notizbuch, Abschnitte und Seiten anlegen

Natürlich lassen sich mit der PowerShell auch neue OneNote-Notizbücher und darin Abschnitte und Seiten anlegen. 

Zuerst starten wir mit einem leeren Notizbuch.

Der hierfür benötigte “NotebookPath” ist wie folgt aufgebaut:
$NotebookPath = “https://d.docs.live.net/[OneDrive-ID]/Dokumente/[NotizbuchName]/”
oder alternativ bei lokaler Ablage:
“C:\Temp\MeinNotizbuch\”
$NotebookPath = "https://d.docs.live.net/0123456789abcdef/Dokumente/MeinNotizbuch/"
# alternativ kann auch ein lokaler Speicherort verwendet werden:
#$NotebookPath = "C:\Temp\MeinNotizbuch\"

# neues Notizbuch erstellen:
$OneNote = New-Object -ComObject OneNote.Application
$Scope = [Microsoft.Office.Interop.OneNote.HierarchyScope]::hsNotebooks
[ref]$xml = ""
$OneNote.OpenHierarchy($NotebookPath, "", $xml, "cftNotebook")
Danach können Abschnitte (Tabs) zum Notizbuch hinzugefügt werden. Der “SectionPath” setzt sich wie folgt zusammen:
SectionPath = [NotebookPath] + [Abschnitts-Name] + “.one”

Also z.B. “https://d.docs.live.net/0123456789abcdef/Dokumente/MeinNotizbuch/ErsterAbschnitt.one
oder alternativ lokal:
“C:\Temp\MeinNotizbuch\ErsterAbschnitt.one”
# Pfad festlegen
$SectionPath = $NotebookPath + "ErsterAbschnitt" + ".one"

# neuen Abschnitt erstellen
[ref]$xmlSection = ""
$OneNote.OpenHierarchy($SectionPath, "", $xmlSection, "cftSection")
Mit der $xmlSection wird die ID des neu angelegten Abschnitts zurückgeliefert – diese wird benötigt, um Seiten in den Abschnitt einzufügen:
[ref]$newpageID = ''
$OneNote.CreateNewPage($xmlSection.Value,[ref]$newpageID,[Microsoft.Office.Interop.OneNote.NewPageStyle]::npsBlankPageWithTitle)
Nun noch den Seitentitel ($title.Value) anpassen und fertig:
[ref]$NewPageXML = ''
$OneNote.GetPageContent($newpageID.Value,[ref]$NewPageXML,[Microsoft.Office.Interop.OneNote.PageInfo]::piAll)

$null = [Reflection.Assembly]::LoadWithPartialName('System.Xml.Linq')
$xDoc = [System.Xml.Linq.XDocument]::Parse($NewPageXML.Value)

$title = $xDoc.Descendants() | Where-Object -Property Name -Like -Value '*}T'

if (-not $title) {
  throw 'Fehler: kann Titel der neuen OneNote Seite nicht auslesen'
}

$title.Value = "Meine erste Seite"
$onenote.UpdatePageContent($xDoc.ToString())
Das Ergebnis sieht dann so aus:

MeinNotizbuch

MeinNotizbuch

 
Print Friendly, PDF & Email

OneNote: vorhandene Notizbücher & Speicherorte per PowerShell auslesen

Seit es OneNote gibt, nutze ich das Programm sowohl geschäftlich als auch privat als mein 2. Gehirn, also um meine Notizen, Protokolle, Planungen, Checklisten und vieles mehr abzulegen und vor allem: wiederzufinden 😉
Und so war es naheliegend, mir mal anzuschauen, was hier mit der PowerShell alles anzustellen ist. Ein guter Einstieg dafür war Richard Siddaway’s Artikel “OneNote and XML-finding notebooks” sowie die MSDN OneNote Developer Reference unter https://msdn.microsoft.com/en-us/library/office/jj680120.aspx.
Zuerst machte es also Sinn, mir mal meine vorhandenen Notebooks inkl. deren Speicherort aufzulisten:
#requires -Version 4.0
function Get-OneNote_Notebook_Path
{
  <#
      .Synopsis
      Pfad zu (allen) OneNote 2013 / 2016 Notizbüchern auflisten
      .DESCRIPTION
      liest den Speicherort aller OneNote Notizbücher aus
      .EXAMPLE
      Get-OneNote_Notebook_Path
      listet die Pfade aller gefundenen Notizbücher auf

      Name                 Path
      ----                 ----
      MeinNotizbuch        https://d.docs.live.net/.../Dokumente/MeinNotizbuch/
      lokalesNotizbuch     C:\Temp\lokalesNotizbuch

      .EXAMPLE
      Get-OneNote_Notebook_Path -Notebook 'MeinNotizbuch'

      Name                 Path
      ----                 ----
      MeinNotizbuch        https://d.docs.live.net/.../Dokumente/MeinNotizbuch/

      .INPUTS
      Notebook
        Name des Notizbuchs, von dem der Speicherort angezeigt werden soll
      .OUTPUTS
      Name
        Name des Notizbuchs
      Path
        Speicherort des Notizbuchs
  #>
  Param([String]$Notebook='*')

  $OneNote = New-Object -ComObject OneNote.Application -ErrorAction SilentlyContinue
  if (-not $OneNote) {
    throw 'Fehler: OneNote Objekt kann nicht erstellt werden (COMobject error)'
  }

  $ScopePages = [Microsoft.Office.Interop.OneNote.HierarchyScope]::hsPages
  [ref]$xml = ''
  $OneNote.GetHierarchy($null, $ScopePages, $xml)

  $schema = @{one = 'http://schemas.microsoft.com/office/onenote/2013/onenote'}

  $xpath = '//one:Notebooks/one:Notebook'
  
  $List =  @() 

  Select-Xml -Xml ([xml]$xml.Value) -Namespace $schema -XPath $xpath | ForEach-Object -Process {
    $List += New-Object psobject -Property @{
      Name = $PSItem.Node.Name
      Path = $PSItem.Node.Path
    }
  }

  $List.Where({$_.Name -like $Notebook})
}
Als Ergebnis erhalte ich folgende Ausgabe:

OneNote Notizbücher & Speicherpfad

OneNote Notizbücher & Speicherpfad

Alternativ auch nur ausgewählte Notizbücher:

Ausgewählte OneNote Notizbücher & Speicherpfad

Ausgewählte OneNote Notizbücher & Speicherpfad

Print Friendly, PDF & Email