[ Team LiB ] |
22.4 Manipulating Print Queues and Print JobsSo far we've shown you how to use ADSI to manipulate persistent and dynamic objects, such as shares, sessions, and resources. Now we're going to examine printer queues and jobs. In this section, we're going to lead you through creating scripts to do the following:
One point before we go on: at the end of Chapter 20, we detail a function called SearchAD. We need to use it now to search Active Directory for the printer's ADsPath and store it in arrSearchResults(0,0). 22.4.1 Identifying Print Queues in Active DirectoryList-Print-Queue.vbs in Example 22-2 is a heavily commented script, so it should be easy to follow. Example 22-2. List-Print-Queue.vbs identifies print queues in Active DirectoryOption Explicit On Error Resume Next '********************************************************************** 'Active Directory path to start the search from '********************************************************************** Const strDomainToSearch = "LDAP://dc=mycorp,dc=com" '********************************************************************** 'Maximizes the Notepad screen when started '********************************************************************** Const vbMaximizedFocus = 3 '********************************************************************** 'Sets the location of the temporary file '********************************************************************** Const TEMPFILE = "C:\PRINTERLIST-TEMP.TXT" '********************************************************************** 'Opens a file and lets you start writing from the beginning of the file '********************************************************************** Const ForWriting = 2 Dim arrPaths( ), fso, ts, strItem, intRC, objShell, intIndex If Not SearchAD(strDomainToSearch,"(objectClass=printQueue)","SubTree",arrPaths) Then MsgBox "Printer listing failed!" Else '********************************************************************** 'Opens the temporary text file for writing. If the text file already 'exists, overwrite it. '********************************************************************** Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile(TEMPFILE, ForWriting, True) '********************************************************************** ' Writes out the printer ADsPaths '********************************************************************** ts.WriteLine "Total printers in Active Directory: " & UBound(arrPaths)+1 ts.WriteLine For intIndex=0 To UBound(arrPaths) ts.WriteLine arrPaths(intIndex,1) ts.WriteLine vbTab & arrPaths(intIndex,0) Next ts.Close '********************************************************************** 'Sets the third parameter of the Shell::Run method to TRUE, which 'allows the script to open up the file in Notepad and maximize the 'screen. The script stops executing until you close Notepad, which 'places a return code into intRC. When Notepad is closed, the script 'deletes the file. '********************************************************************** Set objShell = CreateObject("WScript.Shell") intRC = objShell.Run ("notepad.exe " & TEMPFILE, vbMaximizedFocus, TRUE) fso.DeleteFile(TEMPFILE) End If The script uses the search function to search Active Directory for all objects of class printQueue, writes their ADsPath and cn attributes out to a temporary file, displays the file for you in Notepad, and then erases the file when Notepad is closed. The code for opening and closing files and displaying them with Notepad is the same as that in the ShowUsers.vbs script earlier in the chapter. Here is an example of the output from this program: Total printers in Active Directory: 3 DC1-ph_stores_hp4000 LDAP://CN=DC1-stores_hp4000,CN=DC1,OU=Domain Controllers,DC=mycorp,DC=com SS-0001-Alex&Mark LDAP://CN=COMPUTER-0789-Alex&Mark,CN=COMPUTER-0789,OU=Finances, _ OU=Finance Clients,OU=Clients,DC=mycorp,DC=com ZZ-NT0089-HP LaserJet 4M Plus LDAP://CN=ZZ-0089-HP LaserJet 4M Plus,CN=ZZ-0089,OU=Finances, _ OU=Finance Clients,OU=Clients,DC=mycorp,DC=com
Let's take a look at the output for a moment. The first PrintQueue object is called "DC1-stores_hp4000" and is held within the DC1 domain controller, as if that DC were itself a container object. Computer objects are a special case and can act as containers and hold other objects beneath them. The computer called DC1 (actually an Active Directory domain controller) is actually the parent of this printQueue object. We could go through listing the properties of the PrintQueue objects for you in a script, but this is very easy to do, and to save this chapter from getting any longer, you can find the print queue properties yourself on MSDN. 22.4.2 Binding to a Print QueueUnfortunately, we cannot connect to this printQueue object and list the jobs because the Active Directory object that we have connected to is only the advertisement or publication that such a queue exists. To connect to the printer object that holds the jobs and that we can manipulate, we need to use the WinNT namespace. While we could provide a simple piece of code to connect to a queue, we'd like to modify the previous script to show you how that could be accomplished. We'll list the queues as before, but this time, we'll also bind to the first queue that we find (and only the first) and print out some properties. To see what we need to do, let's take a look at the first queue in the previous output. The actual printer path that we need to connect to is: WinNT://MYCORP/DC1/stores_hp4000 We need to massage the data returned by the SearchAD function to produce the information about the computer name and the printer name. List-Print-Queue-2.vbs is the result, a modified version of List-Print-Queue.vbs with two extra sets of information provided. The first is a new constant to define the workgroup or domain; the second we'll go through after the script in Example 22-3. Example 22-3. List-Print-Queue-2.vbs binds to the print queueOption Explicit On Error Resume Next '********************************************************************** ' Sets the domain or workgroup that the servers or workstations reside in '********************************************************************** Const strDomainOrWorkGroup = "MYCORP" '********************************************************************** 'Active Directory path to start the search from '********************************************************************** Const strDomainToSearch = "LDAP://dc=mycorp,dc=com" '********************************************************************** 'Maximizes the Notepad screen when started '********************************************************************** Const vbMaximizedFocus = 3 '********************************************************************** 'Sets the location of the temporary file '********************************************************************** Const TEMPFILE = "C:\PRINTERLIST-TEMP.TXT" '********************************************************************** 'Opens a file and lets you start writing from the beginning of the file '********************************************************************** Const ForWriting = 2 Dim arrPaths( ), fso, ts, strItem, intRC, objShell, intIndex, strComputer Dim strPrinter, objPrinter If Not _ SearchAD(strDomainToSearch,"(objectClass=printQueue)","SubTree",arrPaths) Then MsgBox "Printer listing failed!" Else '********************************************************************** 'Opens the temporary text file for writing. If the text file already 'exists, overwrite it '********************************************************************** Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.OpenTextFile(TEMPFILE, ForWriting, True) '********************************************************************** ' Writes out the printer ADsPaths '********************************************************************** ts.WriteLine "Total printers in Active Directory: " & UBound(arrPaths)+1 ts.WriteLine For intIndex=0 To UBound(arrPaths) ts.WriteLine arrPaths(intIndex,1) ts.WriteLine vbTab & arrPaths(intIndex,0) Next ts.WriteLine '********************************************************************** 'Bind to the first printer and list the properties '********************************************************************** strComputer = Split(arrPaths(0,0),",")(1) strComputer = Right(strComputer,Len(strComputer) - 3) strPrinter = Right(arrPaths(0,1),Len(arrPaths(0,1)) - Len(strComputer) - 1) Set objPrinter = GetObject("WinNT://" & strDomainOrWorkGroup & "/" _ & strComputer & "/" & strPrinter) ts.WriteLine "Name : " & objPrinter.Name ts.WriteLine "Status : " & objPrinter.Status ts.WriteLine "Model : " & objPrinter.Model ts.WriteLine "Location : " & objPrinter.Location ts.WriteLine "PrinterPath : " & objPrinter.PrinterPath ts.Close '********************************************************************** 'Sets the third parameter of the Shell::Run method to TRUE, which 'allows the script to open up the file in Notepad and maximize the 'screen. The script stops executing until you close Notepad, which 'places a return code into intRC. When Notepad is closed, the script 'deletes the file. '********************************************************************** Set objShell = CreateObject("WScript.Shell") intRC = objShell.Run ("notepad.exe " & TEMPFILE, vbMaximizedFocus, TRUE) fso.DeleteFile(TEMPFILE) End If To bind to the printer and list the properties, the script first splits the entire LDAP path of the first array element, using the comma as the delimiter. It then immediately retrieves the second item (indexed as 1 because item numbers start at 0) and adds it to strComputer. You use VBScript's Split function like this: arrResults = Split("Moose 1,Moose 2,Penguin,Banana,Squirrel,Hamster",",") This results in arrResults(0) containing Moose 1 and arrResults(5) containing Hamster. Instead of passing the results out to an array, we can directly retrieve one value from that array by passing the index value to the Split function. To retrieve and print Squirrel from the preceding string, we use the following code: MsgBox Split("Moose 1,Moose 2,Penguin,Banana,Squirrel,Hamster",",")(4) You can see that here we don't need arrResults at all. That's how Split works in the previous code. The first item returned is "CN=DC1". We can then use the VBScript Right function to take the righthand part of that string—ignoring the first three characters, i.e., DC1—and put the result back into the strComputer variable. We now need the printer name. This is done by taking the right-hand part of the cn attribute returned (DC1- stores_hp4000) and ignoring the number of characters equal to the length of the computer name. That yields "stores_hp4000". We then can assemble all the pieces and bind to the printer object on that computer. We finally print out five attributes (IADs::Name, IADsPrintQueueOperations::Status, IADsPrintQueue::Model, IADsPrintQueue::Location, and IADsPrintQueue::PrinterPath) of that printer to confirm that the printer exists. 22.4.3 IADsPrintQueueOperations and Print QueuesHaving successfully connected to a print queue, you can then use the IADsPrintQueueOperations interface to its full extent. This interface has methods with names like Pause, Resume, and Purge that you should recognize; they correspond to specific print queue functions. There is one important property status that is also available and allows you to query the status of the printer. While List-Print-Queue-2.vbs just prints out this value as an integer, Display-Print-Queue-Status.vbs is a script that binds to the same printer and uses a Select Case statement to print the status out using the MsgBox function. This script is listed in Example 22-4. Example 22-4. Display-Print-Queue-Status.vbs uses MsgBox to display printer status'********************************************************************** 'IADsPrintQueueOperations::Status values '********************************************************************** Const ADS_PRINTER_PAUSED = &H00000001 Const ADS_PRINTER_PENDING_DELETION = &H00000002 Const ADS_PRINTER_ERROR = &H00000003 Const ADS_PRINTER_PAPER_JAM = &H00000004 Const ADS_PRINTER_PAPER_OUT = &H00000005 Const ADS_PRINTER_MANUAL_FEED = &H00000006 Const ADS_PRINTER_PAPER_PROBLEM = &H00000007 Const ADS_PRINTER_OFFLINE = &H00000008 Const ADS_PRINTER_IO_ACTIVE = &H00000100 Const ADS_PRINTER_BUSY = &H00000200 Const ADS_PRINTER_PRINTING = &H00000400 Const ADS_PRINTER_OUTPUT_BIN_FULL = &H00000800 Const ADS_PRINTER_NOT_AVAILABLE = &H00001000 Const ADS_PRINTER_WAITING = &H00002000 Const ADS_PRINTER_PROCESSING = &H000040000 Const ADS_PRINTER_INITIALIZING = &H00008000 Const ADS_PRINTER_WARMING_UP = &H00010000 Const ADS_PRINTER_TONER_LOW = &H00020000 Const ADS_PRINTER_NO_TONER = &H00040000 Const ADS_PRINTER_PAGE_PUNT = &H00080000 Const ADS_PRINTER_USER_INTERVENTION = &H00100000 Const ADS_PRINTER_OUT_OF_MEMORY = &H00200000 Const ADS_PRINTER_DOOR_OPEN = &H00400000 Const ADS_PRINTER_SERVER_UNKNOWN = &H00800000 Const ADS_PRINTER_POWER_SAVE = &H01000000 '********************************************************************** ' Bind to the printer '********************************************************************** Set objPrinter = GetObject("WinNT://MYCORP/DC1/stores_hp4000") '********************************************************************** ' Print out the queue status '********************************************************************** Select Case objPrinter.Status Case 0 MsgBox "On line" Case ADS_PRINTER_PAUSED MsgBox "Paused" Case ADS_PRINTER_PENDING_DELETION MsgBox "Pending deletion" Case ADS_PRINTER_ERROR MsgBox "Printer error" Case ADS_PRINTER_PAPER_JAM MsgBox "Paper jam" Case ADS_PRINTER_PAPER_OUT MsgBox "Out of paper" Case ADS_PRINTER_MANUAL_FEED MsgBox "Manual feed pending" Case ADS_PRINTER_PAPER_PROBLEM MsgBox "Paper trouble" Case ADS_PRINTER_OFFLINE MsgBox "Offline" Case ADS_PRINTER_IO_ACTIVE MsgBox "We/O active" Case ADS_PRINTER_BUSY MsgBox "Printer busy" Case ADS_PRINTER_PRINTING MsgBox "Printing" Case ADS_PRINTER_OUTPUT_BIN_FULL MsgBox "Output bin full" Case ADS_PRINTER_NOT_AVAILABLE MsgBox "Not available" Case ADS_PRINTER_WAITING MsgBox "Waiting" Case ADS_PRINTER_PROCESSING MsgBox "Processing" Case ADS_PRINTER_INITIALIZING MsgBox "Initializating" Case ADS_PRINTER_WARMING_UP MsgBox "Warming up" Case ADS_PRINTER_TONER_LOW MsgBox "Toner low" Case ADS_PRINTER_NO_TONER MsgBox "Without toner" Case ADS_PRINTER_PAGE_PUNT MsgBox "Page punt" Case ADS_PRINTER_USER_INTERVENTION MsgBox "User intervention required" Case ADS_PRINTER_OUT_OF_MEMORY MsgBox "Out of memory" Case ADS_PRINTER_DOOR_OPEN MsgBox "Door open" Case ADS_PRINTER_SERVER_UNKNOWN MsgBox "Server unknown" Case ADS_PRINTER_POWER_SAVE MsgBox "Power save" Case Else MsgBox "UNKNOWN" End Select The final important IADsPrintQueueOperations method that is available to you is IADsPrintQueueOperations::PrintJobs, which returns a collection of print jobs that you can interact with using IADsCollection. 22.4.4 Print JobsThe IADsPrintQueueOperations::PrintJobs method allows you to obtain a collection object that you then can use in a For Each...Next loop. You can pause and resume the jobs using methods of the same name from the IADsPrintJobOperations interface. In addition, as the collection represents the underlying print jobs, you also can use the IADsCollection::Add and IADsCollection::Remove methods to add and remove print jobs from the collection. The Add method is not of much use here, but the Remove method is, since this allows you to delete jobs from the queue. Assuming we had bound successfully to the queue as before, this section of code would purge the queue manually. The following code gives you some idea of what you can do: For Each objJob in objPrinter.PrintJobs objPrinter.PrintJobs.Remove (objJob.Name) Next Example 22-5 demonstrates that each job has a number of attributes from IADsPrintJob and IADsPrintJobOperations you can print. This is not the definitive list, and we urge you to check out MSDN for the full set. Example 22-5. Display some properties and the status of each print job'********************************************************************** 'IADsPrintJobOperations::Status values '********************************************************************** Const ADS_JOB_PAUSED = &H00000001 Const ADS_JOB_ERROR = &H00000002 Const ADS_JOB_DELETING = &H00000004 Const ADS_JOB_PRINTING = &H00000010 Const ADS_JOB_OFFLINE = &H00000020 Const ADS_JOB_PAPEROUT = &H00000040 Const ADS_JOB_PRINTED = &H00000080 Const ADS_JOB_DELETED = &H00000100 '********************************************************************** ' Bind to the printer '********************************************************************** Set objPrinter = GetObject("WinNT://MYCORP/DC1/stores_hp4000") '********************************************************************** 'Print out some properties and the status of each job '********************************************************************** For Each objJob in objPrinter.PrintJobs str = "Name: " & objJob.Name & vbCrLf str = str & "Position: " & objJob.Position & vbCrLf str = str & "Size: " & objJob.Size & vbCrLf str = str & "Total Pages: " & objJob.TotalPages & vbCrLf str = str & "Pages Printed: " & objJob.PagesPrinted & vbCrLf Select Case objJob.Status Case 0 str = str & "Status : " & "OK" Case ADS_JOB_PAUSED str = str & "Status : " & "Paused" Case ADS_JOB_ERROR str = str & "Status : " & "Error" Case ADS_JOB_DELETING str = str & "Status : " & "Deleting" Case ADS_JOB_PRINTING str = str & "Status : " & "Printing" Case ADS_JOB_OFFLINE str = str & "Status : " & "Offline" Case ADS_JOB_PAPEROUT str = str & "Status : " & "Paper Out" Case ADS_JOB_PRINTED str = str & "Status : " & "Printed" Case ADS_JOB_DELETED str = str & "Status : " & "Deleted" Case Else str = str & "Status : " & "Unknown" End Select MsgBox str Next Again, just as in Display-Print-Queue-Status.vbs, the IADsPrintJobOperations::Status property method has a defined set of constants that can be used to tell you about a job. One thing to note is that IADsPrintJobOperations::Position is a read/write value, so you can use this to move jobs around in the queue print sequence. Actually, a number of IADsPrintJob property methods are also read/write: IADsPrintJob::StartTime and IADsPrintJob::UntilTime (to set a future time before which the job can be printed), IADsPrintJob::Priority, IADsPrintJob::Description, and IADsPrintJob::Notify, plus IADsPrintJob::NotifyPath (the user is contacted when the job is printed). |
[ Team LiB ] |