The script goes out to AD and collects all of the printQueue objects in the domain (these represent published printers). From this list the script compiles a list of print servers and dumps all the printer info off each server. The downside to this is that if you have printer servers with no published printers, they'll be missed. This is the data currently collected and outputted to a pipe separated text file:

  • Server
  • Name
  • ShareName
  • Comment
  • Error
  • DriverName
  • EnableBIDI
  • JobCount
  • Location
  • PortName
  • Published
  • Queued
  • Shared
  • Status

You can easily add more data to this by adding more fields inside the loop. I tested this with some really slow links and Wn2k/Win2k3 servers and it seems to work fine.

In order to use the script, you'll need to provide the FQDN of your domain in the DOMAIN_TO_SEARCH field at the top of the script. Additionally you'll need to optionally modify the FILE_PATH field to change the output destination.

Feel free to leave any suggestions, issues, etc in the comments area below.

'==========================================================================
' NAME: Query AD Printers
'
' AUTHOR: Brian Desmond, brian@briandesmond.com
'==========================================================================

Option Explicit 

Const DOMAIN_TO_SEARCH = "dc=sub,dc=domain,dc=com"
Const FILE_PATH = "PrinterInventory.txt"

Dim fso
Set fso = WScript.CreateObject("Scripting.FileSystemObject")

Dim PrinterArray
Set PrinterArray = WScript.CreateObject("Scripting.Dictionary") ' this way we eliminate dupes

' populate our list of printers
Dim cnxn
Set cnxn = WScript.CreateObject("ADODB.Connection")
cnxn.Provider = "ADsDSOObject"
cnxn.Open "Active Directory Provider"

Dim cmd
Set cmd = WScript.CreateObject("ADODB.Command")
cmd.ActiveConnection = cnxn

cmd.CommandText = "<LDAP://" & DOMAIN_TO_SEARCH & ">;(&(objectcategory=printQueue)(objectClass=printQueue));serverName;subtree"
cmd.Properties("Page Size") = 100
cmd.Properties("Timeout") = 30
cmd.Properties("Cache Results") = False

Dim rs
Set rs = cmd.Execute

While Not rs.eof 
	If Not PrinterArray.Exists(rs.Fields("serverName").Value) Then
		PrinterArray.Add rs.Fields("serverName").Value, rs.Fields("serverName").Value
	End If 
			
	rs.MoveNext
Wend 

rs.close
cnxn.Close

Dim outputData
Set outputData = fso.CreateTextFile(FILE_PATH, True)
outputData.WriteLine "Server|Name|ShareName|Comment|Error|DriverName|EnableBIDI|JobCount|Location|PortName|Published|Queued|Shared|Status"

Dim wmiSvc
Dim wmiItems
Dim line
Dim serverVersion
Dim serverName

Dim i
For Each i In PrinterArray.Keys
	If Not Trim(PrinterArray.Item(i)) = "" Then 
		serverName = PrinterArray.Item(i)
		WScript.Echo "Trying: " & serverName
		On Error Resume Next 
		serverVersion = CDbl(Left(GetWindowsVersion(serverName), Len(GetWindowsVersion(serverName)) - 5))
		
		Set wmiSvc = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & serverName & "\root\cimv2")
		Set wmiItems = wmiSvc.ExecQuery("SELECT * FROM Win32_Printer",, 48)
		
		If Err.Number <> 0 Then 
			WScript.Echo "Error: " & serverName
			On Error GoTo 0 
		Else 		
			On Error GoTo 0 
			Dim printer
			For Each printer In wmiItems
				line = ""
				
				line = serverName & "|" 
				line = line & printer.Name & "|"
				line = line & printer.ShareName & "|"
				If serverVersion > 5.0 Then ' Comment supported on XP & newer
					If InStr(printer.Comment, VbCrLf) > 0 Then  'scrub bad text
						line = line & replace(printer.Comment, VbCrLf, " ") & "|"
					Else
						line = line & printer.comment & "|"
					End If 
				Else
					line = line & "|"
				End If 
				line = line & GetErrorStateString(printer.DetectedErrorState) & "|"
				line = line & printer.DriverName & "|"
				If serverVersion > 5.0 Then ' Comment & enablebidi supported on XP & newer			
					line = line & printer.EnableBIDI & "|"
				Else
					line = line & "|"
				End If 
				line = line & printer.JobCountSinceLastReset & "|"
				If InStr(printer.location, VbCrLf) > 0 Then 'scrub bad text
					line = line & Replace(printer.Location, VbCrLf, "") & "|"
				Else
					line = line & printer.Location & "|"
				End If 
				line = line & printer.PortName & "|"
				If serverVersion > 5.0 Then ' published, queued, shared supported on XP & newer
					line = line & printer.Published & "|"
					line = line & printer.Queued & "|"
					line = line & printer.Shared & "|"
				Else
					line = line & "|||"
				End If 							
				line = line & printer.Status
				
				outputData.WriteLine line
			Next
		End If 
	End If 
Next

outputData.Close

Set outputData = Nothing
Set fso = Nothing 
Set wmiItems = Nothing
Set wmiSvc = Nothing 

' translates Win32_Printer.DetectedErrorState
Function GetErrorStateString(errorState)
		Select Case errorState
			Case 0
				GetErrorStateString = "Unknown"
			Case 1
				GetErrorStateString = "Other"
			Case 2
				GetErrorStateString = "No Error"
			Case 3
				GetErrorStateString = "Low Paper"
			Case 4
				GetErrorStateString = "No Paper"
			Case 5
				GetErrorStateString = "Low Toner"
			Case 6
				GetErrorStateString = "No Toner"
			Case 7
				GetErrorStateString = "Door Open"
			Case 8
				GetErrorStateString = "Jammed"
			Case 9
				GetErrorStateString = "Offline"
			Case 10
				GetErrorStateString = "Service Requested"
			Case 11
				GetErrorStateString = "Output Bin Full"
			Case Else
				GetErrorStateString = errorState		
		End Select 
End Function 

' this function returns the windows version
Function GetWindowsVersion(server)
	Dim sbWmiSvc
	Set sbWmiSvc = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & server & "\root\cimv2")

	Dim version
	
	Dim osInstances
	Set osInstances = sbWmiSvc.ExecQuery("SELECT * From Win32_OperatingSystem")
	
	Dim os
	For Each os In osInstances
		version = os.Version
	Next
	
	GetWindowsVersion = version
	
	Set sbWmiSvc = Nothing
	Set osInstances = Nothing
	Set os = Nothing 
End Function