{"id":7731,"date":"2015-02-20T00:01:00","date_gmt":"2015-02-20T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2015\/02\/20\/use-powershell-to-add-table-to-word-doc-and-email-as-attachment\/"},"modified":"2019-02-18T10:30:33","modified_gmt":"2019-02-18T17:30:33","slug":"use-powershell-to-add-table-to-word-doc-and-email-as-attachment","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-add-table-to-word-doc-and-email-as-attachment\/","title":{"rendered":"Use PowerShell to Add Table to Word Doc and Email as Attachment"},"content":{"rendered":"<p align=\"left\"><b>Summary<\/b>: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to create a document in Microsoft Word, add a table, and email the document as an attachment.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. One of the cool things I like to do with Windows PowerShell is to combine multiple tasks so that it makes life easier for me. I use what I call the &ldquo;annoyance meter&rdquo; quite often to determine whether to write a script or not. Today&rsquo;s script is one of those things that rates pretty high on my annoyance meter.<\/p>\n<p>Here is the scenario: I need to supply my professor in my Shakespeare class with a list of proposed topics and my critical approach to them. So what is the big deal? I would have to create a table, type out each of the plays, add my topics, and add my critical approach to each topic. I then have to save the file, open email, find the file, and send the email. That is like, I don&rsquo;t know, maybe a dozen steps.<\/p>\n<h2>Getting started<\/h2>\n<p>But what do I have? I already have a text file with my plays, and I already came up with a listing of topic ideas for each of the plays. I did that yesterday&nbsp;in <a title=\"Add Custom Headers to Folder Full of Word Documents\" href=\"https:\/\/devblogs.microsoft.com\/scripting\/add-custom-headers-to-folder-full-of-word-documents\/\" target=\"_blank\">Add Custom Headers to Folder Full of Word Documents<\/a>.<\/p>\n<p>So all I need to do is to add the literary approach as a third column to the CSV file. Here is my modification:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-20-15-01.png\"><img decoding=\"async\" title=\"Image of play, topic, and approach list\" alt=\"Image of play, topic, and approach list\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-20-15-01.png\" \/><\/a>&nbsp;<\/p>\n<p>Now I open the Windows PowerShell ISE, start a new script, and set my initial variables. Because I am going to use the&nbsp;<b>SaveAs<\/b>&nbsp;method from the <strong>Document<\/strong> object, I know that I will need to pass the format by reference. I include this [ref] when I create the&nbsp;<b>WdSaveFormat<\/b>&nbsp;type. I want to know how many columns I have in my CSV file. Each column will be added as a&nbsp;<b>NoteProperty<\/b>, so I use the&nbsp;<b>Get-Member<\/b>&nbsp;cmdlet to find the&nbsp;<b>NoteProperty<\/b>&nbsp;members, and I count them. I find the number of rows that I will need by counting the number of rows in my CSV file. The code is shown here:<\/p>\n<p style=\"margin-left:30px\">[ref]$SaveFormat = &quot;microsoft.office.interop.word.WdSaveFormat&quot; -as [type]<\/p>\n<p style=\"margin-left:30px\">$topics = Import-Csv C:\\Lit\\Shakespeare.txt<\/p>\n<p style=\"margin-left:30px\">$path = &quot;C:\\lit\\ResearchTopics.docx&quot;<\/p>\n<p style=\"margin-left:30px\">$Number_Of_Rows = ($topics.Count +1)<\/p>\n<p style=\"margin-left:30px\">$Number_Of_Columns = ($topics | gm -MemberType NoteProperty).count<\/p>\n<p style=\"margin-left:30px\">$x = 2<\/p>\n<h2>Create the Word document&nbsp;<\/h2>\n<p><span style=\"font-size:12px\">I create the&nbsp;<\/span><b style=\"font-size:12px\">Word.Application<\/b><span style=\"font-size:12px\">&nbsp;object, set it to not be visible, and add a document to the&nbsp;<\/span><b style=\"font-size:12px\">Documents<\/b><span style=\"font-size:12px\">&nbsp;collection object. I then obtain a range object from the document and store the returned objects in the appropriate objects. This is shown here:<\/span><\/p>\n<p style=\"margin-left:30px\">$Word = New-Object -comobject word.application<\/p>\n<p style=\"margin-left:30px\">$Word.Visible = $false<\/p>\n<p style=\"margin-left:30px\">$Doc = $Word.Documents.Add()<\/p>\n<p style=\"margin-left:30px\">$Range = $Doc.Range()<\/p>\n<p>Now that I have a&nbsp;<b>Range<\/b>&nbsp;object, I can add a table to the&nbsp;<b>Tables<\/b>&nbsp;collection. When I do this, I use the&nbsp;<b>Add<\/b>&nbsp;method and I specify the&nbsp;<b>Range<\/b>&nbsp;that will host the table (the range I have stored in the&nbsp;<b>$Range<\/b>&nbsp;variable), the number of rows, and the number of columns that the table will contain. I pipe the results to the&nbsp;<b>Out-Null<\/b>&nbsp;cmdlet to avoid cluttering up my output pane. Here is the code:<\/p>\n<p style=\"margin-left:30px\">$Doc.Tables.Add($Range,$Number_Of_Rows,$Number_Of_Columns) | Out-Null<\/p>\n<p>Now I get the table and add my column headings. I have only added a single table to the&nbsp;<b>Tables<\/b>&nbsp;collection, so I can simply use&nbsp;<b>Item(1)<\/b>&nbsp;to obtain the table object that represents my new table. I now use the&nbsp;<b>Cell<\/b>&nbsp;property to add my column headings. I want the columns to begin with the first row and first column. Then I specify a text property for the range associated with each cell. This code is shown here:<\/p>\n<p style=\"margin-left:30px\">$Table = $Doc.Tables.item(1)<\/p>\n<p style=\"margin-left:30px\">$Table.Cell(1,1).Range.Text = &quot;Play&quot;<\/p>\n<p style=\"margin-left:30px\">$Table.Cell(1,2).Range.Text = &quot;Topic&quot;<\/p>\n<p style=\"margin-left:30px\">$Table.Cell(1,3).Range.Text = &quot;Approach&quot;<\/p>\n<p>Now I want to add the information to my table. I walk through the information I obtained from my CSV file, and add each appropriate value. Because I want to ensure that play titles appear under the Play column heading, I have specified each property rather than simply walking through the collection of items. This code is shown here:<\/p>\n<p style=\"margin-left:30px\">Foreach($t in $topics)<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;$Table.Cell($x,1).Range.Text = $t.Play<\/p>\n<p style=\"margin-left:30px\">&nbsp;$Table.Cell($x,2).Range.Text= $t.Topic<\/p>\n<p style=\"margin-left:30px\">&nbsp;$Table.Cell($x,3).Range.Text=$t.Approach<\/p>\n<p style=\"margin-left:30px\">&nbsp;$x++<\/p>\n<p style=\"margin-left:30px\">}&nbsp;<\/p>\n<p>I just want a nice looking table, but I do not want to fool with a lot of manual formatting. Luckily, Microsoft Word has an automatic format method associated with the&nbsp;<b>Table<\/b>&nbsp;object. I use a hard-coded number to choose which style I want to use. This is shown here:<\/p>\n<p style=\"margin-left:30px\">$Table.AutoFormat(9)<\/p>\n<p>Now I save my document by using the&nbsp;<b>SaveAs<\/b>&nbsp;method. I need to specify the path and the format when I call this method. I then close the document and exit the application. Here is the code:<\/p>\n<p style=\"margin-left:30px\">$doc.saveas([ref] $path, [ref]$SaveFormat::wdFormatDocumentDefault)<\/p>\n<p style=\"margin-left:30px\">$doc.close()<\/p>\n<p style=\"margin-left:30px\">$word.quit()<\/p>\n<p>I want to release all of these objects, so I call the&nbsp;<b>ReleaseComObject<\/b>&nbsp;method. I do this for each of objects I created. I then call garbage collection to scavenge memory, and I remove the variables. This is shown here:<\/p>\n<p style=\"margin-left:30px\">[System.Runtime.Interopservices.Marshal]::ReleaseComObject($doc) | Out-Null<\/p>\n<p style=\"margin-left:30px\">[System.Runtime.Interopservices.Marshal]::ReleaseComObject($word) | Out-Null<\/p>\n<p style=\"margin-left:30px\">[System.Runtime.Interopservices.Marshal]::ReleaseComObject($range) | Out-Null<\/p>\n<p style=\"margin-left:30px\">[System.Runtime.Interopservices.Marshal]::ReleaseComObject($table) | Out-Null<\/p>\n<p style=\"margin-left:30px\">Remove-Variable Doc,Word, range, table<\/p>\n<p style=\"margin-left:30px\">[gc]::collect()<\/p>\n<p style=\"margin-left:30px\">[gc]::WaitForPendingFinalizers()<\/p>\n<p>The document is shown here:<\/p>\n<p>&nbsp;<a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-20-15-02.png\"><img decoding=\"async\" title=\"Image of table listing plays, topics, and approaches\" alt=\"Image of table listing plays, topics, and approaches\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-2-20-15-02.png\" \/><\/a><\/p>\n<p>To email the document to my professor, I use the&nbsp;<b>Send-MailMessage<\/b>&nbsp;cmdlet. All I need to do is ensure that I am using the right SMTP email server, and that I specify my credentials if required. Here is the code I use:<\/p>\n<p style=\"margin-left:30px\">Send-MailMessage -From &quot;ScriptingGuys@Outlook.com&quot; -To &quot;DrHasenpfeffer@State.Edu&quot; `<\/p>\n<p style=\"margin-left:30px\">&nbsp;-Attachments C:\\Lit\\ResearchTopics.docx -Subject &quot;research topics&quot; -Body &quot;attached&quot; `<\/p>\n<p style=\"margin-left:30px\">&nbsp;-SmtpServer &quot;smtp-mail.outlook.com&quot; -UseSsl -Credential &quot;ScriptingGuys@Outlook.com&quot;<\/p>\n<p>That is all there is to using Windows PowerShell to create a Word document, add a table, and email the document as an attachment. Join me tomorrow when I will talk about more cool stuff.<\/p>\n<p>I invite you to follow me on&nbsp;<a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a>&nbsp;and&nbsp;<a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at&nbsp;<a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the&nbsp;<a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to create a document in Microsoft Word, add a table, and email the document as an attachment. Microsoft Scripting Guy, Ed Wilson, is here. One of the cool things I like to do with Windows PowerShell is to combine multiple tasks so that it [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[49,3,45,360],"class_list":["post-7731","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-office","tag-scripting-guy","tag-windows-powershell","tag-word"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to create a document in Microsoft Word, add a table, and email the document as an attachment. Microsoft Scripting Guy, Ed Wilson, is here. One of the cool things I like to do with Windows PowerShell is to combine multiple tasks so that it [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/7731","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=7731"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/7731\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=7731"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=7731"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=7731"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}