I have a list of users with full name in an excel file. I would like to automatically get their department based on their fullname by getting it from the AD.
My sheet Tabelle1 has a list of 700 plus users. In this case, I need it to be done automatically to save time.
Basically, I want to look in AD based on their full name. If their fullname matched in AD users, then in column 7, it will place the department.
I found a code but I am not sure on how I can continue:
Sub LoadUserInfo()
Dim x, objConnection, objCommand, objRecordSet, oUser, skip, disa
Dim sht As Worksheet
Dim Tabelle1 As Worksheet
' get domain
Dim oRoot
Set oRoot = GetObject("LDAP://rootDSE")
Dim sDomain
sDomain = oRoot.Get("defaultNamingContext")
Dim strLDAP
strLDAP = "LDAP://" & sDomain
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") = 100
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.CommandText = "SELECT adsPath FROM '" & strLDAP & "' WHERE objectCategory='person'AND objectClass='user'"
Set objRecordSet = objCommand.Execute
x = 2
Set sht = ThisWorkbook.Worksheets("Tabelle1")
With sht
Do Until objRecordSet.EOF
Set oUser = GetObject(objRecordSet.Fields("aDSPath"))
skip = oUser.sAMAccountName
disa = oUser.AccountDisabled
If skip = .Cells(x, 5).Value Then
.Cells(x, 7) = oUser.Department
DoEvents
objRecordSet.MoveNext
Else
DoEvents
x = x + 1
objRecordSet.MoveNext
End If
Loop
End With
End Sub
You can simply use filter in the query to get records for the matching user name.
Sub test()
MsgBox GetDepartment("Stark", "Tony")
End Sub
Function GetDepartment(strLastName As String, strFirstName As String) As String
Dim objRoot As Object
Dim strDomain As String
Dim objConn As Object
Dim objComm As Object
Dim objRecordset As Object
Dim sFilter As String
Dim sAttribs As String
Dim sDepth As String
Dim sBase As String
Dim sQuery As String
Set objRoot = GetObject("LDAP://RootDSE")
strDomain = objRoot.Get("DefaultNamingContext")
Set objConn = CreateObject("ADODB.Connection")
Set objComm = CreateObject("ADODB.Command")
strLastName = Replace(strLastName, Space(1), "")
strFirstName = Replace(strFirstName, Space(1), "")
sFilter = "(&(objectClass=person)(objectCategory=user)(givenName=" & strFirstName & ")" & "(sn=" & strLastName & "*)" & ")"
sAttribs = "department,sAMAccountName,givenName,sn"
sDepth = "SubTree"
sBase = "<LDAP://" & strDomain & ">"
sQuery = sBase & ";" & sFilter & ";" & sAttribs & ";" & sDepth
objConn.Open "Data Source=Active Directory Provider;Provider=ADsDSOObject"
Set objComm.ActiveConnection = objConn
objComm.Properties("Page Size") = 40000
objComm.CommandText = sQuery
Set objRecordset = objComm.Execute
Do Until objRecordset.EOF
GetDepartment = objRecordset("department")
Exit Function
objRecordset.MoveNext
Loop
End Function
Related
I have an Excel tool for doing actuarial calculations on data from SQL. The tool imports the table from SQL to my Excel book then does some calculations on the data set.
I want to take the table from SQL (I use CopyFromRecordSet to paste into my spreadsheet) and rather insert that table into an Access db.
Dim acc As Object
Dim TblName As String, DBName As String, scn As String
Set acc = CreateObject("Access.Application")
Set rs = New ADODB.Recordset
scn = ThisWorkbook.Worksheets("AXIS Tables").Range("A3").Value
DBName = ThisWorkbook.Worksheets("AXIS Tables").Range("B3").Value
Call CreateConnectionSQL.CreateConnectionSQL
acc.OpenCurrentDatabase ActiveWorkbook.Path & "\" & scn & "\Input.accdb"
rs.ActiveConnection = cn
rs.CursorType = adOpenForwardOnly
rs.LockType = adLockReadOnly
rs.Source = "SELECT * FROM" DBName
rs.Open
TblName = "SAM"
Call DoCmd.TransferDatabase(TransferType:=acImport, _
databaseName:=rs, _
ObjectType:=acTable, _
Source:=rs.Fields, _
Destination:=acc)
rs.Close
Call CreateConnectionSQL.CloseConnectionACC
acc.CloseCurrentDatabase
acc.Quit
Set acc = Nothing
I tried a plethora of methods, I spent dozens of hours googling. I assume that RecordSet is a virtual database in Excel where the data is stored. I want to dump that data into a new table in Access.
Create a sheet called AXIS in your workbook to hold the query results before importing into Access.
Option Explicit
Sub CopyToAccess()
Const TABLENAME As String = "AXIS"
Const SHEETNAME As String = "AXIS" ' create this sheet
Const SQL As String = "SELECT * FROM TABLE1"
Dim acc As Object, cn As ADODB.Connection, rs As ADODB.Recordset
Dim rng As Range, ws As Worksheet
Dim sPath As String, sAddr As String, n As Long, i As Integer
Dim scn As String, dbname As String, dbpath As String
sPath = ThisWorkbook.Path
With ThisWorkbook.Worksheets("AXIS Tables")
scn = .Range("A3").Value
dbname = .Range("B3").Value
End With
dbpath = sPath & "\" & scn & "\" & dbname
' connect and query sql database
Set cn = CreateConnectionSQL
Set rs = New ADODB.Recordset
rs.ActiveConnection = cn
rs.CursorType = adOpenForwardOnly
rs.LockType = adLockReadOnly
rs.Source = SQL
rs.Open
' clear sheet
Set ws = ThisWorkbook.Worksheets(SHEETNAME)
ws.Cells.Clear
' set field names as header
For i = 1 To rs.Fields.Count
ws.Cells(1, i) = rs(i - 1).Name
Next
' copy record set to sheet
ws.Range("A2").CopyFromRecordset rs
Set rng = ws.Range("A1").CurrentRegion
n = rng.Rows.Count - 1
sAddr = ws.Name & "!" & rng.AddressLocal
sAddr = Replace(sAddr, "$", "") ' remove $ from address
MsgBox n & " records imported to " & sAddr, vbInformation
cn.Close
' open ACCESS
Set acc = CreateObject("Access.Application")
acc.OpenCurrentDatabase dbpath
' clear out any existing table
On Error Resume Next
acc.DoCmd.DeleteObject acTable, TABLENAME
On Error GoTo 0
' export sheet into access
acc.DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel9, TABLENAME, _
sPath & "/" & ThisWorkbook.Name, True, sAddr
' finish
acc.CloseCurrentDatabase
acc.Quit
Set acc = Nothing
MsgBox "Export to " & dbpath & " table " & TABLENAME & " complete", vbInformation
End Sub
Function CreateConnectionSQL() As ADODB.Connection
Const SERVER As String = "server"
Const DB As String = "database"
Const UID As String = "user"
Const PWD As String = "password"
Dim sConStr As String
sConStr = "Driver={SQL Server Native Client 11.0};Server=" & SERVER & _
";Database=" & DB & ";Uid=" & UID & ";Pwd=" & PWD & ";"
'Debug.Print sConStr
Set CreateConnectionSQL = CreateObject("ADODB.Connection")
CreateConnectionSQL.Open sConStr
End Function
The below query generates a new excel file with data from sql server every time it was run. But the generated excel file don't have column headers in it, making it difficult to understand which column is what. So I am interested inserting 5 bold column header names like column_header1, column_header2....column_header5 in the first row of the excel and let the data start from the second row
Sub TEXT()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strCon, strSQL As String
Dim MRC As Variant
strCon = "some_string_connection"
MRC = "" & Worksheets("SQL Text").Range("D4").Value & ""
strSQL = MRC 'Sql Query
Sheets("Summary").Select
With ActiveWorkbook.Connections("Connection1").OLEDBConnection
.CommandText = HR
.CommandType = xlCmdSql
End With
ActiveWorkbook.Connections("Connection1").Refresh
Folder = "U:\" 'Path in U drive
Filename = "Filename" & ".xls"
fpath = Folder & Filename
cn.Open strCon
cn.CommandTimeout = 0
rs.ActiveConnection = cn
rs.Open strSQL
Set fs = CreateObject("Scripting.FileSystemObject")
Set A = fs.CreateTextFile(fpath)
A.Write (rs.GetString(adClipString, , , vbCrLf, ""))
rs.Close
cn.Close
Set cn = Nothing
End Sub
You are writing to the Excel file here:
A.Write (rs.GetString(adClipString, , , vbCrLf, ""))
Thus, this is the place, where you should put your headers. Something like this should be ok:
A.Write "column_header1, column_header2, column_header5" & vbCrLf & _
rs.GetString(adClipString, , , vbCrLf, "")
There are two method.
First method.
Use rs.field and variant array.
Dim vR() As Variant
Dim str As String
For i = 0 To Rs.Fields.Count - 1
ReDim Preserve vR(i)
vR(i) = Rs.Fields(i).Name
Next
Second method is add new workbook and write fields and record.
If Not Rs.EOF Then
With Ws
.Range("a4").CurrentRegion.Clear
For i = 0 To Rs.Fields.Count - 1
.Cells(1, i + 1).Value = Rs.Fields(i).Name
Next
.Range("a2").CopyFromRecordset Rs
.Columns.AutoFit
End With
Else
MsgBox "There is no record!", vbCritical
End If
First full code.
Sub TEXT()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strCon, strSQL As String
Dim MRC As Variant
strCon = "some_string_connection"
MRC = "" & Worksheets("SQL Text").Range("D4").Value & ""
strSQL = MRC 'Sql Query
Sheets("Summary").Select
With ActiveWorkbook.Connections("Connection1").OLEDBConnection
.CommandText = HR
.CommandType = xlCmdSql
End With
ActiveWorkbook.Connections("Connection1").Refresh
Folder = "U:\" 'Path in U drive
Filename = "Filename" & ".xls"
fpath = Folder & Filename
cn.Open strCon
cn.CommandTimeout = 0
rs.ActiveConnection = cn
rs.Open strSQL
Dim vR() As Variant
Dim str As String, i As Integer
For i = 0 To rs.Fields.Count - 1
ReDim Preserve vR(i)
vR(i) = rs.Fields(i).Name
Next
Set fs = CreateObject("Scripting.FileSystemObject")
Set A = fs.CreateTextFile(fpath)
str = Join(vR, vbTab) & vbCrLf
A.Write str
A.Write (rs.GetString(adClipString, , , vbCrLf, ""))
rs.Close
cn.Close
Set cn = Nothing
End Sub
Second full code.
Sub TEXT2()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strCon, strSQL As String
Dim MRC As Variant
strCon = "some_string_connection"
MRC = "" & Worksheets("SQL Text").Range("D4").Value & ""
strSQL = MRC 'Sql Query
Sheets("Summary").Select
With ActiveWorkbook.Connections("Connection1").OLEDBConnection
.CommandText = HR
.CommandType = xlCmdSql
End With
ActiveWorkbook.Connections("Connection1").Refresh
Folder = "U:\" 'Path in U drive
Filename = "Filename" & ".xls"
fpath = Folder & Filename
cn.Open strCon
cn.CommandTimeout = 0
rs.ActiveConnection = cn
rs.Open strSQL
Dim WB As Workbook, Ws As Worksheet
Dim i As Integer
Set WB = Workbooks.Add(Template:=xlWorksheet)
Set Ws = ActiveSheet
If Not rs.EOF Then
With Ws
For i = 0 To rs.Fields.Count - 1
.Cells(1, i + 1).Value = rs.Fields(i).Name
Next
.Range("a2").CopyFromRecordset rs
.Columns.AutoFit
End With
Else
MsgBox "There is no record!", vbCritical
End If
WB.SaveAs fpath
WB.Close (0)
rs.Close
cn.Close
Set cn = Nothing
End Sub
I have a program, that works, I just feel that it is running slower than it should and I feel that it is a bit more unstable than it should be. I am looking for tips on writing "better" code and making my program more stable.
I am looking to better this part of my code for now:
Private Sub Worksheet_Activate()
Application.ScreenUpdating = False
'Removes shapes already there that will be updated by the getWeather function
For Each delShape In Shapes
If delShape.Type = msoAutoShape Then delShape.Delete
Next delShape
'Calls a function to get weather data from a web service
Call getWeather("", "Area1")
Call getWeather("", "Area2")
Call getWeather("", "Area3")
'Starting to implement the first connection to a SQL Access database.
Dim cn As Object
Dim rs As Object
'Set cn and sqlConnect as ADODB-objects. Set rs as recordset
Set cn = CreateObject("ADODB.Connection")
Set sqlConnect = New ADODB.Connection
Set rs = CreateObject("ADODB.RecordSet")
'Set sqlConnect as connection string
sqlConnect.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\databases\database.accdb;Persist Security Info=False;"
'Open connection string via connection object
cn.Open sqlConnect
'Set rs.Activeconnection to cn
rs.ActiveConnection = cn
'Get a username from the application to be used further down
Brukernavn = Application.userName
'This part of the code re-arranges the date format from american to european
StartDate = Date
EndDate = Date - 7
midStartDate = Split(StartDate, ".")
midEndDate = Split(EndDate, ".")
StartDate2 = "" & midStartDate(1) & "/" & midStartDate(0) & "/" & midStartDate(2) & ""
EndDate2 = "" & midEndDate(1) & "/" & midEndDate(0) & "/" & midEndDate(2) & ""
'SQL statement to get data from the access database
rs.Open "SELECT [RefNr], [Registrert Av],[Nettstasjon], [Meldt Dato] , [Bestilling], [Sekundærstasjon], [Avgang], [Hovedkomponent], [HovedÅrsak], [Status Bestilling] FROM [tblDatabase]" & _
"WHERE [Registrert Av] = '" & Brukernavn & "' AND [Loggtype] <> 'Beskjed' AND [Meldt Dato] BETWEEN #" & StartDate2 & "# AND # " & EndDate2 & "#" & _
"ORDER BY [Meldt Dato] DESC;", _
cn, adOpenStatic
'Start to insert data from access database into a list
Dim i As Integer
Dim u As Integer
If Not rs.EOF Then
rs.MoveFirst
End If
i = 0
With lst_SisteFeil
.Clear
Do
If Not rs.EOF Then
.AddItem
If Not IsNull(rs!refnr) Then
.List(i, 0) = rs![refnr]
End If
If IsDate(rs![Meldt Dato]) Then
.List(i, 1) = Format(rs![Meldt Dato], "dd/mm/yy")
End If
.List(i, 4) = rs![nettstasjon]
If Not IsNull(rs![Sekundærstasjon]) Then
.List(i, 2) = rs![Sekundærstasjon]
End If
If Not IsNull(rs![Avgang]) Then
.List(i, 3) = rs![Avgang]
End If
If Not IsNull(rs![Hovedkomponent]) Then
.List(i, 5) = rs![Hovedkomponent]
End If
If Not IsNull(rs![HovedÅrsak]) Then
.List(i, 6) = rs![HovedÅrsak]
End If
If Not IsNull(rs![Status Bestilling]) Then
.List(i, 7) = rs![Status Bestilling]
End If
If Not IsNull(rs![bestilling]) Then
.List(i, 8) = rs![bestilling]
End If
i = i + 1
rs.MoveNext
Else
GoTo endOfFile
End If
Loop Until rs.EOF
End With
endOfFile:
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
'Starts to connect to SQL access database again to get different set of data. This must be possible to make more efficient?
Dim cn2 As Object
Dim rs2 As Object
'Set cn and sqlConnect as ADODB-objects. Set rs as recordset
Set cn2 = CreateObject("ADODB.Connection")
Set sqlConnect2 = New ADODB.Connection
Set rs2 = CreateObject("ADODB.RecordSet")
'Set sqlConnect as connection string
sqlConnect2.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\databases\database.accdb;Persist Security Info=False;"
'Open connection string via connection object
cn2.Open sqlConnect
'Set rs.Activeconnection to cn
rs2.ActiveConnection = cn2
'Second SQL statement
rs2.Open "SELECT [RefNr], [Registrert Av],[Nettstasjon], [Meldt Dato] , [Bestilling], [Sekundærstasjon], [Avgang], [Hovedkomponent], [HovedÅrsak], [Status Bestilling] FROM [tblDatabase]" & _
"WHERE [Registrert Av] <> '" & Brukernavn & "' AND [Meldt Dato] BETWEEN #" & StartDate2 & "# AND # " & EndDate2 & "#" & _
"ORDER BY [Meldt Dato] DESC;", _
cn2, adOpenStatic
'Inserting into second list
If Not rs2.EOF Then
rs2.MoveFirst
End If
u = 0
With lst_AlleFeil
.Clear
Do
If Not rs2.EOF Then
.AddItem
If Not IsNull(rs2!refnr) Then
.List(u, 0) = rs2![refnr]
End If
If IsDate(rs2![Meldt Dato]) Then
.List(u, 1) = Format(rs2![Meldt Dato], "dd/mm/yy")
End If
.List(u, 4) = rs2![nettstasjon]
If Not IsNull(rs2![Sekundærstasjon]) Then
.List(u, 2) = rs2![Sekundærstasjon]
End If
If Not IsNull(rs2![Avgang]) Then
.List(u, 3) = rs2![Avgang]
End If
If Not IsNull(rs2![Hovedkomponent]) Then
.List(u, 5) = rs2![Hovedkomponent]
End If
If Not IsNull(rs2![HovedÅrsak]) Then
.List(u, 6) = rs2![HovedÅrsak]
End If
If Not IsNull(rs2![Status Bestilling]) Then
.List(u, 7) = rs2![Status Bestilling]
End If
If Not IsNull(rs2![bestilling]) Then
.List(u, 8) = rs2![bestilling]
End If
u = u + 1
rs2.MoveNext
Else
GoTo endOfFile2
End If
Loop Until rs2.EOF
End With
endOfFile2:
rs2.Close
cn2.Close
Set rs2 = Nothing
Set cn2 = Nothing
'Starting to connect to the database for the third time
Dim cn3 As Object
Dim rs3 As Object
'Set cn and sqlConnect as ADODB-objects. Set rs as recordset
Set cn3 = CreateObject("ADODB.Connection")
Set sqlConnect3 = New ADODB.Connection
Set rs3 = CreateObject("ADODB.RecordSet")
'Set sqlConnect as connection string
sqlConnect3.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\databases\database.accdb;Persist Security Info=False;"
'Open connection string via connection object
cn3.Open sqlConnect
'Set rs.Activeconnection to cn
rs3.ActiveConnection = cn3
'third sql statement
rs3.Open "SELECT [RefNr], [Registrert Av],[Nettstasjon], [Meldt Dato], [Sekundærstasjon], [Avgang], [Beskrivelse], [Til Dato] FROM [tblDatabase]" & _
"WHERE [Loggtype] = 'Beskjed' AND [Meldt Dato] >= DateAdd('d',-30,Date())" & _
"ORDER BY [Meldt Dato] DESC;", _
cn3, adOpenStatic
'Inserting data in to third list
If Not rs3.EOF Then
rs3.MoveFirst
End If
j = 0
With lst_beskjeder
.Clear
Do
If Not rs3.EOF Then
.AddItem
If Not IsNull(rs3!refnr) Then
.List(j, 0) = rs3![refnr]
End If
If IsDate(rs3![Meldt Dato]) Then
.List(j, 1) = Format(rs3![Meldt Dato], "dd/mm/yy")
End If
.List(j, 4) = rs3![nettstasjon]
If Not IsNull(rs3![Sekundærstasjon]) Then
.List(j, 2) = rs3![Sekundærstasjon]
End If
If Not IsNull(rs3![Avgang]) Then
.List(j, 3) = rs3![Avgang]
End If
If Not IsNull(rs3![beskrivelse]) Then
.List(j, 5) = rs3![beskrivelse]
End If
j = j + 1
rs3.MoveNext
Else
GoTo endOfFile3
End If
Loop Until rs3.EOF
End With
endOfFile3:
rs3.Close
cn3.Close
Set rs3 = Nothing
Set cn3 = Nothing
End Sub
Here is the function I have used to get weather data.
Public Sub getWeather(APIurl As String, sted As String)
Dim i As Integer
i = 0
Dim omraade As String
omraade = ""
omraade = sted
If sted = "Area1" Then
i = 4
ElseIf sted = "Area2" Then
i = 6
ElseIf sted = "Area3" Then
i = 8
End If
Dim WS As Worksheet: Set WS = ActiveSheet
Dim delShape As Shape
Dim city As String
Dim Req As New XMLHTTP
Req.Open "GET", "" & APIurl & "", False
Req.Send
Dim Resp As New DOMDocument
Resp.LoadXML Req.responseText
Dim Weather As IXMLDOMNode
Dim wShape As Shape
Dim thisCell As Range
For Each Weather In Resp.getElementsByTagName("current_condition")
Set thisCell = WS.Range(Cells(2, i), Cells(2, i))
Set wShape = WS.Shapes.AddShape(msoShapeRectangle, thisCell.Left, thisCell.Top, thisCell.Width, thisCell.Height)
wShape.Fill.UserPicture Weather.ChildNodes(4).Text 'img
Cells(3, i).Value = "" & Weather.ChildNodes(7).Text * 0.28 & " m/s" 'windspeedkmph
Cells(4, i).Value = Weather.ChildNodes(9).Text 'Direction
Cells(5, i).Value = Weather.ChildNodes(1).Text & " C" 'observation time
Next Weather
End Sub
Feel free to point out any poor coding and tips on how to improve it. I am currently using the Worksheet Activate sub to activate changes in the tables and get new data, but I suspect that is not the best solution. I am just not sure how else to do it seeing as I want it to be as "automatic" as possible, and use as few buttons to refresh as I can.
Thank you for all the help.
-Thomas
Some tips, but none will affect performance, only help make your code more succinct.
1.
rs.Open "SELECT ..."
If Not rs.EOF Then
rs.MoveFirst
End If
.MoveFirst is unnecessary. After opening a recordset, you are always on the first record, if there are records.
When building complex SQL in VBA, have a look at How to debug dynamic SQL in VBA.
2.
Don't do a Do ... Until loop for recordsets:
Do
If Not rs.EOF Then
' do stuff for each record
' ...
rs.MoveNext
Else
GoTo endOfFile
End If
Loop Until rs.EOF
endOfFile:
rs.Close
Instead use Do While Not rs.EOF :
Do While Not rs.EOF
' do stuff for each record
' ...
rs.MoveNext
Loop
rs.Close
For an empty rs, the loop will not be entered. You don't need the If/Else and the Goto.
I want to use the code below to quickly add all network printers from my domain into an Excel spreadsheet to use for my records. The code works fine except for the fact that the PortName (IP Address) is not displayed (cells are blank).
Could someone look over my code bellow and point out why is it not working for the PortName field..
Private Sub GetAllPrintersFromAD()
Const ADS_SCOPE_SUBTREE = 2
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"
Set objCommand.ActiveConnection = objConnection
objCommand.CommandText = _
"SELECT distinguishedName,portName,location,servername FROM 'LDAP://" & strDomain & "' WHERE objectClass='printQueue'"
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
Set objRecordSet = objCommand.Execute
ActiveSheet.Range("A2").CopyFromRecordset objRecordSet
objRecordSet.Close
objConnection.Close
End Sub
1. Problem: Data types
Your code is not working for a few reasons:
The portName field is stored as DataTypeEnum 12 (Automation Variant: DBTYPE_VARIANT)
DBTYPE_VARIANT is unsupported for usage with ADO (source).
CopyFromRecordset has known data type issues (source)
Note: all other fields are stored as DataTypeEnum 202 (null-terminated Unicode character string).
2. Solution
You will need to iterate through the records and import the portName to a string, then write that string to the correct cell. This ensures that VBA handles the conversion, rather than CopyFromRecordset attempting to determine the (in)correct data type. If you would like to keep your original code with limited modification, I've provided a rudimentary example below.
I was able to duplicate your issue on my machine; the below modified code works as intended and includes the IP.
Private Sub GetAllPrintersFromAD()
Const ADS_SCOPE_SUBTREE = 2
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"
Set objCommand.ActiveConnection = objConnection
objCommand.CommandText = _
"SELECT distinguishedName,portName,location,servername FROM 'LDAP://" & strDomain & "' WHERE objectClass='printQueue'"
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
Set objRecordSet = objCommand.Execute
ActiveSheet.Range("A2").CopyFromRecordset objRecordSet
'Copy over the portName field properly
objRecordSet.MoveFirst
i = 2
Do Until objRecordSet.EOF
strportname = vbNullString
On Error Resume Next
strportname = objRecordSet.Fields("portName")
Err.Clear
On Error GoTo 0
ActiveSheet.Range("B" & i).Value2 = strportname
i = i + 1
objRecordSet.MoveNext
Loop
objRecordSet.Close
objConnection.Close
End Sub
I use this old script to write same data to .csv file. Works good for me. Give it a try.
'Query AD for Printer details form printer name
ReportLog = "OutPut.csv"
Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim objOut : Set objOut = objFSO.CreateTextFile(ReportLog)
objOut.WriteLine "Dis Name;printer name;port name;Location;Server name;"
Set objRootDSE = GetObject("LDAP://rootDSE")
strADsPath = "<LDAP://" & objRootDSE.Get("defaultNamingContext") & ">"
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOOBject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
strFilter = "(&(objectClass=printQueue))"
strAttributes = "distinguishedName,printShareName,portName,location,servername"
strQuery = strADsPath & ";" & strFilter & ";" & strAttributes & ";subtree"
objCommand.CommandText = strQuery
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Timeout") = 300
objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute
'objRecordSet.MoveFirst
Do Until objRecordSet.EOF
strDN = "<ERROR>"
strPSN = "<ERROR>"
strPN = "<ERROR>"
strLO = "<ERROR>"
strSN = "<ERROR>"
On Error Resume Next
strDN = objRecordSet.Fields("distinguishedName")
strPSN = objRecordSet.Fields("printShareName")
strPN = objRecordSet.Fields("portName")
strLO = objRecordSet.Fields("location")
strSN = objRecordSet.Fields("serverName")
Err.Clear
On Error GoTo 0
objOut.WriteLine """" & strDN & """;""" & Join(strPSN, ";") & """;""" & Join(strPN, ";") & """;""" & strLO & """;""" & strSN & """"
objRecordSet.MoveNext
Loop
'Next
objOut.Close
WScript.Echo "Finished"
The output is:
I'm trying to create a dropdown that upon changing the selection from the list of options will run a query that will insert the query results into the page. Here's what I have thus far:
Sub DropDown1_Change()
Dim dbConnect As String
Dim leagueCode As String
Dim leagueList As Range
Dim leagueVal As String
Dim TeamData As String
Set leagueList = Worksheets("Menu Choices").Range("A5:A10")
Set leagueVal = Worksheets("Menu Choices").Cell("B1").Value
leagueCode = Application.WorksheetFunction.Index(leagueList, leagueVal)
TeamData = "SELECT DISTINCT(Teams.teamID), name FROM Teams WHERE lgID = '" & leagueCode & "' & ORDER BY name ASC"
With Worksheets("Menu Choices").QueryTables.Add(Connection:=dbConnect, Destination:=Worksheets("Menu Choices").Range("D5"))
.CommandText = TeamData
.Name = "Team List Query"
.Refresh BackgroundQuery:=False
End With
End Sub
Anywho have any suggestions to get it working? Thanks in advance!
I was able to resolve the issue using similar code to the following:
Sub createTeamList()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim SQL As String
Dim inc As Integer
Dim topCell As Range
Dim leagueID As String
Dim leagueList As Range
Dim leagueChoice As Range
Set leagueList = Worksheets("Menu Choices").Range("A4:A9")
Set leagueChoice = Worksheets("Menu Choices").Range("B1")
leagueID = Application.WorksheetFunction.Index(leagueList, leagueChoice)
Set topCell = Worksheets("Menu Choices").Range("D4")
With topCell
Range(.Offset(1, 0), .Offset(0, 1).End(xlDown)).ClearContents
End With
With cn
.ConnectionString = "Data Source=" & ThisWorkbook.Path & "\lahman_57.mdb"
.Provider = "Microsoft Jet 4.0 OLE DB Provider"
.Open
End With
inc = 0
SQL = "SELECT teamID, name " _
& "FROM Teams " _
& "WHERE lgID = '" & leagueID & "' " _
& "GROUP BY teamID, name " _
& "ORDER BY name "
rs.Open SQL, cn
With rs
Do Until .EOF
topCell.Offset(inc, 0) = .Fields("teamID")
topCell.Offset(inc, 1) = .Fields("name")
inc = inc + 1
.MoveNext
Loop
End With
rs.Close
cn.Close
End Sub