Garacesh Posted June 3, 2014 Posted June 3, 2014 (edited) Huzzah! It's time for my monthly "Stuff don't work like it should do" coding thread! [color="#800080"]$MSword[/color] [color="#FF0000"]=[/color] [color="#008080"]New-Object [i]-ComObject[/i][/color] [color="#800000"]word.application[/color] [color="#800080"]$MSword[/color].Visible [color="#FF0000"]=[/color] [color="#800080"]$False[/color] [color="#800080"]$wdTypes[/color] [color="#FF0000"]=[/color] [color="#008080"]Add-Type [i]-AssemblyName[/i][/color][color="#800000"] 'Microsoft.Office.Interop.Word'[/color][color="#008080"][i] -Passthru[/i][/color] [color="#800080"]$wdSaveFormat[/color] [color="#FF0000"]=[/color] [color="#800080"]$wdTypes[/color] | [color="#008080"]Where[/color] {[color="#800080"]$_[/color].Name [color="#FF0000"]-eq[/color] [color="#800000"]"wdSaveFormat"[/color]} [color="#800080"]$MSword[/color].documents.open([color="#800000"]".DOC FILE"[/color]) [color="#800080"]$MSWord[/color].ActiveDocument.saveas([[color="#008080"]ref[/color]][color="#800000"]".HTM FILE"[/color], [[color="#008080"]ref[/color]][color="#800080"]$wdSaveFormat[/color]::wdFormatHTML); [color="#800080"]$MSWord[/color].ActiveDocument.Close([[color="#008080"]ref[/color]]0); [color="#800080"]$MSWord[/color].Quit([[color="#008080"]ref[/color]]0); This works fine. It silently opens up a document in Word, saves it as a HTM file (We use it for digital signage), closes the file, doesn't save changes, and quits word. Huzzah. Now I want to do something similar in PowerPoint. Open up the file, save as JPG, quit. So I start to re-work my code. According to the internets, powerpoint.application ought to work. Good. Let's fiddle around some more. [color="#800080"]$MSPPT[/color] [color="#FF0000"]=[/color] [color="#008080"]New-Object [i]-ComObject[/i][/color] [color="#800000"]powerpoint.application[/color] [color="#800080"]$MSPPT[/color].visible [color="#FF0000"]=[/color] [color="#800080"]$True[/color] [color="#800080"]$MSPPT[/color].presentations.open([color="#800000"]".PPT FILE"[/color]) Plan was to keep visible as TRUE until it works, then change to FALSE. Standard debugging. However, "Stuff don't work like it should do", you see. [ATTACH=CONFIG]24838[/ATTACH] However, crawling around the dregs on the internets I find that [color="#800080"]$MSPPT[/color].visible [color="#FF0000"]=[/color] [Microsoft.Office.Core.MsoTriState]::msoTrue works file, and running that opens up PowerPoint, void of any presentation, as it should. However, opening a presentation still fails and I'm stuck finding information on this error code because it appears to apply to a lot of different programs. Why does it 'just work' for Word but not for Powerpoint? Edited June 3, 2014 by Garacesh
LosOjos Posted June 3, 2014 Posted June 3, 2014 (edited) OK, I'll start by saying I know almost nothing about Powershell, however I do have some experience with Office scripting. I believe the problem you're having is that Powerpoint won't allow you to open a presentation while it's hidden. However, there's a workaround: you can open the presentation hidden with an overloaded Open() method, like so: $MSPPT = New-Object -ComObject powerpoint.application $MSPPT.presentations.open("C:\test.pptx",[Microsoft.Office.Core.MsoTriState]::msoFalse,[Microsoft.Office.Core.MsoTriState]::msoFalse,[Microsoft.Office.Core.MsoTriState]::msoFalse) All very backwards but that works (for me at least) and you'd never know Powerpoint was open. More info on that overloaded Open method: PPT97: How to Use the Presentations.Open Method EDIT: how do you do syntax highlighting on here BTW? Tried quoting your post to see it but it just had a load of 'color' tags - you didn't do it manually, did you?! Edited June 3, 2014 by LosOjos
Garacesh Posted June 3, 2014 Author Posted June 3, 2014 Yes, I did it manually. Syntax highlighting makes it a lot easier for me to read my own code. There's only 4 colours, it's not really difficult to do. Only took ≈60 seconds. That didn't work either.. Same error, but Exception calling "Open" with "4" argument(s) this time, instead of just "1" argument(s) Also, currently PowerPoint isn't hidden, Visible is True and it does actually open PowerPoint when I use the (...)::msoTrue line.
LosOjos Posted June 3, 2014 Posted June 3, 2014 Bit of a long shot but have you tried it exactly as I posted it i.e. without the 'visible' line? Also, have you tried opening the file manually to check it's not corrupt?
Garacesh Posted June 3, 2014 Author Posted June 3, 2014 (edited) Yep, didn't work. BUT I have made progress. Faffing around with it (testing different paths, etc), I've discovered that the error is caused by the file currently being in use by another user (Which is actually extremely common, but doesn't actually matter because I just want to SAVE AS), so now I need to figure out how to make it open as Read Only (or, if prompted, reply with "Yes, open as Read-Only, similar to how my Word script automatically decides "No, don't save changes" when you exit). Edit: [color="#800080"]$MSPPT[/color].presentations.open([color="#800000"]".PPT FILE"[/color], 2, [color="#800080"]$True[/color])[/Code] Edited June 3, 2014 by Garacesh
LosOjos Posted June 3, 2014 Posted June 3, 2014 Yep, didn't work. BUT I have made progress. Faffing around with it (testing different paths, etc), I've discovered that the error is caused by the file currently being in use by another user (Which is actually extremely common, but doesn't actually matter because I just want to SAVE AS), so now I need to figure out how to make it open as Read Only (or, if prompted, reply with "Yes, open as Read-Only, similar to how my Word script automatically decides "No, don't save changes" when you exit). OK great, narrowing it down! If you change the second argument in the overloaded Open method I posted earlier to 'msoTrue', it'll open read-only - perhaps that'll be enough to overcome the problem?
Garacesh Posted June 3, 2014 Author Posted June 3, 2014 (edited) Using [color="#800080"]$MSPPT[/color].presentations.open([color="#800000"]".PPT FILE"[/color], 2, [color="#800080"]$True[/color])[/Code] worked! (yay internet), though I suspect your lines may be doing the same thing, just the 'longhand' way? So, we've got the document open. Now to figure out how to save each slide as a JPG. Onwards and upwards! Edit: Getting a lot of "[color=#FF0000]You cannot call a method on a null-valued expression.[/color]".. It still doesn't want to admit that [color=#800080]$MSPPT[/color] is a real thing.. Also [color=#800080]$MSPPT[/color].Quit([[color=#008080]ref[/color]]0) doesn't work. "[color=#FF0000]Cannot find an overload for "Quit" and the argument count: "1".[/color]" Edited June 3, 2014 by Garacesh
LosOjos Posted June 3, 2014 Posted June 3, 2014 Slides have an Export method which is simply Slide.Export(string filename, string filetype) E.G. Slide.Export("C:\slide.jpg", "JPG") You can get a collection fo slides from ActivePresentation.Slides or pick an individual one by specifying it's index (starting from 1) e.g. ActivePresentation.Slides(1) Just brain dumping - hope it helps!
LosOjos Posted June 3, 2014 Posted June 3, 2014 (edited) You may have already cracked it, but just in case, this does it: $MSPPT = New-Object -ComObject powerpoint.application $PRES = $MSPPT.presentations.open("C:\test.pptx", 2, $True, $False) foreach($Slide in $PRES.slides) { $Slide.Export("C:\" + $Slide.Name + ".jpg", "JPG") } $MSPPT.Quit() You were right RE the Open method being the same as I was using, didn't realise it'd accept bools (assumed it wouldn't because of earlier error!). The last argument is the one that sets whether it's shownor not, so change that to $True (or omit it entirely) if you want to see the presentation open Problem I'm having is that PowerPoint won't quit - according to the documentation, you don't/can't set an exit code, which would make your "no overload" error ring true, however if I check taskman PowerPoint continues running... Edited June 3, 2014 by LosOjos
LosOjos Posted June 3, 2014 Posted June 3, 2014 Supposedly you're supposed to use ReleaseComObject to properly terminate some Office applications after calling Quit, but that doesn't seem to work for me either: [system.Runtime.InteropServices.Marshal]::ReleaseComObject($MSPPT) Source: Windows PowerShell Tip: Getting Rid of a COM Object (Once and For All)
Garacesh Posted June 3, 2014 Author Posted June 3, 2014 (edited) Aha! [color="#800080"]$MSPPT[/color].ActivePresentation.SaveAs([color="#800000"]"LOCATION"[/color], [Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType]::ppSaveAsJPG); Saves each slide to the location as Slide1, Slide2, Slide3 etc. So that's the next step completed! (I did originally try saving just as a JPG, but that saved the entire file as one JPG file.. Not quite what I was after lol) Now to get it to close.. [color="#800080"]$MSPPT[/color].ActivePresentation.Close [color="#800080"]$MSPPT[/color].Quit doesn't seem to be working. The PowerPoint stays open (Both program and presentation) and the command line just prints out this: [ATTACH=CONFIG]24848[/ATTACH] Edit: I could force it to terminate with Stop-Process, I guess. Kludgy. Edited June 3, 2014 by Garacesh
LosOjos Posted June 3, 2014 Posted June 3, 2014 Have you tried with the ReleaseComObject method I posted/linked to above? Could be that I'm using an old version of PowerShell (I think) that it won't work for me
Garacesh Posted June 3, 2014 Author Posted June 3, 2014 Yeah I tried that. Bizarrely, it prints "1" in the command line and does nothing else. Looks like I'm going to have to settle for: [color="#800080"]$MSPPT[/color] [color="#FF0000"]=[/color] [color="#008080"]New-Object [i]-ComObject[/i][/color] [color="#800000"]powerpoint.application[/color] [color="#800080"]$ppTypes[/color] [color="#FF0000"]=[/color] [color="#008080"]Add-Type [i]-AssemblyName[/i][/color] [color="#800000"]'Microsoft.Office.Interop.Powerpoint'[/color] [color="#008080"][i]-Passthru[/i][/color] [color="#800080"]$ppSaveFormat[/color] [color="#FF0000"]=[/color] [color="#800080"]$ppTypes[/color] | [color="#008080"][b]Where[/b][/color] {[color="#800080"]$_[/color].Name [color="#FF0000"]-eq[/color] [color="#800000"]"ppSaveFormat"[/color]} [color="#800080"]$MSPPT[/color].presentations.open([color="#800000"]".PPT FILE"[/color], 2, [color="#800080"]$True[/color]) [color="#800080"]$MSPPT[/color].ActivePresentation.SaveAs([color="#800000"]"LOCATION"[/color], [Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType]::ppSaveAsJPG); [color="#008080"][b]Stop-Process[/b] [i]-name[/i][/color] [color="#800000"]"POWERPNT"[/color][color="#008080"][i] -force[/i][/color] [color="#800080"]$MSPPT[/color] [color="#FF0000"]=[/color] [color="#800080"]$Null[/color] Annoyingly, changing $MSPPT.visible = [Microsoft.Office.Core.MsoTriState]::msoTrue to $MSPPT.visible = [Microsoft.Office.Core.MsoTriState]::msoFalse errors, so no doing it silently for me Still. It is what it is. It's working, at least.
ascott2 Posted June 3, 2014 Posted June 3, 2014 (edited) Try $MSPPT.ActivePresentation.Close() $MSPPT.Quit() Both are methods, without the parenthesis, you are just outputting details of the method. Also you may wasn't to use [system.Runtime.Interopservices.Marshal]::ReleaseComObject($MSPPT) after as that will dispose of the Comobject and terminate the processes correctly. Ref http://technet.microsoft.com/en-us/library/ff730962.aspx Hope that helps. Edited June 3, 2014 by ascott2
LosOjos Posted June 3, 2014 Posted June 3, 2014 (edited) Annoyingly, changing $MSPPT.visible = [Microsoft.Office.Core.MsoTriState]::msoTrue to $MSPPT.visible = [Microsoft.Office.Core.MsoTriState]::msoFalse errors, so no doing it silently for me Still. It is what it is. It's working, at least. ...I posted how to do that waaay back just remove the $MSPPT.Visible line entirely and tag another $False on the end of the Open line, it works, honest! EDIT: the RemoveComObject printing 1 is actually a good sign, there's a KB article I was reading earlier that stated it decrements references each time it runs, so should output 0 when all objects are released. The workaround (nasty though it was) was to put it in a loop like so: while([system.Runtime.InteropServices.Marshal]::ReleaseComObject($MSPPT) -gt 0){} EDIT: here's the KB - http://support.microsoft.com/kb/317109 Edited June 3, 2014 by LosOjos
Garacesh Posted June 3, 2014 Author Posted June 3, 2014 ...I posted how to do that waaay back just remove the $MSPPT.Visible line entirely and tag another $False on the end of the Open line, it works, honest! Yeah, that works, but since there's no program 'running', There's no ActivePresentation, so nothing can save. It throws "You cannot call a method on a null-valued expression" Try $MSPPT.ActivePresentation.Close() $MSPPT.Quit() Both are methods, without the parenthesis, you are just outputting details of the method. Ah, I thought the parenthesis was just providing extra information (in the case of my earlier Word script, to not save changes to the file) Interestingly ActivePresentation.Close() works, and ends up with PowerPoint having no file open. Quit() however, seems to do nothing. The program doesn't exit.
LosOjos Posted June 3, 2014 Posted June 3, 2014 (edited) Yeah, that works, but since there's no program 'running', There's no ActivePresentation, so nothing can save. It throws "You cannot call a method on a null-valued expression" You can get a reference to the presentation from Open, like so: $PRES = $MSPPT.presentations.open("C:\test.pptx", 2, $True, $False) Then, replace any instance of $MSPPT.ActivePresentation with $PRES The post I made earlier shows what I mean, I did things a bit differently to you but it'll explain better than I can what I'm on about: Earlier Post EDIT: re-reading my posts, I apologise if I'm coming across as a bit of a d**k, my people skills are somewhat lacking... Edited June 3, 2014 by LosOjos
Garacesh Posted June 3, 2014 Author Posted June 3, 2014 EDIT: re-reading my posts, I apologise if I'm coming across as a bit of a d**k, my people skills are somewhat lacking... You weren't - don't worry about it. The reason I didn't go with that was because there was "no reason to", per-se. I see tutorials online that do a lot of things like $Var = BlahBlahBlah and then only call $Var once.. I think "Why? You're just adding a pointless, extra step!".. I didn't realise there was actually a point to yours.
LosOjos Posted June 3, 2014 Posted June 3, 2014 You weren't - don't worry about it. The reason I didn't go with that was because there was "no reason to", per-se. I see tutorials online that do a lot of things like $Var = BlahBlahBlah and then only call $Var once.. I think "Why? You're just adding a pointless, extra step!".. I didn't realise there was actually a point to yours. It's a habit I've picked up over the years of scripting with Office as I used to get random issues occurring using "Active..." identifiers, particularly with worksheets where the user would click on a different sheet and the macro would go haywire on it... I always learn the hard way lol! So now I make a point of storing a reference to the doc/sheet I'm working with to avoid any issues
Garacesh Posted June 3, 2014 Author Posted June 3, 2014 I guess there's always the point of "All references you might want to change are stored in variables. The variables are set at the very top of the script so it's very easy to change", too.. It's just.. Messy, I feel.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now