Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Need to connect to printers base on OU

Status
Not open for further replies.

sparkbyte

Technical User
Sep 20, 2002
879
US
I need to modifuy my script to find the users OU and connect to any printers that are in the same OU.

Here is the script so far.

Code:
'****************************************************
'*  Script by:  John Fuhrman
'*  Date:       2008, August 21
'****************************************************


Option Explicit 
'On Error Resume Next 

Dim WSHShell: Set WSHShell = CreateObject("WScript.Shell")
Dim WSHNetwork: Set WSHNetwork = CreateObject("WScript.Network")

Const ADS_SCOPE_SUBTREE = 2

Dim objConnection: Set objConnection = CreateObject("ADODB.Connection")
Dim objCommand: Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"

'Automatically find the domain name
Dim objDomain: Set objDomain = getObject("LDAP://rootDse")
Dim strDomain: strDomain = objDomain.Get("dnsHostName")
Dim strLDAPDomain: strLDAPDomain = "LDAP://" & objDomain.Get("defaultNamingContext")
Dim objLDAPDomain: Set objLDAPDomain = GetObject(strLDAPDomain)

' Get the currently logged in user
Dim strUserName: strUserName = WshNetwork.UserName
' Get the currently logged in users distinguished Name from AD.
Const E_ADS_PROPERTY_NOT_FOUND  = &h8000500D

Dim objUser: Set objUser = GetObject _
    ("LDAP://" & GetDistinguishedName(strUserName))

If strDomain = "" Then 
'If strDomain <> "" Then 
GetADprinters 
Else 
ConnectRemote
End If 

Public Sub GetADprinters()

' Create dictionary object to store found printers 
Dim objDictPrntrs: Set objDictPrntrs = CreateObject("Scripting.Dictionary")
objDictPrntrs.CompareMode = vbTextCompare

' Active Directory printer Enumoration
Set objCommand.ActiveConnection = objConnection
objCommand.CommandText = "Select printerName, serverName from " _     
    & " '" & strLDAPDomain & "'  where objectClass='printQueue'"  
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
Dim objRecordSet: Set objRecordSet = objCommand.Execute

' Loop through the list of printers in AD and add them to our dictionary object
' to be able to connect to them.
Do Until objRecordSet.EOF
	objDictPrntrs.Add "\\" & objRecordSet.Fields("serverName").Value &_
			"\" & objRecordSet.Fields("printerName").Value, _
			UCase(objRecordSet.Fields("printerName").Value)
	objRecordSet.MoveNext
Loop ' End Do Until Loop

	' loop through printer connections
	Dim WSHPrinters, LOOP_COUNTER
	Set WSHPrinters = WSHNetwork.EnumPrinterConnections
	For LOOP_COUNTER = 0 To WSHPrinters.Count - 1 Step 2
	    PrinterPath = WSHPrinters.Item(LOOP_COUNTER +1)
	    ' if the current path exist in our dictionary remove it
'	    If objDictPrntrs.Exists(PrinterPath) Then WScript.Echo "printer exists"
	    If objDictPrntrs.Exists(PrinterPath) Then objDictPrntrs.Remove PrinterPath
	Next

	' Loop through found AD printers and connect to them.
	Dim PrinterPath
	For Each PrinterPath In objDictPrntrs.Keys
		WSHNetwork.AddWindowsPrinterConnection PrinterPath
	Next
End Sub 

Sub ConnectRemote()
' Enumerate printers based on a list of print servers.
' Create disctionary object to store found printers 
Dim objDictPrnts: Set objDictPrnts = CreateObject("Scripting.Dictionary")
objDictPrnts.CompareMode = vbTextCompare

' Create array with list of print servers
Dim arrPrintServers(1)
arrPrintServers(0) = "mdl-fp1"
arrPrintServers(1) = "mdl-vs1"
'arrPrintServers(2) = ""
'arrPrintServers(3) = ""
'arrPrintServers(4) = ""
'arrPrintServers(5) = ""
'arrPrintServers(6) = ""
'arrPrintServers(7) = ""
'arrPrintServers(8) = ""
'arrPrintServers(9) = ""

' Begin loop for each print server
Dim PrintServer
For Each PrintServer In arrPrintServers
'WScript.Echo PrintServer

' Enumerate all printers on Print server
Dim strPrnServer: strPrnServer = PrintServer
Dim objWMIService: Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strPrnServer & "\root\cimv2")
Dim colInstalledPrinters: Set colInstalledPrinters =  objWMIService.ExecQuery _
    ("Select * from Win32_Printer")
' Add printers found to a dictionary object for later 
Dim objPrinter
For Each objPrinter In colInstalledPrinters
' create a dictionary to store our printer paths
On Error Resume Next 
'WScript.Echo objPrinter.Name
objDictPrnts.Add "\\" & strPrnServer & "\" & objPrinter.Name, UCase(objPrinter.Name)
Next

	' loop through printer connections
	Dim WSHPrinters, LOOP_COUNTER
	Set WSHPrinters = WSHNetwork.EnumPrinterConnections
	For LOOP_COUNTER = 0 To WSHPrinters.Count - 1 Step 2
	    PrinterPath = WSHPrinters.Item(LOOP_COUNTER +1)
	    ' if the current path exist in our dictionary remove it
'	    If objDictPrnts.Exists(PrinterPath) Then WScript.Echo "printer exists"
	    If objDictPrnts.Exists(PrinterPath) Then objDictPrnts.Remove PrinterPath
	Next

' Loop through the printers add connect to them.
Dim PrinterPath
For Each PrinterPath In objDictPrnts.Keys
	WSHNetwork.AddWindowsPrinterConnection PrinterPath
Next
Next 
' End loop for each print server
End Sub 

Function GetDistinguishedName(strUserName)
    Const ADS_SCOPE_SUBTREE = 2
    Dim objConnection, objCommand, strDomain, objRoot, objRecordSet
    
    Set objRoot = GetObject("LDAP://rootDSE")
    strDomain = objRoot.Get("defaultNamingContext")
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand = CreateObject("ADODB.Command")
    objConnection.Provider = ("ADsDSOObject")
    objConnection.Open "Active Directory Provider"
    objCommand.ActiveConnection = objConnection
    objCommand.CommandText = "SELECT distinguishedName FROM " & _
                             "'LDAP://" & strDomain & "' " & _
                             "WHERE samAccountName = '" & strUserName & "'"
    objCommand.Properties("SearchScope") = ADS_SCOPE_SUBTREE
    Set objRecordSet = objCommand.Execute
    If Not objRecordSet.EOF Then
        GetDistinguishedName = objRecordSet.Fields.Item("distinguishedName").Value
    End If
End Function

Thanks
John Fuhrman
 
Here's my take on your script. I moved a few things around to improve readability and performance...

Code:
Option Explicit 
'On Error Resume Next 

Dim WSHNetwork: Set WSHNetwork = CreateObject("WScript.Network")

'Automatically find the domain name
Dim objDomain: Set objDomain = getObject("LDAP://rootDse")
Dim strLDAPDomain: strLDAPDomain = "LDAP://" & objDomain.Get("defaultNamingContext")

' Get the currently logged in users distinguished Name from AD.
Dim strUserDN : Set strUserDN = GetDistinguishedName()

' If strLDAPDomain = "" Then
If strLDAPDomain <> "" Then 
	GetADprinters 
Else 
	ConnectRemote
End If 

Sub GetADprinters()
	Dim objDictPrntrs, objConnection, objCommand, objRecordSet
    Dim WSHPrinters, LOOP_COUNTER, PrinterPath, sServer, sPrntName
    Dim sUserOU, sPrntDN, sPrntOU

	sUserOU = GetOU(strUserDN)

	' Create dictionary object to store found printers 
	Set objDictPrntrs = CreateObject("Scripting.Dictionary")
	objDictPrntrs.CompareMode = vbTextCompare
	
	' Active Directory printer Enumeration
	Const ADS_SCOPE_SUBTREE = 2
	
	Set objConnection = CreateObject("ADODB.Connection")
	With objConnection
		.Provider = "ADsDSOObject"
		.Open "Active Directory Provider"
	End With
	
	Set objCommand =   CreateObject("ADODB.Command")
	With objCommand
	Set objCommand.ActiveConnection = objConnection
		.CommandText = _
			"SELECT distinguishedName, printerName, serverName " & _
			"FROM '" & strLDAPDomain & "' " & _
			"WHERE objectClass = 'printQueue'"
		.Properties("Page Size") = 1000
		.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
	End With

	Set objRecordSet = objCommand.Execute
	
	' Loop through the list of printers in AD and add them to our dictionary object
	' to be able to connect to them.
	Do Until objRecordSet.EOF
		sServer = objRecordSet.Fields("serverName").Value
		sPrntName = objRecordSet.Fields("printerName").Value
		sPrntDN = objRecordSet.Fields("distinguishedName").Value

		' Filter repeats reported from AD.
		If Not objDictPrntrs.Exists("\\" & sServer & "\" & sPrntName) Then
			' Create dictionary item with printer path as key and printer OU as item
			objDictPrntrs.Add "\\" & sServer & "\" & sPrntName, UCase(GetOU(sPrntDN))
' 		Else
' 			WScript.Echo "Repeat!	" & sServer & "	" & objDictPrntrs.Item("\\" & sServer & "\" & sPrntName)
		End If
' 		WScript.Echo "\\" & sServer & "\" & sPrntName
' 		WScript.Echo vbTab & sPrntDN

		objRecordSet.MoveNext
	Loop ' End Do Until Loop
	
    ' loop through printer connections
    Set WSHPrinters = WSHNetwork.EnumPrinterConnections
    For LOOP_COUNTER = 0 To WSHPrinters.Count - 1 Step 2
        PrinterPath = WSHPrinters.Item(LOOP_COUNTER + 1)
        ' if the current path exist in our dictionary remove it
        If objDictPrntrs.Exists(PrinterPath) Then objDictPrntrs.Remove PrinterPath
    Next

    ' Loop through found AD printers and connect to them.
    For Each PrinterPath In objDictPrntrs.Keys
'     	WScript.Echo PrinterPath
		' Only connect to printer if User's OU matches Printer's OU
		If objDictPrntrs.Item(PrinterPath) = sUserOU Then
			WSHNetwork.AddWindowsPrinterConnection PrinterPath
		End If
    Next
End Sub 

Sub ConnectRemote()
	' Enumerate printers based on a list of print servers.
	' Create disctionary object to store found printers 
	Dim objDictPrnts: Set objDictPrnts = CreateObject("Scripting.Dictionary")
	objDictPrnts.CompareMode = vbTextCompare
	
	' Create array with list of print servers
	Dim arrPrintServers(1)
	arrPrintServers(0) = "mdl-fp1"
	arrPrintServers(1) = "mdl-vs1"
	'arrPrintServers(2) = ""
	'arrPrintServers(3) = ""
	'arrPrintServers(4) = ""
	'arrPrintServers(5) = ""
	'arrPrintServers(6) = ""
	'arrPrintServers(7) = ""
	'arrPrintServers(8) = ""
	'arrPrintServers(9) = ""
	
	' Begin loop for each print server
	Dim strPrintServer
	For Each strPrintServer In arrPrintServers
		'WScript.Echo PrintServer
		
		' Enumerate all printers on Print server
		Dim objWMIService: Set objWMIService = GetObject("winmgmts:\\" & strPrnServer & "\root\cimv2")
		Dim colInstalledPrinters: Set colInstalledPrinters =  objWMIService.ExecQuery("Select * from Win32_Printer")
		' Add printers found to a dictionary object for later 
		Dim objPrinter
		For Each objPrinter In colInstalledPrinters
			' create a dictionary to store our printer paths
			On Error Resume Next 
			'WScript.Echo objPrinter.Name
			objDictPrnts.Add "\\" & strPrnServer & "\" & objPrinter.Name, UCase(objPrinter.Name)
		Next
		
		' loop through printer connections
		Dim WSHPrinters, LOOP_COUNTER
		Set WSHPrinters = WSHNetwork.EnumPrinterConnections
		For LOOP_COUNTER = 0 To WSHPrinters.Count - 1 Step 2
		    PrinterPath = WSHPrinters.Item(LOOP_COUNTER +1)
		    ' if the current path exist in our dictionary remove it
		'        If objDictPrnts.Exists(PrinterPath) Then WScript.Echo "printer exists"
		    If objDictPrnts.Exists(PrinterPath) Then objDictPrnts.Remove PrinterPath
		Next
		
		' Loop through the printers add connect to them.
		Dim PrinterPath
		For Each PrinterPath In objDictPrnts.Keys
		    WSHNetwork.AddWindowsPrinterConnection PrinterPath
		Next
	Next 
	' End loop for each print server
End Sub 

Function GetDistinguishedName()
	Dim objADSysInfo : Set objADSysInfo = CreateObject("ADSystemInfo")
	GetDistinguishedName = objADSysInfo.UserName
End Function

Function GetOU(DistName)
	Dim Counter, DN
	DN = Split(DistName, ",")
	For Counter = 0 To UBound(DN)
		If Left(DN(Counter),3) = "OU=" Then
			If GetOU = "" Then
				GetOU = DN(Counter)
			Else
				GetOU = GetOU & "," & DN(Counter)
			End If
		End If
	Next
End Function

I think that your idea of matching up the User's OU with the Printer's OU isn't 100% plausable. Generally, most ADs have all of the servers in one OU and users in some hierarchy related to the business.

It may be better to select printer based on the OU that contains the computer account. It seems more likely to me that a group of computers would be in the same OU as the print server for that group.


PSC

Governments and corporations need people like you and me. We are samurai. The keyboard cowboys. And all those other people out there who have no idea what's going on are the cattle. Mooo! --Mr. The Plague, from the movie "Hackers
 
PSC thanks for the comments. You may be right about placing the printers with the server objects, but the clients that the script was intended for only has a couple of servers in KC and the users in AD are organized by department/job function and by luck/happenstance the printers are also located with the users in each department. The only exception are a few users that travel between geographic sites with laptops.

Here is a copy of the current script.

Code:
'****************************************************
'*  Script:		Connect2ADPrinters.vbs
'*  Script by:  John Fuhrman
'*  Date:       2008, August 21
'*  Version:	1.5 (2008, September 5)
'*  
'*  Description:
'*  This script connects to printers that have been
'*  published in Active Directory and moved into the
'*  OU of the person logging on and sets the users 
'*  Default Printer based on security group membership.
'*  
'*  Printer security groups need to be prefixed with
'*  "PTR-" and suffixed with the printer name for
'*  the script to identify 
'*
'*  The script also detects whether the printer has
'*  already been connected to and skips the connect if
'*  the printer is pre-existing.
'****************************************************


On Error Resume Next  

Function GetUserLDAPOU(strUser)
Dim objRecordSet
Dim objConnection, objCommand
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = _
    "SELECT distinguishedName FROM '" & strLDAPDomain & _ 
     "'WHERE objectCategory='user'AND sAMAccountName='" & strUser & "'"
Set objRecordSet = objCommand.Execute

On Error Resume Next 
'objRecordSet.MoveFirst
Do Until objRecordSet.EOF
    strDN = objRecordSet.Fields("distinguishedName").Value
    arrPath = Split(strDN, ",")
    counter = 0
    For Each Path In arrPath
    	strUserDN = strUserDN & "," & arrPath(counter + 1)
    counter = counter + 1
    Next 
    objRecordSet.MoveNext
    strUserDN = Mid(strUserDN,2)
Loop
	GetUserLDAPOU = strUserDN
End Function 

Function GetDistinguishedName(strUserName)

    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand = CreateObject("ADODB.Command")
    objConnection.Provider = ("ADsDSOObject")
    objConnection.Open "Active Directory Provider"
    objCommand.ActiveConnection = objConnection
    objCommand.CommandText = "SELECT distinguishedName FROM " & _
                             "'LDAP://" & strDomain & "' " & _
                             "WHERE samAccountName = '" & strUserName & "'"
    objCommand.Properties("SearchScope") = ADS_SCOPE_SUBTREE
    Set objRecordSet = objCommand.Execute
    If Not objRecordSet.EOF Then
        GetDistinguishedName = objRecordSet.Fields.Item("distinguishedName").Value
    End If
    objConnection.Close
End Function

Private Sub GetOUPrinters(strUserOU,strUserName)
'WScript.Echo "Getting Printers"
'WScript.Echo "User:   " & strUserName
'WScript.Echo "UserOU: " & strUserOU
' Create disctionary object to store found printers 
Dim objDictPrnts: Set objDictPrnts = CreateObject("Scripting.Dictionary")
objDictPrnts.CompareMode = vbTextCompare

Dim objConnection, objCommand
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = "Select printerName, serverName from " _     
    & " 'LDAP://" & strUserOU & "'  where objectClass='printQueue'"  

Dim objRecordSet
Set objRecordSet = objCommand.Execute

' Add printers to dictionary.
Do Until objRecordSet.EOF
	objDictPrnts.Add "\\" & objRecordSet.Fields("serverName").Value &_
		"\" & objRecordSet.Fields("printerName").Value, _
		UCase(objRecordSet.Fields("printerName").Value)
'		WScript.Echo "Found Printer: " & objRecordSet.Fields("printerName").Value
    objRecordSet.MoveNext
Loop
	
    ' loop through printer connections
	Dim WSHPrinters, LOOP_COUNTER
	Set WSHPrinters = WSHNetwork.EnumPrinterConnections
	For LOOP_COUNTER = 0 To WSHPrinters.Count - 1 Step 2
	    Dim PrinterPath
	    PrinterPath = WSHPrinters.Item(LOOP_COUNTER +1)
	    
	    If objDictPrnts.Exists(PrinterPath) Then 
'	    WScript.Echo "Printer already Exists, removing from connect to list.: " &_
'	    vbCrLf & PrinterPath & vbCrLf
	    End If 

	'     if the current path exist in our dictionary remove it
	    If objDictPrnts.Exists(PrinterPath) Then 
	    objDictPrnts.Remove PrinterPath
	    End If 
	Next
	
	' loop through the path's that were not found and add them
'	ReDim PrinterPath()
	For Each PrinterPath In objDictPrnts.Keys
'		WScript.Echo "Connecting to printer: " & PrinterPath
	    WSHNetwork.AddWindowsPrinterConnection PrinterPath
	Next
	

' Set default Printer

'Dim objRecordSet
Set objRecordSet = objCommand.Execute

objRecordSet.MoveFirst
Do Until objRecordSet.EOF
	objDictPrnts.Add UCase(objRecordSet.Fields("printerName").Value),"\\" &_
	 objRecordSet.Fields("serverName").Value &_
		"\" & objRecordSet.Fields("printerName").Value
		
'		WScript.Echo "Found Printer: " &_
'			 objRecordSet.Fields("printerName").Value
    objRecordSet.MoveNext
Loop

Const E_ADS_PROPERTY_NOT_FOUND  = &h8000500D
 
Dim objUser
Set objUser = GetObject ("LDAP://" &_
 GetDistinguishedName(strUserName))

'WScript.Echo "User: " & GetDistinguishedName(strUserName)

Dim intPrimaryGroupID, arrMemberOf, strCounter
intPrimaryGroupID = objUser.Get("primaryGroupID")
arrMemberOf = objUser.GetEx("memberOf")
If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then
'    WScript.Echo "The memberOf attribute is not set."
Else
	Dim Group, arrGroup, arrGroupName, arrGrpPrefix, strError
		strCounter = 0 ' Initialize counter
    For Each Group in arrMemberOf
    	arrGroup = Split(group,",")
    	arrGroupName = Split(arrGroup(0),"=")
    	arrGrpPrefix = Split(arrGroupName(1),"-")
        If arrGrpPrefix(0) <> UCase("ptr") Then 
'        	WScript.Echo arrGroupName(1) &_
'        	 " is Not a Printer Security Group."
        Else 
	        If strCounter > 0 Then 
			MsgBox "You are a Member of more that one Printer Group!!" & vbCrLf &_
					"Your default printer cannot be properly determined." & vbCrLf &_
					 vbCrLf & "Please call your Administrator." 
			Exit For ' Causes For...Next loop to end
			Else 
	        strCounter = strCounter + 1 'Increment counter for next loop
'	        MsgBox "Setting default printer to " &_
'			 objDictPrnts.Item(Mid(arrGroupName(1),5))
			wshnetwork.SetDefaultPrinter(objDictPrnts.Item(Mid(arrGroupName(1),5)))
			End If 
		End If 
    Next
End If

End Sub  

'Automatically find the domain name
Const ADS_SCOPE_SUBTREE = 2
Dim objDomain, objLDAPDomain, strDomain, strLDAPDomain
Set objDomain = getObject("LDAP://rootDse")
strDomain = objDomain.Get("dnsHostName")
strLDAPDomain = "LDAP://" & objDomain.Get("defaultNamingContext")
Set objLDAPDomain = GetObject(strLDAPDomain)

Dim WshNetwork, strUserName
Set WshNetwork = WScript.CreateObject("WScript.Network")
strUserName = WshNetwork.UserName

Dim strUserLDAPOU
strUserLDAPOU = GetUserLDAPOU(strUserName)
'WScript.Echo "User: " & GetDistinguishedName(strUserName)
'WScript.Echo "LDAP PATH: " & strUserLDAPOU

GetOUPrinters strUserLDAPOU, strUserName

As you can see I decided to eliminate the section to adapt to a non domain environment.

Thanks
John Fuhrman
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top