moichn
Goto Top

Automatisierung der Serienbrieffunktion in Word über ein PowerShell-Skript

Hallo,
ich habe folgende Frage:
Wie kann man über Powershell ein Skript schreiben, das die Serienbrieffunktion in einer Word-Datei startet und eine spezielle Datei abspeichert?

Hintergrund:
Ich befinde mich in der Ausbildung und habe in meinem Praxiseinsatz gesehen, dass viel Arbeitszeit durch das manuelle Ausfüllen von Vorlagen verschwendet wird. Das habe ich in einem ersten Schritt über die Serienbrieffunktion und eine Excel-Datenbank gelöst. Das funktioniert auch super.
Leider sind das (gerade für die älteren Leute) viel zu kompliziert: Man muss erst die das Dokument mit der Tabelle verknüpfen, dann einen Serienbrief starten, das gewünschte Dokument erstellen und abspeichern. Macht man einen Fehler wird beispielsweise die gesamte Tabelle in einem Word-Dokument ausgegeben, was zu unmut führt, weil "das ja dann mehr Arbeit ist, als wenn ich das selbst ausfüllen würde".
Das ist gerade für Ältere sehr kompliziert und außerdem 1000 unnötige Klicks. Daher möchte ich das so gut wie möglich automatisieren.
Mein Ausbildungsleiter hat zu mir gesagt, dass das über PowerShell möglich wäre und ich das mal versuchen soll.
Leider hat meine Google Recherche leider keine Infos gebracht, die mir weiterhelfen.


Anforderungen:
Ich möchte, dass zukünftig Daten manuell in eine bestehende Excel-Tabelle eingegeben werden (Spalten sind sowas wie Name und Adresse).
Dann soll in einem zweiten Schritt manuell ein Powershell-Skript gestartet werden, das folgendes leisten soll:
  • Abfrage für welche Zeile ein Dokument erstellt werden soll
  • Verknüpfung des Word-Dokuments mit der Excel-Tabelle
  • Erstellung eines Serienbriefs für die eingegebene Zeile
  • Anlegen eines Ordners anhand einer Syntax (Name, Vorname, Datum des heutigen Tages)
  • Abspeichern des Dokuments als Word-Datei in dem jeweiligen Ordner

Content-ID: 52301435974

Url: https://administrator.de/contentid/52301435974

Ausgedruckt am: 23.11.2024 um 13:11 Uhr

erikro
erikro 02.02.2024 um 10:50:33 Uhr
Goto Top
Moin,

Powershell geht sicherlich auch. Aber imho wäre VBA die richtige Sprache. Damit könntest Du dann z. B. nette Knöpfchen in die Exceltabelle einfügen.

Liebe Grüße

Erik
11078840001
11078840001 02.02.2024 um 10:53:32 Uhr
Goto Top
HansDampf06
HansDampf06 02.02.2024 um 11:05:19 Uhr
Goto Top
Wieso PowerShell? MS Office und damit gerade MS Word hat doch VBA (= Visual Basic for Application(s))?!

Das, was Du lösen willst, wird über VBA aka Makros realisiert, und zwar über die Automakros als Startpunkt.

Insoweit ist MS Word sehr hilfreich, weil jedes Dokument (.docx oder docm) mit einer speziellen / aufgabenbezogenen Dokumentenvorlage (.dotm) verknüpft wird (anstelle von Normal.dotm). Wird ein neues Dokument erstellt, wird es auf Basis dieser Dokumentenvorlage erstellt (Menüpunkt "Neue Datei"). In die Dokumentenvorlage gehört das Modul mit den Automakros und in diesem Modul erstellst Du die Automakros für Dokument öffnen / schließen etc. Über diese Automakros rufst Du - ich würde das jedenfalls in ein separates Sub-Makro (auch in einem zweiten Modul) packen - eine Routine, die die Serienbrieffunktion mit den entsprechenden Parametern für die Datenquelle konfiguriert.

Und schwuppdiwupp ist nichts mehr zu tun, außer mit den Dokumenten zu arbeiten und natürlich die Datenquelle zu pflegen ...

Möchte man es professioneller machen, dann könnte man das Ganze dahingehend ausbauen, dass jedes Dokument eine eigene ID bekommt und die Daten aus der Datenquelle auf der Basis dieser ID abgerufen werden. Die Zuordnung der Datensätze zu einem Dokument wird dann aber wohl eher außerhalb von Word erfolgen müssen, wenngleich das natürlich auch mit Formularen in Word denk-/machbar ist. Ansonsten können unter dem Menü Serienbrief in Word die relevanten Datensätze ausgewählt werden.

Schließlich kann die Interaktion mit der Datenquelle mittels Makros zugleich über eigene Menüpunkte dauerhaft zugreifbar gemacht werden.

Viele Grüße
HansDampf06
Blackmann
Blackmann 02.02.2024 um 12:45:07 Uhr
Goto Top
Moin,

ich habe ein ähnliches Problem, Ausfüllen eines gleichbleibenden Word-Dokuments, wie folgt erledigt:

1. In Excel eine Seite mit den notwendigen Variablen ausgefüllt, Listenansicht --> wenn fertig, dann Button: Speichern & Drucken
2.1. Excel Datei in einem weiteren Blatt für Word vorbereitet, Zeilenansicht (und auch Daten in Excel gespeichert)
2.2. Aus der Zeilenansicht ein Worddokument mittels VBA/Serienbrief ausgefüllt und zum Drucker geschickt.

Das läuft gut, man hat nur die Liste in Excel auszufüllen und per Klick entsteht das Dokument.

BG BM
micneu
micneu 03.02.2024 um 15:17:44 Uhr
Goto Top
Ich habe sowas mal für mein Team in Python geschrieben, Word Dokument erstellt, und bestimmte Bereiche definiert die ersetzt werden sollen und entsprechend die Daten aus einer csv geholt. Alles jetzt sehr vereinfacht beschrieben
moichn
moichn 07.02.2024 um 10:39:02 Uhr
Goto Top
Ich sollte das Problem unbedingt in Powershell lösen.
Das habe ich mittlerweile auch gut hinbekommen.
Allerdings muss ich immer manuell das jeweilige Tabellenblatt auswählen (Tabelle1).
Das bedeutet: Ich starte das Skript, gebe die ID ein, dann öffnet sich irgendwo hinter den offenen Tabs ein Fenster in dem ich manuell Tabelle1 auswählen muss (siehe Bild) und ich bekomme es einfach nicht hin, dass das automatisch geht.


Hat da jemand eine Idee?

Der Code sieht so aus:

# manuell zu definierende Dateipfade und Variablen
$wordPfad = "...\Brief.docx"  
$excelPfad = "...\DB.xlsx"  
$savePfad = "...\"  
$spalteName = 3
$spalteVorname = 4

# Word-Anwendung öffnen
$word = New-Object -ComObject Word.Application

# Word-Anwendung unsichtbar machen
$word.Visible = $false

# ID einlesen
[int]$ID = Read-Host "Geben Sie die ID ein"  

# Hinweis auf manuelle Tabellenauswahl
Write-Host "  
Um ein Dokument für die ID $ID zu erzeugen, öffnet sich automatisch ein Fenster."  
Write-Host "Bitte bestätigen Sie dort die Auswahl von Tabelle 1, damit das Dokument erzeugt werden kann." -ForegroundColor Green  
Write-Host "  
Die Anwendung schließt sich danach automatisch."  

# Excel-Objekt erstellen
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$workbook = $excel.Workbooks.Open($excelPfad)
$worksheet = $workbook.Sheets.Item("Tabelle1")  

#Speicherdaten
$zeile = ($ID + 1)
$name = $worksheet.Cells.Item($zeile, $spalteName).Text
$vorname = $worksheet.Cells.Item($zeile, $spalteVorname).Text
$erstellungsdatum = Get-Date -Format "yy-MM-dd"  

# Ordner erstellen
$folderName = "$erstellungsdatum $name, $vorname"  
$folderPath = Join-Path $savePfad $folderName
New-Item -ItemType Directory -Path $folderPath | Out-Null
$ablageort = "$folderPath\Brief_ausgefüllt.docx"  

# Schließen Sie das Arbeitsblatt und die Excel-Anwendung
$workbook.Close()
$excel.Quit()

# Word-Dokument öffnen
$doc = $word.Documents.Open($wordPfad)

# Serienbrieffunktion aktivieren
$mailMerge = $doc.MailMerge

# Datenquelle öffnen und Datensatzauswahl festlegen
$datasource = $mailMerge.OpenDataSource($excelPfad)
#$datasource.Open($excelPfad, $null, $true, $null, $null, $null, $null, $null, $null, $null, $null, "Tabelle1$") 

# Serienbrieffunktion aktivieren
$mailMerge.Destination = [Microsoft.Office.Interop.Word.WdMailMergeDestination]::wdSendToNewDocument

# Benutzer nach der Startzeile fragen und für Von und An festlegen
$mailMerge.DataSource.FirstRecord = $ID   # Startzeile
$mailMerge.DataSource.LastRecord = $ID    # Endzeile

# Serienbrief zusammenführen
$mailMerge.Execute()

# Speichern des Serienbriefs unter dem angegebenen Pfad
$word.ActiveDocument.SaveAs([ref]$ablageort)

# Ursprüngliches Word-Dokument schließen
$doc.Close()

# Word-Dokument schließen
$word.Quit()

Hinweis:
Die Zeile "#$datasource.Open($excelPfad, $null, $true, $null, $null, $null, $null, $null, $null, $null, $null, "Tabelle1$")"
ist im Code enthalten, aber kommentiert, weil sie das Problem nicht löst.
Stattdessen wird, nachdem die ID abgefragt wurde und manuell Tabelle1 ausgewählt wurde, folgende Fehlermeldung angezeigt:

Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
In Zeile:54 Zeichen:1
+ $datasource.Open($excelPfad, $null, $true, $null, $null, $null, $null ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
fenster
11078840001
11078840001 07.02.2024 aktualisiert um 11:35:32 Uhr
Goto Top
Die Funktion OpenDataSource gibt kein Objekt zurück und du versuchst eine Methode aufzurufen von einem Objekt ($datasource) das es nicht gibt genau das teilt dir die Fehlermeldung mit face-smile.

Du musst der Methode "OpenDataSource" das SQL Statement mitgeben damit Word weiß welches Sheet es nehmen muss.
# .....
$x = [System.Reflection.Missing]::Value
$mailMerge = $doc.MailMerge
$mailmerge.OpenDataSource($excelPfad,0,$false,$true,$false,$false,$x,$x,$x,$x,$x,$x,'SELECT * FROM `Tabelle1$`')  
$mailMerge.Destination = [Microsoft.Office.Interop.Word.WdMailMergeDestination]::wdSendToNewDocument
# .....
https://learn.microsoft.com/de-de/office/vba/api/word.mailmerge.opendata ...
moichn
Lösung moichn 07.02.2024 um 13:48:35 Uhr
Goto Top
Vielen Dank für die ganze Hilfe!
Das Skript ist fertig und funktioniert. Sicher gibt es noch viel Verbesserungspotential, aber das reicht mir erstmal face-smile

# manuell zu definierende Dateipfade und Variablen
$wordPfad = "Pfad\Name.docx"  
$excelPfad = "Pfad\Name.xlsx"  
$savePfad = "Pfad\"  
$spalteName = 3
$spalteVorname = 4

# Word-Anwendung öffnen
$word = New-Object -ComObject Word.Application

# Word-Anwendung unsichtbar machen
$word.Visible = $false

# ID einlesen
[int]$ID = Read-Host "Geben Sie die ID ein"  

# Rückmeldung an User
Write-Host "  
Das Dokument für die ID $ID wird nun erzeugt." -ForegroundColor Green  
Write-Host "Die Anwendung schließt sich automatisch."  

# Excel-Objekt erstellen
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$workbook = $excel.Workbooks.Open($excelPfad)
$worksheet = $workbook.Sheets.Item("Tabelle1")  

#Speicherdaten
$zeile = ($ID + 1)
$name = $worksheet.Cells.Item($zeile, $spalteName).Text
$vorname = $worksheet.Cells.Item($zeile, $spalteVorname).Text
$erstellungsdatum = Get-Date -Format "yy-MM-dd"  

# Ordner erstellen
$folderName = "$erstellungsdatum $name, $vorname"  
$folderPath = Join-Path $savePfad $folderName
New-Item -ItemType Directory -Path $folderPath | Out-Null
$ablageort = "$folderPath\Brief_ausgefüllt.docx"  

# Schließen Sie das Arbeitsblatt und die Excel-Anwendung
$workbook.Close()
$excel.Quit()

# Word-Dokument öffnen
$doc = $word.Documents.Open($wordPfad)

# Serienbrieffunktion aktivieren
$x = [System.Reflection.Missing]::Value
$mailMerge = $doc.MailMerge

# Datenquelle öffnen und Datensatzauswahl festlegen
$mailmerge.OpenDataSource($excelPfad,0,$false,$true,$false,$false,$x,$x,$x,$x,$x,$x,'SELECT * FROM `Tabelle1$`')    
$mailMerge.Destination = [Microsoft.Office.Interop.Word.WdMailMergeDestination]::wdSendToNewDocument

# Benutzer nach der Startzeile fragen und für Von und An festlegen
$mailMerge.DataSource.FirstRecord = $ID   # Startzeile
$mailMerge.DataSource.LastRecord = $ID    # Endzeile

# Serienbrief zusammenführen
$mailMerge.Execute()

# Speichern des Serienbriefs unter dem angegebenen Pfad
$word.ActiveDocument.SaveAs([ref]$ablageort)

# Ursprüngliches Word-Dokument schließen
$doc.Close()

# Word-Dokument schließen
$word.Quit()