| T O P I C R E V I E W |
| netmarcos |
Posted - 05/27/2003 : 10:47:27 AM There has been a lot of discussion surrounding this issue. The script below is the result of the combined effort of several people.
'*******************************************************************
' ADWorkstationLastLogon.vbs
' VBScript to determine when each computer in the domain
' lastlogged on.
'
' ------------------------------------------------------------------
' Copyright (c) 2002 Richard L. Mueller
' Version 1.2 - January 23, 2003
' Modified - March 4, 2003 Kevin Buley
' - Added output lines to show that the script is processing
' (DC name, # x of y)
' Modified March 5, 2003 Mark M. Webster
' - Modified output to be fixed width for import
' - Made several structural modifications and
' additional comments
'
' Because the LastLogon attribute is not replicated, every Domain Controller
' in the domain must be queried to find the latest LastLogon date for each
' computer. The lastest date found is kept in a dictionary object. The
' program first uses ADO to search the domain for all Domain Controllers.
' The AdsPath of each Domain Controller is saved in an array. Then, for each
' Domain Controller, ADO is used to search the copy of Active Directory on
' that Domain Controller for all computer objects and return the LastLogon
' attribute. The LastLogon attribute is a 64-bit number representing the
' number of 100 nanosecond intervals since 12:00 am January 1, 1601. This
' value is converted to a date. The last logon date is in UTC (Coordinated
' Univeral Time). It must be adjusted by the Time Zone bias in the machine
' registry to convert to local time.
'
' You have a royalty-free right to use, modify, reproduce, and distribute
' this script file in any way you find useful, provided that you agree
' that the copyright owner above has no warranty, obligations, or liability
' for such use.
'************************************************************************************************
Option Explicit
Const ForAppending = 8
Dim k
Dim sDCs() 'Dynamic array to hold the path for all DCs
Dim BiasKey 'Active Time Bias from Registry
Dim Bias 'Time Bias
Dim strAdsPath 'Machine account DN
Dim strDate 'Date output string
Dim sDate 'Local machine current date
Dim lngDate 'LastLogon date
Dim strTime 'Local machine current time
Dim strLDate 'Local machine current date and time
Dim objList 'Dictionary object to track latest LastLogon for each computer
Dim objRoot 'RootDSE object
Dim strConfig 'Configuration Naming Context
Dim objDC 'Domain Controller
Dim strDNSDomain 'Default nameing context
Dim strComputer 'Computer object Name
Dim objConnection 'ADO conection
Dim objCommand 'ADO command
Dim objRecordSet 'Object to hold attributes from AD
Dim oWshShell 'Windows shell script
Dim objFSO 'File System object
Dim objFile 'File object used to open text file for output
Dim objLastLogon 'Last Logon Long Integer attribute
Dim strFilePath 'Path to current directory
Set oWshShell = CreateObject("Wscript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
strFilePath = objFSO.GetAbsolutePathName(".")
sDate = Date
strTime = Now
StrLDate = DatePart("m",sDate) & "." & DatePart("d",sDate) & "." & Hour(strTime) & "." & Minute(strTime)
Set objFile = objFSO.OpenTextFile (strFilePath & "\DomainLastLogon." & strLDate & ".log",ForAppending,True)
'* Use a dictionary object to track latest LastLogon for each computer.
Set objList = CreateObject("Scripting.Dictionary")
objList.CompareMode = vbTextCompare
'* Obtain local Time Zone bias from machine registry.
BiasKey = oWshShell.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias")
If UCase(TypeName(BiasKey)) = "LONG" Then
Bias = BiasKey
ElseIf UCase(TypeName(BiasKey)) = "VARIANT()" Then
Bias = 0
For k = 0 To UBound(BiasKey)
Bias = Bias + (BiasKey(k) * 256^k)
Next
End If
'* Determine configuration context and DNS domain from RootDSE object.
Set objRoot = GetObject("LDAP://RootDSE")
strConfig = objRoot.Get("ConfigurationNamingContext")
strDNSDomain = objRoot.Get("DefaultNamingContext")
'* Use ADO to search Active Directory for ObjectClass nTDSDSA.
'* This will identify all Domain Controllers.
Set objCommand = CreateObject("ADODB.Command")
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open = "Active Directory Provider"
objCommand.ActiveConnection = objConnection
objCommand.CommandText = "<LDAP://" & strConfig & ">;(ObjectClass=nTDSDSA);AdsPath;subtree"
objCommand.Properties("Page Size") = 100
objCommand.Properties("Timeout") = 30
objCommand.Properties("Searchscope") = 2
objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute
'* Enumerate parent objects of class nTDSDSA. Save Domain Controller
'* AdsPaths in dynamic array sDCs.
k = 0
Do Until objRecordSet.EOF
Set objDC = GetObject(GetObject(objRecordSet.Fields("AdsPath")).Parent)
ReDim Preserve sDCs(k)
sDCs(k) = objDC.DNSHostName
k = k + 1
objRecordSet.MoveNext
Loop
'* Retrieve LastLogon attribute for each computer on each Domain Controller.
For k = 0 To Ubound(sDCs)
oWshShell.Popup "Checking 'lastlogon' at domain controller " & sDCs(k) & ". Controller " & k & " of " & Ubound(sDCs),2,"Checking",64
'*******************************************************************
'* Modify this line for the base of your search path depending on your own AD implementation
'*******************************************************************
objCommand.CommandText = "<LDAP://" & sDCs(k) & "/OU=Workstations," & strDNSDomain & ">;(ObjectCategory=computer);Name,LastLogon;subtree"
On Error Resume Next
Err.Clear
Set objRecordSet = objCommand.Execute
If Err.Number <> 0 Then
Err.Clear
On Error GoTo 0
oWshShell.Popup "Domain Controller not available: " & sDCs(k),2,"Notice",48
Else
On Error GoTo 0
Do Until objRecordSet.EOF
strAdsPath = objRecordSet.Fields("Name")
strDate = objRecordSet.Fields("LastLogon")
On Error Resume Next
Err.Clear
Set lngDate = strDate
If Err.Number <> 0 Then
Err.Clear
strDate = #1/1/1601#
Else
If (lngDate.HighPart = 0) And (lngDate.LowPart = 0 ) Then
strDate = #1/1/1601#
Else
strDate = #1/1/1601# + (((lngDate.HighPart * (2 ^ 32)) + lngDate.LowPart)/600000000 - Bias)/1440
End If
End If
On Error GoTo 0
If objList.Exists(strAdsPath) Then
If strDate > objList(strAdsPath) Then
objList(strAdsPath) = strDate
End If
Else
objList.Add strAdsPath, strDate
End If
objRecordSet.MoveNext
Loop
End If
Next
'* Output latest LastLogon date for each computer.
For Each strComputer In objList
Call VBOut(strComputer,objList(strComputer))
Next
objFile.WriteBlankLines (3)
objFile.Close
oWshShell.Popup "Output file " & strFilePath & "\DomainLastLogon." & strLDate & ".log created." & Chr(13)_
& " Script processing complete.",5,"Notice",64
'* Clean up.
Set objRoot = Nothing
Set objConnection = Nothing
Set objCommand = Nothing
Set objRecordSet = Nothing
Set objDC = Nothing
Set lngDate = Nothing
Set objList = Nothing
Set oWshShell = Nothing
'*******************************************************************
'* Function VBOut
'*
'* Format data and write to output file
'*
'*******************************************************************
Function VBOut(strPC,strTime)
Dim strComputerName 'Formatted computer name output string
Dim strLogonTime 'Formatted Last Logon Time output string
Dim DataOutArray(1) 'This array is used to format the output strings
'* Format computer name string
DataOutArray(0) = strPC
DataOutArray(1) = " "
strComputerName = Join(DataOutArray)
strComputerName = Left (strComputerName, 18)
'* Format Last Logon Time string
DataOutArray(0) = strTime
DataOutArray(1) = " "
strLogonTime = Join(DataOutArray)
strLogonTime = Left (strLogonTime, 24)
'* Write to output file
objFile.WriteLine strComputerName & " " & strLogonTime
End Function 'End of Script
Mark M. Webster
When people fear the government, there is tyranny. When government fears the people, there is liberty -Thomas Paine
|
| 30 L A T E S T R E P L I E S (Newest First) |
| netmarcos |
Posted - 02/27/2007 : 10:27:22 PM Oh my, that is a good one. Unfortunately, that information is not stored in AD, or at least not that correlation. The lastLogon attribute for the computer object just records that last time the machine authenticated to AD, not necessarily when a user last used that machine to log onto the domain. To get the last user logon for an individual machine would require checking the security log on that machine since AD does not track which machine a user was authenticated from.
Anyway, I am glad that folks are still getting some use out of this. |
| tday |
Posted - 02/27/2007 : 6:42:01 PM Awesome script netmarcos! Been searching for something like this all day. Works great for me and I was wondering if there was a way to add one feature? Not only do I want the report of the last date and time of the login of the machine, but could we retrieve the user's name also that was associated with that last login?
This will help solve many issues for us?
Thanks again :-) |
| Maverick07 |
Posted - 08/31/2005 : 03:23:07 AM Hi, the version of the domain controller is 2000. And here is my script... i am not a profi in vbscript :)
I think the function to convert the 64bit integer (lastlogon) to a date is not really good. I get times for example of 01:47:55 at midnight ! And i dont think that anybody logon on a computer at this time *g*
-------------------------------------------------------- Option Explicit On Error Resume Next
Const ForAppending = 8 Const ADS_SCOPE_SUBTREE = 5
'Declarations
Dim BiasKey 'Active Time Bias from Registry Dim Bias 'Time Bias
Dim objConnection 'ADO conection Dim objCommand 'ADO command Dim objRecordSet 'Object to hold attributes from AD Dim oWshShell 'Windows shell script Dim objFSO 'Scripting File System Dim objFile 'Open text file Dim objLastLogon 'Last Logon Long Integer attribute Dim strFilePath 'Path to current directory Dim strComputer 'PC Name Dim strComputerName 'Output computer name string Dim strTimeSTMP 'Modify Time Stamp Attribute Dim strADSPath 'Active Directory container for computer account Dim strLogon 'String to hold interpreted last logon value Dim strLogonTime 'Last Logon Time output string Dim strDate 'Last Logon Date attribute Dim strValidate Dim CNameArray(1) Dim CTimeArray(1) Dim anzahl 'numbers of computers in the AD
Set oWshShell = CreateObject("WScript.Shell") Set objFSO = CreateObject("Scripting.FileSystemObject") strFilePath = objFSO.GetAbsolutePathName(".") Set objFile = objFSO.OpenTextFile (strFilePath & "\PCNAME-n-DATE.log",ForAppending,True)
' Use a dictionary object to track latest LastLogon for each computer Set objList = CreateObject("Scripting.Dictionary") objList.CompareMode = vbtextCompare
Set objConnection = CreateObject("ADODB.Connection") Set objCommand = CreateObject("ADODB.Command")
' Obtain local Time Zone bias from machine registry. BiasKey = oWshShell.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias") If UCase(TypeName(BiasKey)) = "LONG" Then Bias = BiasKey ElseIf UCase(TypeName(BiasKey)) = "VARIANT()" Then Bias = 0 For k = 0 To UBound(BiasKey) Bias = Bias + (BiasKey(k) * 256^k) Next End If
objFile.WriteLine "Output File opened at " & Now objFile.WriteLine "============================================================================="
objConnection.Provider = "ADsDSOObject" objConnection.Open "Active Directory Provider" Set objCommand.ActiveConnection = objConnection
objCommand.CommandText = "Select Name, ADSPath, lastlogon from 'LDAP://dc=domain,dc=com" & " where objectClass='computer'"
objCommand.Properties("Page Size") = 2000 objCommand.Properties("Timeout") = 30 objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute objRecordSet.MoveFirst
Do Until objRecordSet.EOF strComputer = objRecordSet.Fields("Name").Value strADSPath = objRecordSet.Fields("ADSPath").Value set objLastLogon = objRecordSet.Fields("lastlogon").Value
If err.number <> 0 Then strlogon = "Not set" Err.Clear
Else
' Convert the LargeInteger object to a string strLogon = Hex(objLastLogon.HighPart) & Hex(objLastLogon.LowPart)
strDate = #1/1/1601# + (objLastLogon.highpart * 2^32 + objLastLogon.lowpart) /864E9 - Bias / 1440
End If
' Format computer name string
CNameArray(0) = strComputer CNameArray(1) = " " strComputerName = Join(CNameArray) strComputerName = Left (strComputerName, 18)
' Format Last Logon Time string
CTImeArray(0) = strLogon CTimeArray(1) = " " strLogonTime = Join(CTimeArray) strLogonTime = Left (strLogonTime, 18)
' Output in File
objFile.Write "Computername: " & strComputerName & VbCrLf objFile.Write " " & strLogonTime & VbCrLf objFile.Write "last Login: " & strDate & VbCrLf objFile.WriteLine "AD Path: " & strADSPath objFile.WriteLine "----------------------" & VbCrLf
objRecordSet.MoveNext Loop
objFile.WriteLine " End of log file for: " & Now objFile.WriteBlankLines (0) objFile.WriteLine "=============================================================================" objFile.WriteBlankLines (0) objFile.Close |
| netmarcos |
Posted - 08/30/2005 : 11:07:25 AM 2.01.1601 is an intersting result, no doubt. What version are your domain controllers? 2000 or 2003? What modifications (if any) were made to the original script to fit your environment? |
| Maverick07 |
Posted - 08/30/2005 : 09:20:30 AM i have the problem that some computers have the date 2.01.1601 ! Why ? They have a normal lastlogontime in the properties of the ADSI. Can someone help me please ? |
| durhamrobertl |
Posted - 06/30/2005 : 12:26:31 PM It seems the script is more accurate based on last login. dsquery -inactive x -limit 0 seems to be looking at something different than last login to determine inactivity.
What would be the difference in the dsquery for inactive and the script when dsquesry returns far less results than the script does? |
| rick0127 |
Posted - 06/03/2005 : 3:42:44 PM TOPIC_ID=3724 is exactly what I need. Unfortunately I need it in c#. Does anyone have a translation?
rick
|
| netmarcos |
Posted - 06/01/2005 : 07:58:40 AM Perhaps something along these lines' LastLogon.vbs
' VBScript program to determine when each computer in the domain lastlogged
' on.
'
' ----------------------------------------------------------------------
' Copyright (c) 2002 Richard L. Mueller
' Version 1.2 - January 23, 2003
' Modified - March 4, 2003 Kevin Buley
' - Added output lines to show that the script is processing (DC name, # x of y)
' - Modified output to be pipe-delimited "|" for import into spreadsheet
'
' Because the LastLogon attribute is not replicated, every Domain Controller
' in the domain must be queried to find the latest LastLogon date for each
' computer. The lastest date found is kept in a dictionary object. The
' program first uses ADO to search the domain for all Domain Controllers.
' The AdsPath of each Domain Controller is saved in an array. Then, for each
' Domain Controller, ADO is used to search the copy of Active Directory on
' that Domain Controller for all computer objects and return the LastLogon
' attribute. The LastLogon attribute is a 64-bit number representing the
' number of 100 nanosecond intervals since 12:00 am January 1, 1601. This
' value is converted to a date. The last logon date is in UTC (Coordinated
' Univeral Time). It must be adjusted by the Time Zone bias in the machine
' registry to convert to local time.
'
' You have a royalty-free right to use, modify, reproduce, and distribute
' this script file in any way you find useful, provided that you agree
' that the copyright owner above has no warranty, obligations, or liability
' for such use.
Option Explicit
Const ForAppending = 8
Dim k, sDCs()
Dim BiasKey 'Active Time Bias from Registry
Dim Bias 'Time Bias
Dim strAdsPath, strDate, lngDate, nDate
Dim objList 'Dictionary object to track latest LastLogon for each computer
Dim objRoot 'RootDSE object
Dim strConfig 'Configuration Naming Context
Dim objDC 'Domain Controller
Dim strDNSDomain '
Dim strComputer 'Computer object Name
Dim objConnection 'ADO conection
Dim objCommand 'ADO command
Dim objRecordSet 'Object to hold attributes from AD
Dim oWshShell 'Windows shell script
Dim objFSO 'File System object
Dim objFile 'File object used to open text file for output
Dim objLastLogon 'Last Logon Long Integer attribute
Dim strFilePath 'Path to current directory
Set oWshShell = CreateObject("Wscript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
strFilePath = objFSO.GetAbsolutePathName(".")
Set objFile = objFSO.OpenTextFile (strFilePath & "\PCNAME-n-DATE.log",ForAppending,True)
' Use a dictionary object to track latest LastLogon for each computer.
Set objList = CreateObject("Scripting.Dictionary")
objList.CompareMode = vbTextCompare
' Obtain local Time Zone bias from machine registry.
BiasKey = oWshShell.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias")
If UCase(TypeName(BiasKey)) = "LONG" Then
Bias = BiasKey
ElseIf UCase(TypeName(BiasKey)) = "VARIANT()" Then
Bias = 0
For k = 0 To UBound(BiasKey)
Bias = Bias + (BiasKey(k) * 256^k)
Next
End If
' Determine configuration context and DNS domain from RootDSE object.
Set objRoot = GetObject("LDAP://RootDSE")
strConfig = objRoot.Get("ConfigurationNamingContext")
strDNSDomain = objRoot.Get("DefaultNamingContext")
' Use ADO to search Active Directory for ObjectClass nTDSDSA.
' This will identify all Domain Controllers.
Set objCommand = CreateObject("ADODB.Command")
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open = "Active Directory Provider"
objCommand.ActiveConnection = objConnection
objCommand.CommandText = "<LDAP://" & strConfig & ">;(ObjectClass=nTDSDSA);AdsPath;subtree"
objCommand.Properties("Page Size") = 100
objCommand.Properties("Timeout") = 30
objCommand.Properties("Searchscope") = 2
objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute
' Enumerate parent objects of class nTDSDSA. Save Domain Controller
' AdsPaths in dynamic array sDCs.
k = 0
'Do Until objRecordSet.EOF
' Set objDC = GetObject(GetObject(objRecordSet.Fields("AdsPath")).Parent)
' ReDim Preserve sDCs(k)
' sDCs(k) = objDC.DNSHostName
' k = k + 1
' objRecordSet.MoveNext
'Loop
' Retrieve LastLogon attribute for each computer on each Domain Controller.
'For k = 0 To Ubound(sDCs)
' oWshShell.Popup "Checking 'lastlogon' at domain controller " & sDCs(k) & ". Controller " & k & " of " & Ubound(sDCs),2,"Checking",64
' objCommand.CommandText = "<LDAP://" & sDCs(k) & "/OU=Corporate,OU=Workstations," & strDNSDomain & ">;(ObjectCategory=computer);Name,LastLogon;subtree"
' On Error Resume Next
' Err.Clear
' Set objRecordSet = objCommand.Execute
' If Err.Number <> 0 Then
' Err.Clear
' On Error GoTo 0
' oWshShell.Popup "Domain Controller not available: " & sDCs(k),2,"Notice",48
' Else
' On Error GoTo 0
' Do Until objRecordSet.EOF
' strAdsPath = objRecordSet.Fields("Name")
' strDate = objRecordSet.Fields("LastLogon")
' On Error Resume Next
' Err.Clear
' Set lngDate = strDate
' If Err.Number <> 0 Then
' Err.Clear
' nDate = #1/1/1601#
' Else
' If (lngDate.HighPart = 0) And (lngDate.LowPart = 0 ) Then
' nDate = #1/1/1601#
' Else
' nDate = #1/1/1601# + (lngDate.highpart * 2^32 + lngDate.lowpart) / 864E9 - Bias / 1440 '#1/1/1601# + (((lngDate.HighPart * (2 ^ 32)) + lngDate.LowPart)/600000000 - Bias)/1440
' End If
' End If
' On Error GoTo 0
' If objList.Exists(strAdsPath) Then
' If nDate > objList(strAdsPath) Then
' objList(strAdsPath) = nDate
' End If
' Else
' objList.Add strAdsPath, nDate
' End If
' objRecordSet.MoveNext
' Loop
' End If
'Next
Call GetDate(server1.abc3.abc.company.com)
Call GetDate(server2.abc3.abc.company.com)
' Output latest LastLogon date for each computer.
objFile.WriteLine "Output File opened at " & Now
For Each strComputer In objList
Call VBOut(strComputer,objList(strComputer))
Next
objFile.WriteLine " End of log file for: " & Now
objFile.WriteBlankLines (1)
objFile.WriteLine "============================================================================="
objFile.WriteBlankLines (3)
objFile.Close
' Clean up.
Set objRoot = Nothing
Set objConnection = Nothing
Set objCommand = Nothing
Set objRecordSet = Nothing
Set objDC = Nothing
Set lngDate = Nothing
Set objList = Nothing
Set oWshShell = Nothing
'************************************************************************************************
'* Function VBOut
'*
'* Format data and write to output file
'*
'************************************************************************************************
Function VBOut(strPC,strTime)
Dim strComputerName 'Formatted computer name output string
Dim strLogonTime 'Formatted Last Logon Time output string
Dim CNameArray(1) 'This array is used to format the output strings
'Format computer name string
CNameArray(0) = strPC
CNameArray(1) = " "
strComputerName = Join(CNameArray)
strComputerName = Left (strComputerName, 18)
'Format Last Logon Time string
CNameArray(0) = strTime
CNameArray(1) = " "
strLogonTime = Join(CNameArray)
strLogonTime = Left (strLogonTime, 24)
objFile.Write strComputerName
objFile.WriteLine " " & strLogonTime
End Function
Function GetDate(sDC)
objCommand.CommandText = "<LDAP://" & sDC & "/OU=Corporate,OU=Workstations," & strDNSDomain & ">;(ObjectCategory=computer);Name,LastLogon;subtree"
On Error Resume Next
Err.Clear
Set objRecordSet = objCommand.Execute
If Err.Number <> 0 Then
Err.Clear
On Error GoTo 0
oWshShell.Popup "Domain Controller not available: " & sDC,2,"Notice",48
Else
On Error GoTo 0
Do Until objRecordSet.EOF
strAdsPath = objRecordSet.Fields("Name")
strDate = objRecordSet.Fields("LastLogon")
On Error Resume Next
Err.Clear
Set lngDate = strDate
If Err.Number <> 0 Then
Err.Clear
nDate = #1/1/1601#
Else
If (lngDate.HighPart = 0) And (lngDate.LowPart = 0 ) Then
nDate = #1/1/1601#
Else
nDate = #1/1/1601# + (lngDate.highpart * 2^32 + lngDate.lowpart) / 864E9 - Bias / 1440
End If
End If
On Error GoTo 0
If objList.Exists(strAdsPath) Then
If nDate > objList(strAdsPath) Then
objList(strAdsPath) = nDate
End If
Else
objList.Add strAdsPath, nDate
End If
objRecordSet.MoveNext
Loop
End If
End Function |
| AvatarPalin |
Posted - 05/31/2005 : 9:47:15 PM Sorry to test your patience,
but i have tried to figure this out, is it possible to give an example of the text. I should also be more clear on what i want it to do just incase we have our wires crossed.
my setup looks like this..
abc1.abc.company.com abc2.abc.company.com abc3.abc.comapny.com
i want to query this
server1.abc3.abc.company.com server2.abc3.abc.company.com
instead of all possible DC's in the forest..
Thank you for your time.. i do appreciate it.. there's nothing like the help of someone to get you out of a work related jam..
|
| netmarcos |
Posted - 05/31/2005 : 07:58:42 AM This section lists all of the DCs and then loops through each one '* Determine configuration context and DNS domain from RootDSE object.
Set objRoot = GetObject("LDAP://RootDSE")
strConfig = objRoot.Get("ConfigurationNamingContext")
strDNSDomain = objRoot.Get("DefaultNamingContext")
'* Use ADO to search Active Directory for ObjectClass nTDSDSA.
'* This will identify all Domain Controllers.
Set objCommand = CreateObject("ADODB.Command")
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open = "Active Directory Provider"
objCommand.ActiveConnection = objConnection
objCommand.CommandText = "<LDAP://" & strConfig & ">;(ObjectClass=nTDSDSA);AdsPath;subtree"
objCommand.Properties("Page Size") = 100
objCommand.Properties("Timeout") = 30
objCommand.Properties("Searchscope") = 2
objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute
'* Enumerate parent objects of class nTDSDSA. Save Domain Controller
'* AdsPaths in dynamic array sDCs.
k = 0
Do Until objRecordSet.EOF
Set objDC = GetObject(GetObject(objRecordSet.Fields("AdsPath")).Parent)
ReDim Preserve sDCs(k)
sDCs(k) = objDC.DNSHostName
k = k + 1
objRecordSet.MoveNext
Loop
'* Retrieve LastLogon attribute for each computer on each Domain Controller.
For k = 0 To Ubound(sDCs)
oWshShell.Popup "Checking 'lastlogon' at domain controller " & sDCs(k) & ". Controller " & k & " of " & Ubound(sDCs),2,"Checking",64
'*******************************************************************
'* Modify this line for the base of your search path depending on your own AD implementation
'*******************************************************************
objCommand.CommandText = "<LDAP://" & sDCs(k) & "/OU=Workstations," & strDNSDomain & ">;(ObjectCategory=computer);Name,LastLogon;subtree"
You could simply alter the last line to call a specific DC instead of sDCs(k). And don't forget to comment out or remove the For... and Next lines if you do. |
| AvatarPalin |
Posted - 05/31/2005 : 03:05:41 AM I was wondering if someone could help me, how do i restrict the search to only on DC, please consider me a noob. I welcome all looks of distane, but i do need assistance. If someone could help me I would appreciate it..
Thanking you |
| Matricarus |
Posted - 04/28/2005 : 1:56:32 PM Small mistake. Here's how to convert the LargeInteger to date format :
strDate = #1/1/1601# + (lngDate.highpart * 2^32 + lngDate.lowpart) / 864E9 - Bias / 1440
Hope this helps. Bye.
|
| Zeohwanz |
Posted - 01/04/2005 : 09:34:09 AM Can anyone please let me know how to get rid of subtree support?
|
| photoquality |
Posted - 11/19/2004 : 3:03:30 PM Here is a chunk of code that will give you the description w/o an error.
strdesc="" IF vartype(objRecordSet.Fields("Description")) > 8192 then strdesc=CSTR(JOIN(objRecordSet.Fields("Description"))) ELSEIF vartype(objRecordSet.Fields("Description")) = 1 then strdesc="No Description" ELSEIF vartype(objRecordSet.Fields("Description")) = 8 then strdesc=objRecordSet.Fields("Description") END IF
|
| pappy2670 |
Posted - 11/18/2004 : 3:30:48 PM I had some problems as well. Make sure that "/OU=Workstations," reflects the name and type in your directory. In my case I had a container called Computers, so I used "/cn=computers, ". The OU (org unit) vs CN (container) thing threw me for a while so make sure you pick the correct one.
Good Luck. |
| aruiz |
Posted - 11/18/2004 : 2:10:06 PM Hi Guys,
I've been working on this script for a while and but still having trouble modifying:
objCommand.CommandText = "<LDAP://" & sDCs(k) & "/OU=Workstations," & strDNSDomain & ">;(ObjectCategory=computer);Name,LastLogon;subtree"
Can someone help with a clear example?
Thanks |
| netmarcos |
Posted - 10/28/2004 : 11:06:09 AM I suppose that you could do this by adding a variant(strName)for the computer name using an Inputbox to prompt for the value and modify the line that reads objCommand.CommandText = "<LDAP://" & sDCs(k) & "/OU=Workstations," & strDNSDomain & ">;(ObjectCategory=computer);Name,LastLogon;subtree" by adding an additional property to the search criteria objCommand.CommandText = "<LDAP://" & sDCs(k) & "/OU=Workstations," & strDNSDomain & ">;(ObjectCategory=computer)(Name=" & strName & ");Name,LastLogon;subtree"
For user lookup objCommand.CommandText = "<LDAP://" & sDCs(k) & "/OU=Accounts," & strDNSDomain & ">;(ObjectCategory=user)(samAccountName=" & strName & ");Name,LastLogon;subtree"
|
| dsmith1180 |
Posted - 10/27/2004 : 7:24:18 PM This code is awesome , just used. May I ask how the code could be modified to allow an helpdesk tech to be prompted for a particular user they are looking for. anotherwords how could a user prompt be built into this to ask for a single username and output the login time for a single user? This would be great to use for verifying when users last logged on, esp those who fib about rebooting! |
| scripter101 |
Posted - 10/19/2004 : 3:00:19 PM I'm getting a similar message as others. I'm tring to add the computer description to the log file but I keep getting the following error:
Error: Wrong number of arguments or invalid property assignment
Does anybody have any ideas on how to do this?
|
| imakfu |
Posted - 10/18/2004 : 5:20:13 PM OK I throw in the towel. I don't have the mental "know how" to get this done. For the life of me I can't seem to get this script to return the Description field in the results. Nothing I have done gives me valid results, I simply get one error after the other.
Thanks to all who offered advice. |
| imakfu |
Posted - 10/18/2004 : 11:45:07 AM Thanks.
Unfortunately we aren't running a 2003 environment. Here's the error I'm getting when running the script with the Description field added.
Line: 185 Char: 5 Error: Wrong number of arguments or invalid property assignment Code: 800A01C2
Here's the code. Line 185 is the line that starts with "Call VBOut(struser,objList(struser,strDesc)) " --------------------
For Each struser In objList
Call VBOut(struser,objList(struser,strDesc))
Next
objFile.WriteBlankLines (3) objFile.Close
oWshShell.Popup "Output file " & strFilePath & "\DomainLastLogon." & strLDate & ".log created." & Chr(13)_ & " Script processing complete.",5,"Notice",64
'* Clean up.
Set objRoot = Nothing Set objConnection = Nothing Set objCommand = Nothing Set objRecordSet = Nothing Set objDC = Nothing Set lngDate = Nothing Set objList = Nothing Set oWshShell = Nothing
'******************************************************************* '* Function VBOut '* '* Format data and write to output file '* '*******************************************************************
Function VBOut(strPC,strTime,strDescription)
Dim struserName 'Formatted computer name output string Dim strLogonTime 'Formatted Last Logon Time output string Dim strDescrip
Dim DataOutArray(2) 'This array is used to format the output strings
'* Format computer name string
DataOutArray(0) = strPC DataOutArray(2) = " " struserName = Join(DataOutArray) struserName = Left (struserName, 18)
'* Format Last Logon Time string
DataOutArray(0) = strTime DataOutArray(2) = " " strLogonTime = Join(DataOutArray) strLogonTime = Left (strLogonTime, 24)
DataOutArray(0) = strDescription DataOutArray(2) = " " strDescrip = Join(DataOutArray) strDescrip = Left (strDescrip, 30)
'* Write to output file
objFile.WriteLine struserName & " " & strLogonTime & " " & strDescrip
End Function
'End of Script |
| netmarcos |
Posted - 10/15/2004 : 2:15:51 PM Ya just gotta love progress! |
| wkasdo |
Posted - 10/14/2004 : 11:27:08 AM For the lucky people with a domain in 2003 native mode: dsquery computer -inactive 10 to search for computers that have not logged on for more than 10 weeks. |
| imakfu |
Posted - 10/14/2004 : 11:23:19 AM Thanks.
I can succesfully get to all the DCs with just the 2 default attributes listed in the script, but when I try to add the Description attribute (which I really need) the script faults at the ilne mentioned above. Here's what I have:
Set objRecordSet = objCommand.Execute If Err.Number <> 0 Then Err.Clear On Error GoTo 0 oWshShell.Popup "Domain Controller not available: " & sDCs(k),2,"Notice",48 Else On Error GoTo 0 Do Until objRecordSet.EOF strAdsPath = objRecordSet.Fields("Name") strDate = objRecordSet.Fields("LastLogon") strDesc = objRecordSet.Fields("Description") On Error Resume Next Err.Clear Set lngDate = strDate If Err.Number <> 0 Then Err.Clear strDate = #1/1/1601# Else If (lngDate.HighPart = 0) And (lngDate.LowPart = 0 ) Then strDate = #1/1/1601# Else strDate = #1/1/1601# + (((lngDate.HighPart * (2 ^ 32)) + lngDate.LowPart)/600000000 - Bias)/1440 End If End If On Error GoTo 0 If objList.Exists(strAdsPath) Then If strDate > objList(strAdsPath) Then objList(strAdsPath) = strDate End If Else objList.Add strAdsPath, strDate End If objRecordSet.MoveNext Loop End If Next
'* Output latest LastLogon date for each computer.
For Each struser In objList
Call VBOut(struser,objList(struser))
Next
objFile.WriteBlankLines (3) objFile.Close
oWshShell.Popup "Output file " & strFilePath & "\DomainLastLogon." & strLDate & ".log created." & Chr(13)_ & " Script processing complete.",5,"Notice",64
'* Clean up.
Set objRoot = Nothing Set objConnection = Nothing Set objCommand = Nothing Set objRecordSet = Nothing Set objDC = Nothing Set lngDate = Nothing Set objList = Nothing Set oWshShell = Nothing
'******************************************************************* '* Function VBOut '* '* Format data and write to output file '* '*******************************************************************
Function VBOut(strPC,strTime,strDescription)
Dim struserName 'Formatted computer name output string Dim strLogonTime 'Formatted Last Logon Time output string Dim strDescrip
Dim DataOutArray(2) 'This array is used to format the output strings
'* Format computer name string
DataOutArray(0) = strPC DataOutArray(2) = " " struserName = Join(DataOutArray) struserName = Left (struserName, 18)
'* Format Last Logon Time string
DataOutArray(0) = strTime DataOutArray(2) = " " strLogonTime = Join(DataOutArray) strLogonTime = Left (strLogonTime, 24)
DataOutArray(0) = strDescription DataOutArray(2) = " " strDescrip = Join(DataOutArray) strDescrip = Left (strDescrip, 30)
'* Write to output file
objFile.WriteLine struserName & " " & strLogonTime & " " & strDescrip
End Function
'End of Script |
| photoquality |
Posted - 10/06/2004 : 5:24:09 PM If you are in a large enterprise, or you have DC's that are on the other side of a slow link you may have issues.
If you log how many records each DC returns, some may return 0. This is because the timeout is 30 seconds (the default posted in most MS code examples). If you change this number to a larger number you will find great success.
objCommand.Properties("Timeout") = 30
I have changed it to 1060. You can use whatever your tolerance is. With the increased timeout I received 100% replies from over 100 DC's. At 30, I got about a 55% reply rate.
objCommand.Properties("Timeout") = 1060
|
| imakfu |
Posted - 09/24/2004 : 6:44:37 PM After adding the Description field I now get a stop error on the following line:
Call VBOut(struser,objList(struser))
Any ideas?
Thanks! |
| pappy2670 |
Posted - 09/24/2004 : 12:12:53 PM OK - I figured out my problem, I had the ou's in the path in the wrong order. I have been working blind and just guessing at what to do. Thanks to everyone for the help. |
| pappy2670 |
Posted - 09/23/2004 : 5:29:11 PM I'm still beating my head against the wall. I still cannot go more than 1 level deep. I replace "/OU=Workstations" the the name of one of my OU's (like Finance) and all is well. What should the syntax be to look in "Finance_PC_OU" which is in the Finance OU?
Thanx... |
| imakfu |
Posted - 09/23/2004 : 3:53:06 PM Thanks!
I'm trying your second suggestion now. I did try yesterday to go from the root using dc=company,dc=com and searching that for all user accounts, but it timed-out after about an hour.
Thanks again for you help. You're a lifesaver.
|
| netmarcos |
Posted - 09/23/2004 : 2:27:06 PM Well, there are several possible approaches to this problem. The most basic solution would be to adjust the search path to the root of your OU structure and have it search the entire domain for accounts. Less desirable, but also effective would be to duplicate the section within the For k = 0 To Ubound(sDCs)...Nextloop for each context that you want to search. Third would be to run the sucker for each set of UOs that you wish to search, modifying the path each time.
Oh BTW: to add the Description - or any other field - create a variant (Dim sDesc) and then change this line ">;(ObjectCategory=user);Name,LastLogon,Description;subtree" and add sDesc = objRecordSet.Fields("Description") and then don't forget to add that to your output string.
As for disabled users, you need to collect userAccountControl. Some typical values include 512-enabled, 544-change password at logon, 514-disabled.
|
|
|