{"id":49833,"date":"2010-05-13T00:01:00","date_gmt":"2010-05-13T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2010\/05\/13\/hey-scripting-guy-how-can-i-customize-microsoft-powerpoint-presentations\/"},"modified":"2010-05-13T00:01:00","modified_gmt":"2010-05-13T00:01:00","slug":"hey-scripting-guy-how-can-i-customize-microsoft-powerpoint-presentations","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-customize-microsoft-powerpoint-presentations\/","title":{"rendered":"Hey, Scripting Guy! How Can I Customize Microsoft PowerPoint Presentations?"},"content":{"rendered":"<p><a class=\"addthis_button\" href=\"http:\/\/www.addthis.com\/bookmark.php?v=250&amp;pub=scriptingguys\"><img decoding=\"async\" alt=\"Bookmark and Share\" src=\"http:\/\/s7.addthis.com\/static\/btn\/v2\/lg-share-en.gif\" width=\"125\" height=\"16\"><\/a><\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"><\/p>\n<p class=\"MsoNormal\">&nbsp;Hey, Scripting Guy! I am a sales person, and therefore not a professional IT person. I live and die on my ability to use Microsoft PowerPoint. I therefore stumbled across your Web site while searching for solutions to a problem I have. Let me briefly explain the situation. I learned a long time ago that customers love it when I personalize my slide deck for them. It shows that I care, and in addition, they perceive the presentation as tailored to their needs. The problem is that I may visit as many as 20 different customers a week, and therefore that requires a lot of time spent adding slides, saving the presentation with new names, and trying to remember to change the name of the last customer before my next presentation. As you can see, it is quite a dilemma. I was therefore intrigued when I ran across your site, so I am wondering if you could see your way clear to assist me. You would be helping the global economy to grow by increasing my productivity. What do you say, pal? If you will not help me, would you be willing to help the world?<\/p>\n<p class=\"MsoNormal\">&#8212; AN<\/p>\n<p class=\"MsoNormal\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\"><img decoding=\"async\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\">Hello AN, <\/p>\n<p class=\"MsoNormal\">Microsoft Scripting Guy Ed Wilson here. I am glad you decided to be brief &ndash; I would have hated to sit through your long version. Anyway, I completely understand your situation. Back when I was a Microsoft Technical Account Manager (TAM), I used to personalize the presentations for my customers. However, I only had a few customers, so it made it really easy. Windows PowerShell was not invented back then either. Your suggestion was pretty cool and I decided to write the ReadCSVandAddPowerPointSlide.ps1 script for you. The complete ReadCSVandAddPowerPointSlide.ps1 script is seen here.<\/p>\n<p class=\"CodeBlockScreenedHead\"><strong>ReadCSVandAddPowerPointSlide.ps1<\/p>\n<p><\/strong><\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">Add-type -AssemblyName office<br \/>$Application = New-Object -ComObject powerpoint.application<br \/>$application.visible = [Microsoft.Office.Core.MsoTriState]::msoTrue<br \/>$slideType = &#8220;microsoft.office.interop.powerpoint.ppSlideLayout&#8221; -as [type]<br \/>$templatePresentation = &#8220;C:fsoTemplatePresentation.pptx&#8221;<br \/>Import-Csv -Path C:fsopptTemplateNames.csv | ForEach-Object { `<br \/><span>&nbsp;<\/span>$presentation = $application.Presentations.open($templatePresentation)<br \/><span>&nbsp;<\/span>$customLayout = $presentation.Slides.item(2).customLayout<br \/><span>&nbsp;<\/span>$slide = $presentation.slides.addSlide(1,$customLayout)<br \/><span>&nbsp;<\/span>$slide.layout = $slideType::ppLayoutTitle<br \/><span>&nbsp;<\/span>$slide.Shapes.title.TextFrame.TextRange.Text = $_.group<br \/><span>&nbsp;<\/span>$slide.shapes.item(2).TextFrame.TextRange.Text = $_.date<\/p>\n<p><span>&nbsp;<\/span>$presentation.SavecopyAs(&#8220;C:fso$($_.group)&#8221;)<br \/><span>&nbsp;<\/span>$presentation.Close()<br \/><span>&nbsp;<\/span>&#8220;Created $($_.group)&#8221;<br \/>}<\/p>\n<p>$application.quit()<br \/>$application = $null<br \/>[gc]::collect()<br \/>[gc]::WaitForPendingFinalizers()<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The first thing that must be done is to add the <b>office<\/b> assembly to the current Windows PowerShell session, create the <b>PowerPoint<\/b> application object, set it visible, and create the b type. This was discussed in <a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2010\/05\/10\/hey-scripting-guy-may-10-2010.aspx\"><span>Monday&rsquo;s Hey, Scripting Guy! post<\/span><\/a>. <\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">Add-type -AssemblyName office<br \/>$Application = New-Object -ComObject powerpoint.application<br \/>$application.visible = [Microsoft.Office.Core.MsoTriState]::msoTrue<br \/>$slideType = &#8220;microsoft.office.interop.powerpoint.ppSlideLayout&#8221; -as [type]<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">After that has been accomplished, the path to the template presentation is assigned to the <b>$templatePresentation<\/b> variable. The template presentation will form the basis for the new Microsoft presentations that will be created. As seen in the following image, the presentation contains several slides and has a specific theme applied to it. <\/p>\n<p class=\"Fig-Graphic\"><span><img decoding=\"async\" title=\"Image of presentation template\" alt=\"Image of presentation template\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2010\/may\/hey0513\/hsg-05-13-10-01.jpg\" width=\"600\" height=\"420\"><a href=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2010\/may\/hey0513\/hsg-05-13-10-01.jpg\"><font face=\"Segoe\"><\/font><\/a><\/span><\/p>\n<p class=\"Fig-Graphic\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\">The code that assigns the path to the template presentation is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">$templatePresentation = &#8220;C:fsoTemplatePresentation.pptx&#8221;<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The new slide that will be inserted into each new presentation will be customized with the date of the presentation and the name of the specific group that will receive the presentation. Rather than using a plain text file to hold this information, a comma-separated value (CSV) file is used. As seen in the following image, CSV files can be created, displayed, and edited in Microsoft Excel. <\/p>\n<p class=\"Fig-Graphic\"><span><img decoding=\"async\" title=\"Image of CSV file being viewed in Microsoft Excel\" alt=\"Image of CSV file being viewed in Microsoft Excel\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\n\/hsg\/2010\/may\/hey0513\/hsg-05-13-10-02.jpg\" width=\"600\" height=\"400\"><a href=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2010\/may\/hey0513\/hsg-05-13-10-02.jpg\"><font face=\"Segoe\"><\/font><\/a><\/span><\/p>\n<p class=\"Fig-Graphic\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\">The good thing about a CSV file, however, is it is easily consumed in Windows PowerShell by using the <b>Import-CSV<\/b> cmdlet. The first line of the CSV file contains the field names. These names are used to refer to the data that is stored in each column of the CSV file. The results of importing the CSV are piped to the <b>ForEach-Object<\/b> cmdlet that allows us to work on each line as it comes across the pipeline. This section of the script is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">Import-Csv -Path C:fsopptTemplateNames.csv | ForEach-Object { `<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The template presentation is opened by using the <b>Open<\/b> method from the <b>Presentation<\/b> object. The returned <b>Presentation<\/b> object is stored in the <b>$presentation<\/b> variable. Next a <b>CustomLayout<\/b> object is retrieved from the second slide in the template presentation, and the object is stored in the <b>$customLayout<\/b> variable. The <b>AddSlide<\/b> method from the <b>Slides<\/b> collection object is used to add a slide with the layout stored in the <b>$customLayout<\/b> variable in the first position. These lines of code were all discussed in <a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2010\/05\/12\/hey-scripting-guy-may-12-2010.aspx\"><span>yesterday&rsquo;s Hey, Scripting Guy! post<\/span><\/a>. This section of the script is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">$presentation = $application.Presentations.open($templatePresentation)<br \/><span>&nbsp;<\/span>$customLayout = $presentation.Slides.item(2).customLayout<br \/><span>&nbsp;<\/span>$slide = $presentation.slides.addSlide(1,$customLayout)<br \/><span>&nbsp;<\/span>$slide.layout = $slideType::ppLayoutTitle<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The <b>group<\/b> property from the CSV file is used to assign the text to the title shape on the slide. The <b>$_<\/b> automatic variable is used to refer to the current item on the pipeline. This is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>$slide.Shapes.title.TextFrame.TextRange.Text = $_.group<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The title shape object is the first item in the <b>Shapes<\/b> collection of the new slide. The second item is the <b>TextFrame<\/b> under the title. The <b>text<\/b> property of the <b>TextRange<\/b> object is used to add the date to the slide. The date is stored in the date property from the CSV file. This section of the script is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>$slide.shapes.item(2).TextFrame.TextRange.Text = $_.date<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The <a href=\"http:\/\/bit.ly\/a7hUuP\"><font face=\"Segoe\">SaveCopyAs method<\/font><\/a> from the <b>presentation<\/b> object is used to save the newly created Microsoft PowerPoint presentation. The <b>SaveCopyAs<\/b> method is overloaded and has several optional parameters. Luckily, the first parameter is used to save the file with a new name, and to not make any changes to the current template presentation. The other options are discussed on MSDN. <\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>$presentation.SavecopyAs(&#8220;C:fso$($_.group)&#8221;)<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">One of the newly created Microsoft PowerPoint presentations is shown in the following image.<\/p>\n<p class=\"Fig-Graphic\"><span><img decoding=\"async\" title=\"Image of newly created Microsoft PowerPoint presentation\" alt=\"Image of newly created Microsoft PowerPoint presentation\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2010\/may\/hey0513\/hsg-05-13-10-03.jpg\" width=\"600\" height=\"420\"><a href=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2010\/may\/hey0513\/hsg-05-13-10-03.jpg\"><font face=\"Segoe\"><\/font><\/a><\/span><\/p>\n<p class=\"Fig-Graphic\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\">The template presentation is closed after the changes were saved to a new file. In the next loop, the template presentation will be opened and the new slide created for the next group and date on the list. After the presentation has been closed, a message is displayed that states the name of the group that was created. A subexpression is used to prevent unraveling of the <b>group<\/b> property from the object:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>$presentation.Close()<br \/><span>&nbsp;<\/span>&#8220;Created $($_.group)&#8221;<br \/>}<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">After all of the new presentations have been created, it is time for cleanup. The <b>quit<\/b> method of the <b>application<\/b> object is called, the <b>$application<\/b> variable nulled out, and garbage collection is called. This is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">$application.quit()<br \/>$application = $null<br \/>[gc]::collect()<br \/>[gc]::WaitForPendingFinalizers()<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\">AN, that is all there is to using Windows PowerShell to create new Microsoft PowerPoint presentations. This brings Microsoft PowerPoint Week to a close. Join us tomorrow for Quick-Hits Friday. <\/p>\n<p class=\"MsoNormal\">If you want to know exactly what we will be looking at tomorrow, follow us on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> or <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\">Facebook<\/a>. If you have any questions, send e-mail to us at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\" target=\"_blank\"><font face=\"Segoe\">scripter@microsoft.com<\/font><\/a> or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\"><font face=\"Segoe\">Official Scripting Guys Forum<\/font><\/a>. See you tomorrow. Until then, peace.<\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p><b><span>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/p>\n<p><\/span><\/b><\/p>\n<p><span><\/span>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; &nbsp;Hey, Scripting Guy! I am a sales person, and therefore not a professional IT person. I live and die on my ability to use Microsoft PowerPoint. I therefore stumbled across your Web site while searching for solutions to a problem I have. Let me briefly explain the situation. I learned a long time ago [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[129,49,3,45],"class_list":["post-49833","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-microsoft-powerpoint","tag-office","tag-scripting-guy","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; &nbsp;Hey, Scripting Guy! I am a sales person, and therefore not a professional IT person. I live and die on my ability to use Microsoft PowerPoint. I therefore stumbled across your Web site while searching for solutions to a problem I have. Let me briefly explain the situation. I learned a long time ago [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/49833","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\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=49833"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/49833\/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=49833"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=49833"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=49833"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}