PowerPoint-Folien mit PowerShell in Text konvertieren

Dieser Beitrag ist etwas praxisorientierter. Zwei Dinge vorweg: Das Thema ist alles andere als nue und die vorgestellte Lösung ist alles andere als perfekt. Es geht ausschließlich darum, wie sich mit verhältnismäßig wenig Aufwand der Text aus den Folien einer PowerPoint-Datei per PowerShell extrahieren lässt. Sozusagen von Power zu Power (sollte ich im Folgenden einmal PowerShell mit PowerPoint verwechseln, bitte ich dies zu entschuldigen. Das passiert mir sogar in meinen Schulungen hin und wieder;).

Ausgangspunkt ist die Assembly DocumentFormat.OpenXml.dll, die Teil des Open XML SDKs von Microsoft ist. Es gibt sie in verschiedenen Varianten, sowohl für .NET 4.6 als auch für .NET Core. Ich verwende die Variante für .NET 4.6. Ich gebe mit Absicht keinen Download-Link an, da man sie an verschiedenden Stellen findet. Entwickler nutzen natürlich das Nuget-Package, das sich theoretisch auch per PowerShell und Install-Package hinzufügen lässt. Aus der Package-Datei (einfach ein .Zip anhängen) muss dann die Dll-Datei herauskopiert werden. Der Rest des Package kann gefahrlos „entsorgt“ werden.

Alle folgenden Beispiele gehen davon aus, dass sich die Dll-Datei im selben Verzeichnis befindet wie die Ps1-Datei.

Bevor es losgeht, noch ein Tipp. Der programm- bzw. skriptgesteuerte Umgang mit den „modernen“ Microsoft Office-Dokumentformaten ist sehr gut dokumentiert. Wie sich die Texte aus einer PowerPoint-Datei extrahieren lassen, z.B. unter der folgenden Adresse:

https://docs.microsoft.com/en-us/office/open-xml/how-to-get-all-the-text-in-all-slides-in-a-presentation

Die Beispiele sind natürlich alle in C# oder VB verfasst. Höchstwahrscheinlich gibt es bereits fertige PowerShell-Module für den Umgang mit PowerPoint-Präsentationen. Ich war zu bequem, um danach zu suchen. Im Folgenden geht es daher in erster Linie um das Ausprobieren mit dem Ziel, die Hintergründe besser verstehen zu können.

Schritt 1: Als erstes wird die Assembly per Add-Type geladen. Dabei kommt einmal mehr das sehr praktische using namespace zum Einsatz.

Schritt 2: Im nächsten Schritt wird die Pptx-Datei geöffnet und das PresentationPart-Objekt angesprochen.

Schritt 3: Ausgabe der Anzahl der Folien

Als kleine „Warm-Up“-Übung wird die Anzahl der Folien (Slides) ausgegeben.

Hier tritt eine typische PowerShell-Besonderheit zum Tragen, über die ich auch nach > 16 Jahren PowerShell immer wieder „stolpere“. Ohne die explite Array-Klammerung per @() werden alle SlidePart-Objekte einzeln angesprochen und die Count-Eigenschaft liefert für jedes SlidePart-Objekt eine 1. Solche Besonderheiten findet man immer durch Ausprobieren heraus.

Schritt 4: Holen der SlideIds

Für das Durchlaufen aller Slides wird die SlideIdList und ihre ChildElements benötigt.

$slideIds = $presentationPart.Presentation.SlideIdList.ChildElements

Schritt 5: Durchlaufen aller Slides

Wir nähern uns dem Finale, wenngleich es noch ein Zwischenhügel erklommen werden muss. Abe die foreach-Schleife darf man bereits eingeben.

Schritt 6: Holen des SlidePart

Jetzt wird es ein wenig komplizierter. Um an den Folieninhalt zu kommen, wird der SlidePart benötigt. Dazu wird die RelationShipId benötigt, um über diese über den allgemeinen PresentationPart den SlidePart zu holen.

Schritt 7: Zusammenstellen des Textes des SlidePart

Liegt das SlidePart-Objekt vor, geht es „nur noch“ darum, den Text zu erhalten. Das SlidePart-Objekt besitzt, wie alle Inhaltsobjekte, eine praktische Descendants<T>-Methode, die alle Abkömmlinge des Knotens des angegebenen Typs holt. Da sich diese C#-Schreibweise aber nicht 1:1 übertragen lässt, kann die Methode daher nicht direkt aufgerufen werden.

Es gibt zwei Alternativen:

>Aufruf von Descendants() ohne Parameter. In diesem Fall werden alle Abkömmlinge zurückegeben. Die Text-Elemente werden dann per Where-Object gefilter.

>Aufruf der generischen Descendants<T>()-Methode mit Hilfe von etwas „Reflection-Magic“, die aber einfach und überschaubar ist (die Invoke-GenericMethod-Fuction stelle ich in einem anderen Blog-Beitrag vor).

Im Folgenden verwende ich die zweite Variante.

Alle Textelemente eines Slide werden zu einem StringBuilder-Objekt hinzugefügt, dessen Inhalt am Ende ausgegeben wird. Warum einen StringBuilder und nicht einfach +=? Bei größeren Textmengen ist diese Variante deutlich schneller.

Der Vollständigheit halber stelle ich die Invoke-GenericMethod-Function ohne weiteren Erläuterungen vor. Nur soviel: Damit es nicht zu kompliziert wird, funktioniert der Methodenaufruf nur dann, dass die über die Abfrage von Name und IsGenericMethod tatsächlich nur die eine Methode resultiert, die auch aufgerufen werden soll.

Ansonsten deckt das Skript von Dave Wyatt alle Eventualitäten ab, ist dafür aber auch „etwas“ umfangreicher:

https://gallery.technet.microsoft.com/Invoke-Generic-Methods-bf7675af/view/Discussions#content

Das war alles. Die vorgestellte Befehlsfolge sollte den Textinhalt einer beliebigen Pptx-Datei ausgeben.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.