Hey, Scripting Guy! How can I print text files to a printer other than the default printer?
— JD
Hey, JD. Boy, talk about pride going before the fall. When we first set out to answer this question we already “knew” how to solve the problem. We were well aware that the Shell object provides a way for you to print text files to the default printer; we were also well aware that this was the only printer to which you could print text files. But, being the Scripting Guys and all, we figured we had a clever workaround for this problem: we’d tell everyone to use Microsoft Word to print out the text files. And then we’d just sit back and listen to everyone tell us how smart we were.
Oops. It was only after we started writing up our answer that we actually bothered to check and see if Microsoft Word actually did allow you to choose an alternate printer when printing documents from a script. As it turns out, it doesn’t: Word requires you to print to the default printer as well. As painful as it is to admit this, the Scripting Guys were wrong.
Note. OK, true: we’re wrong lots of times. But that doesn’t make it any less painful. |
As you might expect, this then became a matter of pride: we had to find a way to print a text file to a different printer. Unfortunately, we couldn’t find such a way. Therefore, we opted to go with Plan B: if we can print only to the default printer, well, then we’ll just change the default printer, print the file, and then change back. Here’s a solution that will work on Windows XP and Windows Server 2003:
strComputer = “.”Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
Set colPrinters = objWMIService.ExecQuery _ (“Select * from Win32_Printer Where Default = TRUE”)
For Each objPrinter in colPrinters strOldDefault = objPrinter.Name strOldDefault = Replace(strOldDefault, “\”, “\\”) Next
Set colPrinters = objWMIService.ExecQuery _ (“Select * from Win32_Printer Where Name = ‘\\\\atl-ps-01\\printer2′”)
For Each objPrinter in colPrinters objPrinter.SetDefaultPrinter() Next
Wscript.Sleep 2000
TargetFolder = “C:\Logs” Set objShell = CreateObject(“Shell.Application”) Set objFolder = objShell.Namespace(TargetFolder) Set colItems = objFolder.Items For Each objItem in colItems objItem.InvokeVerbEx(“Print”) Next
Set colPrinters = objWMIService.ExecQuery _ (“Select * from Win32_Printer Where Name = ‘” & strOldDefault & “‘”)
For Each objPrinter in colPrinters objPrinter.SetDefaultPrinter() Next
Note. Why only Windows XP and Windows Server 2003? Well, in prior versions of Windows it’s not real easy to identify – and change – the default printer; that’s because the WMI class Win32_Printer has neither a Default property nor a SetDefaultPrinter() method. Therefore, we decided to go with the XP/2003 solution for today; if there’s enough interest in doing a Windows 2000 version, well, we’ll see what we can come up with. |
Admittedly, this script might seem a tiny bit complicated; bear with us, though, and you’ll see what we’re doing and why. We begin by connecting to the WMI service on the local computer and then retrieving the Name of the default printer. That’s what we do here:
strComputer = “.”Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
Set colPrinters = objWMIService.ExecQuery _ (“Select * from Win32_Printer Where Default = TRUE”)
For Each objPrinter in colPrinters strOldDefault = objPrinter.Name strOldDefault = Replace(strOldDefault, “\”, “\\”) Next
The first part of this code snippet should be self-explanatory; the only semi-tricky part lies in our WQL query. We want information only about the default printer so we construct a query that returns data for printers where the Default property is equal to True. Because there can be only one default printer on a computer, this query should return just one printer.
The second part of the snippet – the For Each loop – might take a little bit more explaining. In the For Each loop we retrieve the Name of the default printer (remember, that’s the only printer in the collection) and store it in a variable named strOldDefault. So far so good. We then have this line of code:
strOldDefault = Replace(strOldDefault, “\”, “\\”)
Why? Well, if the default printer happens to be a network printer it’s going to have a name like this: \\atl-ps-01\printer1. That’s fine, except that later on in the script we need to use that printer name in a WQL Where clause. Because the \ is a reserved character, we have to “escape” each \ character by doubling it; in other words, our printer – for purposes the Where clause – must have the name \\\\atl-ps-01\\printer1. We use the VBScript Replace function to replace any \ in the printer name with a pair of \’s.
Got that? Good. Next we have this block of code:
Set colPrinters = objWMIService.ExecQuery _ (“Select * from Win32_Printer Where Name = ‘\\\\atl-ps-01\\printer2′”)For Each objPrinter in colPrinters objPrinter.SetDefaultPrinter() Next
Wscript.Sleep 2000
Here we’re requesting a new collection, this one consisting of all printers with the name \\\\atl-ps-01\\printer2 (note the doubled-up \’s); as you might have guessed, this is the printer we want to print to. We retrieve this collection (which, again, will have only one member), then use the SetDefaultPrinter() method to make \\atl-ps-01\printer2 the default printer. We then pause the script for two seconds, just to make sure the change is made.
Now that we have a new default printer we can go ahead and print our text file. We’ve taken this code directly from a previous Hey, Scripting Guy! column, the one on printing text files. We won’t talk about the code here; see the column on printing text files if you need more information:
TargetFolder = “C:\Logs” Set objShell = CreateObject(“Shell.Application”) Set objFolder = objShell.Namespace(TargetFolder) Set colItems = objFolder.Items For Each objItem in colItems objItem.InvokeVerbEx(“Print”) Next
So what have we done so far? Well, we’ve determined the name of the default printer (for this discussion we’ll assume it’s \\atl-ps-01\printer1) and stored it in a variable named strOldDefault. We’ve changed the default printer to \\atl-ps-01\printer2 and printed our text files. Now all we have to do is restore the old default printer, something we do with this block of code:
Set colPrinters = objWMIService.ExecQuery _ (“Select * from Win32_Printer Where Name = ‘” & strOldDefault & “‘”)For Each objPrinter in colPrinters objPrinter.SetDefaultPrinter() Next
As you can see, here we connect to the old default printer; that is, we request a collection consisting of all the printers that have a Name property equal to the value stored in the variable strOldDefault. As soon as we get that collection we then use the SetDefaultPrinter() method to reset \\atl-ps-01\printer1 as the default printer. The net result: we printed our text files to printer2, yet printer1 remains the default printer. It might not be a particularly clever solution, but it works.
Besides, we’ve learned our lesson about trying to be too clever. We promise never to try and do anything smart again (which is one promise we can probably keep).
0 comments