Genera documentos Word con PowerShell
¿Conoces PowerShell? Es una herramienta que viene ya instalada en todos los Windows que te permite automatizar muchas cosas y te permite hacer cosas que ni imaginarías. Eso sí, es para nostálgicos del MS-DOS o línea de comandos, como yo 😊.
Uno de mis últimos grandes descubrimientos, como siempre creado por la necesidad, ha sido que puedes generar un script de PowerShell que genere automáticamente un documento Word y lo vas completando con el contenido que quieras.
Ya puse un ejemplo en mi post: Cómo documentar tu ETL del SSIS con PowerShell pero ahora quiero poner los comandos de forma más explícita, ya que, para algunas cosas ,como personalizar la portada, la documentación escasea.
Voy a empezar desde el principio: Los scripts los puedes escribir en un notepad o donde quieras y si los guardas como con la extensión ps1 Windows detecta que es un script de Powershell y te da la opción a lanzarlo. Otra opción, es utilizar el programa «Windows PowerShell ISE» que incorpora el editor y la línea comandos, o directamente la línea de comandos abriendo «Windows PowerShell». Una vez, conocido esto, voy con lo que nos trae a este post: crear un documento word.
Lo primero es configurar y crear el documento Word. Lo único que hay que indicar es la url donde se quiere ubicar y si se quiere que se vea o no mientras se genera.
###############################################################################################
# Datos a rellenar
# $docfile --> Url donde se dejara el documento
###############################################################################################
#Configuración del documento Word
#url
$docfile = "C:\Test\EjemDoc.docx"
#Creamos instancia del objeto word
$MSWord = New-Object -ComObject Word.Application
#Lo hacemos visible
$MSWord.Visible = $True
#Creamos nuevo documento
$mydoc = $MSWord.Documents.Add()
A continuación, y de manera opcional, se pueden rellenar algunas de las propiedades del documento. Esto viene bien para rellenar ciertos parámetros automáticos a posteriori.
#Rellenamos algunas propiedades del documento.
#Título
$comObject = $mydoc.BuiltInDocumentProperties("Title")
$binding = "System.Reflection.BindingFlags" -as [type]
[System.__ComObject].invokemember("Value",$binding::SetProperty,$null,$comObject,"Ejemplo de doc con PowerShell")
#Compañia - Empresa
$comObject = $mydoc.BuiltInDocumentProperties("Company")
$binding = "System.Reflection.BindingFlags" -as [type]
[System.__ComObject].invokemember("Value",$binding::SetProperty,$null,$comObject,"Data Crazy World")
#Autor
$comObject = $mydoc.BuiltInDocumentProperties("Author")
$binding = "System.Reflection.BindingFlags" -as [type]
[System.__ComObject].invokemember("Value",$binding::SetProperty,$null,$comObject,"Cristina Tarabini-Castellani")
¡Y ahora la portada!. Se puede construir a mano una, pero es más sencillo utilizar alguna de las plantillas que se incorporan por defecto en el Word. Las diferentes portadas que te ofrecen son:
Igual hay más, pero estas son las que he podido averiguar. Hay que tener en cuenta, que yo manejo la versión en español y por tanto los nombres están en español. Si manejas la versión en inglés, tendrás que poner los nombres ingleses.
Y ahora que ya te he hablado un poco de las opciones que hay, toca preparar la portada para añadirla al documento.
#Preparamos la portada
$CoverPage = 'Movimiento' #Nombre de la plantilla de la portada
$Selection = $MSWord.application.selection
#Se coge la plantilla de la portada elegida
$MSWord.Templates.LoadBuildingBlocks()
$bb =$MSWord.templates | Where-Object -Property name -EQ -Value 'Built-In Building Blocks.dotx'
$part = $bb.BuildingBlockEntries.item($CoverPage)
Con esto ya tendría la portada, pero hay que tratarla un poco y este código que incluyo a continuación, es para personalizar la portada “Movimiento”. Si se escoge otra, habría que estudiar cómo personalizarla. En este código, cambio la imagen y el color, además de rellenar algunos de los textos que vienen en la portada.
#Tratamos la plantilla de portada elegida.
######################### Esto es para la portada "Movimiento"
$null = $part.Insert($MSWord.Selection.range, $true)
#Las 3 líneas verdes verticales. Les voy a cambiar el color a Rosa :)
$Selection.Document.Shapes.Item("Grupo 78").GroupItems[1].Fill.ForeColor.Rgb = 16711847 ##ff00a7
#El rectángulo grande verde. También lo cambio a Rosa
$Selection.Document.Shapes.Item("Grupo 78").GroupItems[2].Fill.ForeColor.Rgb = 16711847 ##ff00a7
#Borramos la imagen por defecto de la portada. No he sido capaz de sustituirla
$Selection.Document.Shapes.Item('Imagen 1').Delete()
#Creamos el nuevo Canva para recoger el logo y colocarla en el mismo lugar. Hay que configurar el tamaño
$null = $Selection.Document.Shapes.AddCanvas(1, 1, 200, 107.5)
$null = $Selection.Document.Shapes.Item('Lienzo 1').CanvasItems.AddPicture("C:\DataCrazyWorld\Logos DataCrazyWorld\Elementos\Logos\Color_Small.png", $false, $True, $null, $null, 200, 107.5)#439.2, 295.55
$Selection.Document.Shapes.Item('Lienzo 1').Left =-999996
$Selection.Document.Shapes.Item('Lienzo 1').Top = -999995
$Selection.Document.Shapes.Item('Lienzo 1').Height = 107.5
$Selection.Document.Shapes.Item('Lienzo 1').Width = 200
$Selection.Document.Shapes.Item('Lienzo 1').Title = "Logo"
$Selection.Document.Shapes.Item('Lienzo 1').AlternativeText = "Imagen del logo"
$Selection.Document.Shapes.Item('Lienzo 1').RelativeHorizontalPosition = 1
$Selection.Document.Shapes.Item('Lienzo 1').RelativeVerticalPosition = 1
$Selection.Document.Shapes.Item('Lienzo 1').CanvasItems.PictureFormat
#Reemplazamos la etiqueta [Año]
$año = Get-Date -Format "yyyy"
$Selection.Document.Shapes.Item("Grupo 78").GroupItems[3].TextFrame.TextRange.Text= $año #Año
#Reemplazamos la etiqueta [Fecha]
$fecha = Get-Date -Format "dd/MM/yyyy"
$Texto = $Selection.Document.Shapes.Item("Grupo 78").GroupItems[4].TextFrame.TextRange.Text
$Selection.Document.Shapes.Item("Grupo 78").GroupItems[4].TextFrame.TextRange.Text = $Texto.Replace("[Fecha]",$fecha)
#########################Fin portada "Movimiento"
Tras la portada, viene el índice, así que se puede crear una tabla de contenidos.
#Metemos un salto de página para incluir la tabla de contenidos
$Selection = $MSWord.Selection
$Selection.InsertBreak([Microsoft.Office.Interop.Word.WdBreakType]::wdSectionBreakNextPage)
$Selection = $MSWord.Selection
$range = $Selection.Range
$toc = $mydoc.TablesOfContents.Add($range)
$Selection.TypeParagraph()
#Metemos un salto de página para empezar a documentar
$Selection.InsertBreak([Microsoft.Office.Interop.Word.WdBreakType]::wdSectionBreakNextPage)
Y a partir de aquí ya es crear el contenido. Se pueden usar títulos, listas, tablas… Aquí tenéis algunos ejemplos
#Creamos array de stilos para las cabeceras. Esto es opcional... me sirve para acortar luego los comandos
$styles = @(
[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading1
,[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading2
,[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading3
,[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading4
,[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading5
,[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading6
,[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading7
,[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading8
,[Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleHeading9
)
#Configuramos la apariencia del documento a partir de aquí
$Section = $mydoc.Sections.Item(1)
$Header = $Section.Headers.Item(1)
$Footer = $Section.Footers.Item(1)
$Footer.PageNumbers.Add()
#Creamos una referencia al documento actual, para añadirle el texto
$myText = $MSWord.Selection
#Ponemos el Titulo1
$myText.Style = $styles[0] #Titulo 1
$myText.TypeText("Ejemplo de documento generado por PowerShell")
$myText.TypeParagraph()
#Seguimos rellenando con texto normal
$myText.TypeText("Rellenas el contenido que quieras")
$myText.TypeParagraph()
#Ponemos el Titulo2
$myText.Style = $styles[1] #Titulo 2
$myText.TypeText("Ejemplo título 2")
$myText.TypeParagraph()
#Hacemos una lista
$myText.Style = [Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStyleListBullet
$myText.Font.Bold = 1
$myText.TypeText('Tit. Lista: ')
$myText.TypeParagraph()
$myText.Font.Bold = 0
$myText.Style = [Microsoft.Office.Interop.Word.WdBuiltinStyle]::wdStylePlainText
$myText.TypeText('Detalle lista')
$myText.TypeParagraph()
#Dejamos libre una línea
$myText.TypeParagraph()
#Creamos una tabla
$Range = @($myText.Paragraphs)[-1].Range
$Table = $myText.Tables.add(
$myText.Range #$Range
,2 #Rows
,3 #Columns
,[Microsoft.Office.Interop.Word.WdDefaultTableBehavior]::wdWord9TableBehavior
,[Microsoft.Office.Interop.Word.WdAutoFitBehavior]::wdAutoFitContent
)
## Cabecera de la Tabla
$Table.cell(1,1).range.Bold=1
$Table.cell(1,1).range.text = "Columna 1"
$Table.cell(1,2).range.Bold=1
$Table.cell(1,2).range.text = "Columna 2"
$Table.cell(1,3).range.Bold=1
$Table.cell(1,3).range.text = "Columna 3"
#rellenamos la celda con la descripción de la columna cogida de BBDD
$Table.cell(2,1).range.Bold = 0
$Table.cell(2,1).range.text = 'Cont. Col1'
$Table.cell(2,2).range.Bold = 0
$Table.cell(2,2).range.text = 'Cont. Col2'
$Table.cell(2,3).range.Bold = 0
$Table.cell(2,3).range.text = 'Cont. Col3'
#Para continuar escribiendo fuera de la tabla y dejar una linea
$myText.Start= $mydoc.Content.End
$myText.TypeParagraph()
Una vez terminado de introducir el contenido, hay que pedir que se actualice la tabla de contenidos.
#Actualizamos el índice
$toc.Update()
Y por último, hay que salvar el documento, cerrar y limpiar todo.
#Salvamos el documento Word
$saveFormat = [Microsoft.Office.Interop.Word.WdSaveFormat]::wdFormatDocumentDefault
$mydoc.SaveAs([ref][system.object]$docfile, [ref]$saveFormat)
$mydoc.Close()
$MSWord.Quit()
# Limpiar el objeto Com
$null = [System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$MSWord)
Remove-Variable MSWord
Dejo aquí ,en el GitHub, toda esta recopilación de comandos de PowerShell para crear documentos Word.
Ahora te invito a imaginar todas las aplicaciones que puede tener. Ya puse un ejemplo, pero en los próximos posts, pondré muchos más… como ya dije, iban a ser unos cuantos post relativos a la documentación . Y a ti ¿qué se te ocurre? ¡Te leo!
Bibliografía
- Creating a Table of Contents in Word Using PowerShell
- Read & Write MS Office custom properties with PowerShell
- How to change custom properties for many Word documents
- https://www.erickscottjohnson.com/blog–examples/how-to-add-a-cover-page-to-word-with-powershell#comments
- Automate Microsoft Word – PowerShell – SS64.com
- https://www.powershellgallery.com/packages/WordDoc/1.2.0/Content/WordDoc.psm1
- https://github.com/zloeber/Powershell/blob/master/Supplemental/WordFunctions.ps1
- Edit a Word template with variables using Powershell?
- DocumentProperty Interface (Microsoft.Office.Core)
- Shape object (Word)
- https://github.com/ascott18/PowershellGallery/blob/master/Functions/WordDocument.ps1
- Shape.TextFrame property (Word)
Excelente post, como siempre, Cris.
Gracias por tu apoyo Ana!!