Mark Minasi's Reader Forum
Mark Minasi's Reader Forum
Home | Profile | Register | Active Topics | Active Polls | Members | Search | FAQ | Minasi Forum RSS Feed
 All Forums
 Old, obsolete or unused
 Scripting Archive
 Last Logon Attribute for workstations

Note: You must be registered in order to post a reply.
To register, click here. Registration is FREE!

Screensize:
UserName:
Password:
Format Mode:
Format: BoldItalicizedUnderlineStrikethrough Align LeftCenteredAlign Right Horizontal Rule Insert HyperlinkInsert EmailInsert Image Insert CodeInsert QuoteInsert List
   
Message:

* HTML is OFF
* Forum Code is ON
Smilies
Smile [:)] Big Smile [:D] Cool [8D] Blush [:I]
Tongue [:P] Evil [):] Wink [;)] Clown [:o)]
Black Eye [B)] Eight Ball [8] Frown [:(] Shy [8)]
Shocked [:0] Angry [:(!] Dead [xx(] Sleepy [|)]
Kisses [:X] Approve [^] Disapprove [V] Question [?]

 
Note: please do not cross-post.
Cross-postings will be deleted and ignored.
Thanks for helping to keep this forum junk-free!
   

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.

Mark Minasi's Reader Forum © 2002-2011 Mark Minasi Go To Top Of Page
This page was generated in 0.33 seconds. Snitz Forums 2000