bourny Posted November 26, 2008 Posted November 26, 2008 i am writing a script to manage my computers in active directory . i will be moving them around OU`s based on the IP address DNS has them assigned to. This appears to pull out computers that have no IP address since DHCP has released the address for that machine due to the machine not connecting to the network for a while. This is where my question begins. Is there a way to pull an attribute from AD to find out when the last time the machine connected to the network. If the machine has not connected for a few months I want to isolate this in a different OU for inactive machines. I have the script for everything but pulling the attribute from AD for the last time it had been on the network.. Many thanks
water Posted November 26, 2008 Posted November 26, 2008 Have a look at http://www.microsoft.com/technet/scriptcen.../lastlogon.mspx. This article explains how to calculate the last logon time.At http://www.autoitscript.com/forum/index.ph...st&p=422402 you'll find a script that converts the lastlogontimestamp to a readable format. My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki Standard UDFs: Excel - Example Scripts - Wiki Word - Wiki Tutorials: ADO - Wiki WebDriver - Wiki
99ojo Posted November 26, 2008 Posted November 26, 2008 if you have xp or 2003 server machine you can use: dsquery computer -inactive <weeks>. This shows you inactive computeraccounts and you may filter or script them. Move all machines which are inactive for 12 weeks on Domain yourdomain.local into OU Inactive: dsquery computer -inactive 12 |dsmove -newparent OU=Inactive,dc=yourdomain, dc=local you may have to use parameter -limit. see dsquery computer /? ;-)) Stefan
bourny Posted November 26, 2008 Author Posted November 26, 2008 99ojo - I dont have a 2003 domain unfortunatly but thanks for that. Water - Have a look at http://www.microsoft.com/technet/scriptcen.../lastlogon.mspx. This article explains how to calculate the last logon time. At http://www.autoitscript.com/forum/index.ph...st&p=422402 you'll find a script that converts the lastlogontimestamp to a readable format. I have looked at both articles - the AutoIt article appears to claim there is a set of code that will do this job but I have looked at the code and tried it - (Placed the correction into what I think is the right place) but it does not work. It looks to me as if I dont need the VBS as the AutiIt coder appears to have managed to get it working and has converted it... Here is my attempt at his code ... Obviously doing something wrong The Error I get from the below is : $objRecordSet = $objCommand.Execute $objRecordSet = $objCommand.Execute^ ERROR expandcollapse popup[/code] Dim $objShell Dim $objEnv Dim $CompEnv0 Dim $Description $objShell = ObjCreate("Wscript.Shell") $objEnv = $objShell.Environment("Process") $CompEnv0 = StringLeft($objEnv("COMPUTERNAME"), 4) GetSiteDescription ("MyDom.co.uk") MsgBox(0,"",$Description) Func GetSiteDescription($sLongDomainName) Dim $objConnection, $objCommand, $arrFQDN, $objRecordSet, $objOU $objConnection = ObjCreate("ADODB.Connection") $objConnection.Open("Provider=ADsDSOObject;") $objCommand = ObjCreate("ADODB.Command") $objCommand.ActiveConnection = $objConnection $arrFQDN=StringSplit($sLongDomainName,".") $objCommand.CommandText = "<LDAP://OU=LOCATIONS,OU=DEPT" & ",DC=" & $arrFQDN[1] & ",DC=" & $arrFQDN[2] & ",DC=" & $arrFQDN[3] & ">;(&(objectCategory=organizationalunit)(name=*"& $CompEnv0 &"));Name,distinguishedName,description;subtree" $objRecordSet = $objCommand.Execute ;$objOU = ObjGet("LDAP://" & $objRecordSet.Fields("distinguishedName")) ;$Description=$objOU.Get("description") ;$objConnection.Close ;Return $Description ;--------------------Added in Ammended script and remmed out 2 lines above ;$objRecordSet = $objCommand.Execute $DistListing = $objRecordSet.Fields("DistinguishedName").value $objConnection.Close $objDescription = ObjGet("LDAP://"& $DistListing) $Description = $objDescription.description Return $Description = $objDescription.description EndFunc [code]
99ojo Posted November 26, 2008 Posted November 26, 2008 if you have xp or 2003 server machine you can use: dsquery computer -inactive <weeks>. This shows you inactive computeraccounts and you may filter or script them.Move all machines which are inactive for 12 weeks on Domain yourdomain.local into OU Inactive:dsquery computer -inactive 12 |dsmove -newparent OU=Inactive,dc=yourdomain, dc=localyou may have to use parameter -limit. see dsquery computer /?;-))Stefanit works on w2k domains as well.;-))
bourny Posted November 26, 2008 Author Posted November 26, 2008 it works on w2k domains as well.;-))When I run this Query it tells me the Query does not work because you are connected to a domain that does not support this query.I am running "DSQuery Computer -inactive 5"
99ojo Posted November 26, 2008 Posted November 26, 2008 When I run this Query it tells me the Query does not work because you are connected to a domain that does not support this query.I am running "DSQuery Computer -inactive 5"set on client HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AdminDebug\ADsOpenObjectFlags to 0x03. it will stop crypting and signing ldap traffic.
bourny Posted November 26, 2008 Author Posted November 26, 2008 set on client HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AdminDebug\ADsOpenObjectFlags to 0x03. it will stop crypting and signing ldap traffic. I have added the Dword and rebooted but does not get around - same error
99ojo Posted November 26, 2008 Posted November 26, 2008 I have added the Dword and rebooted but does not get around - same errorwhich servicepack is on your w2k domain controller?
bourny Posted November 26, 2008 Author Posted November 26, 2008 which servicepack is on your w2k domain controller?SErvice Pack 4 ....Not to be rude I appreciate your help but I cannot change my domain controllers to suit this script .... I am Very intersted in how to get the script pointed out earlier to work ....I think this is going off on a tangent now...
water Posted November 26, 2008 Posted November 26, 2008 As the lastlogin attribute is not synchronized between AD controllers you'll have to query each AD controller for this attribute and calculate the most current.See this link My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki Standard UDFs: Excel - Example Scripts - Wiki Word - Wiki Tutorials: ADO - Wiki WebDriver - Wiki
bourny Posted November 26, 2008 Author Posted November 26, 2008 As the lastlogin attribute is not synchronized between AD controllers you'll have to query each AD controller for this attribute and calculate the most current.See this linkSo when I look at the script provided in the http://www.autoitscript.com/forum/index.ph...st&p=422402 appears to have got this working does this mean it may not work as it appears to query the domain not an individual DC - Have I picked you up right I think I am lost now -.....I suppose my question is - is there a way to do this in AutoIt or will I have to give this up as a bad job. Object scripting is out of my knowledge at the moment so I am stuck to trying to understand the object scripts in this forum but clearly failing to pick up what need to be done
bourny Posted November 26, 2008 Author Posted November 26, 2008 I appear to have got it working using an example script in the link you provided and as it states you have to have the correct DC to get the inmformation ..... Shame there is no way of knowing without going thru all the DC`s which on logged the computer / user on Thanks water
99ojo Posted November 26, 2008 Posted November 26, 2008 I appear to have got it working using an example script in the link you provided and as it states you have to have the correct DC to get the inmformation ..... Shame there is no way of knowing without going thru all the DC`s which on logged the computer / user onThanks watermaybe you should query the age of the password. all computers change their computer password. this is replicated all over the domain, so you have to query only one dc. you may use the tool netpwage to query and pipe into a textfile to work with.;-))
bourny Posted November 26, 2008 Author Posted November 26, 2008 maybe you should query the age of the password. all computers change their computer password. this is replicated all over the domain, so you have to query only one dc. you may use the tool netpwage to query and pipe into a textfile to work with.;-))Thanks again for your suggestions 99ojo. I am happy with the script I have now got together - I will simply put the script into a function and spam it with the name of all my DC`s until I get a logon date or an answer to if the CN has never logged on or does not exist. This is simple to do - The hard part is getting a script to actually pull out the date which I now have with the help of the forum.Thanks again 99ojo - you demonstrate a good knowledge of Ad tools but in this case I want to get AutoIt to do this all in one script without having to bring in external tools that simply bring more scope for issues out of my scripts control.
water Posted November 26, 2008 Posted November 26, 2008 (edited) The following example script (based on adfunctions.au3) queries all domain controllers and returns the true last login time for computer PCTS29 (the sAMAccountName for a computer is the comptuername followed by a dollar sign). The get the true last login for a user just use @username or the sAMAccountName of the desired user. expandcollapse popupGlobal $objConnection = ObjCreate("ADODB.Connection") ; Create COM object to AD $objConnection.ConnectionString = "Provider=ADsDSOObject" $objConnection.Open("Active Directory Provider") ; Open connection to AD Global $objRootDSE = ObjGet("LDAP://RootDSE") Global $strDNSDomain = $objRootDSE.Get("defaultNamingContext") ; Retrieve the current AD domain name Global $strHostServer = $objRootDSE.Get("dnsHostName") ; Retrieve the name of the connected DC Global $strConfiguration = $objRootDSE.Get("ConfigurationNamingContext") ; Retrieve the Configuration naming context Global $objOpenDS = ObjGet("LDAP:") Global $DCList, $LastLogin=0 _ADListDomainControllers($DCList) For $i =1 to $DCList[0] $sTmp = StringSplit($DCList[$i],",") $sTmp = StringSplit($sTmp[1],"CN=",1) $sTmp = _GetLogin($sTmp[2],"PCTS29$") If $sTmp > $LastLogin Then $LastLogin = $sTmp Next ConsoleWrite($LastLogin) Func _GetLogin($strHostServer,$sAMAccountName) $strQuery = "<LDAP://" & $strHostServer & "/" & $strDNSDomain & ">;(sAMAccountName=" & $sAMAccountName & ");ADsPath;subtree" $objRecordSet = $objConnection.Execute($strQuery) ; Retrieve the FQDN for the object $ldap_entry = $objRecordSet.fields(0).value $oObject = ObjGet($ldap_entry) ; Retrieve the COM Object for the object $result = $oObject.LastLogin $oObject.PurgePropertyList If $result = "" Then Return "" Else Return $result EndIf EndFunc ; _ADListDomainControllers ; Retrieves the names of all domain controllers in the current Domain Func _ADListDomainControllers(ByRef $DCList) $objCommand = ObjCreate("ADODB.Command") $objCommand.ActiveConnection = $objConnection $objCommand.Properties("Page Size") = 1000 $objCommand.Properties("Searchscope") = 2 $objCommand.CommandText = "Select distinguishedName FROM 'LDAP://" & $strHostServer & "/ou=Domain Controllers," & $strDNSDomain & "' WHERE objectclass='computer'" $objRecordSet = $objCommand.Execute Dim $DCList[$objRecordSet.RecordCount + 1] $objRecordSet.MoveFirst Do $DCList[0] += 1 $objCommand.CommandText = "<LDAP://" & $strHostServer & "/" & $objRecordSet.Fields("distinguishedName" ).Value & ">;;serverReferenceBL;Range=0-*;base" $objRecSet2 = $objCommand.Execute $objRecSet2.MoveFirst Do $temparray = $objRecSet2.Fields(0).Value $DCList[$DCList[0]] = $temparray[0] $objRecSet2.MoveNext Until $objRecSet2.EOF $objRecordSet.MoveNext Until $objRecordSet.EOF $objCommand = 0 $objRecordSet = 0 Return EndFunc ;==>_ADListDomainControllers Edited November 26, 2008 by water My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki Standard UDFs: Excel - Example Scripts - Wiki Word - Wiki Tutorials: ADO - Wiki WebDriver - Wiki
bourny Posted November 26, 2008 Author Posted November 26, 2008 For the benefit of everyone here is my completed script I have for scanning all my domain controllers for the last logged on date expandcollapse popup[/code] #include <Date.au3> #include <array.au3> Dim $LogonInfo[3] $LogonInfo[0] = "Not Found" $ArrayOfDcs = _ArrayCreate("l2dc8", "dc1", "dc2", "dc3", "dc4", "dc10", "dc9") $OUtoScan = "OU=redundant,OU=Client Computers";;;;; This will need to be the full path e.g cn="laptops,cn=Computer Accounts,cn="RootOU" $ObjectToLookFor = "cn=BBTest" $LogonInfo = ScanForObject($ArrayOfDcs, $OUtoScan, $ObjectToLookFor) Select Case $LogonInfo[0] = "Error" MsgBox(0, "Failed to find Last Logged on date", "Checked All Dc`s and failed to find the object / last logged on date") Case $LogonInfo[0] = "Never" MsgBox(0, "Completed Scan", "The object specified has never logged onto any DC yet....") Case $LogonInfo[0] = "Found" MsgBox(0, "Completed Scan", "Found the following...." & @lf & _ "Last logged on = " & $LogonInfo[1] & @lf & _ "Domain Controller = " & $LogonInfo[2]) Case Else MsgBox(0, "Failed to find Last Logged on date", "Checked All Dc`s and failed to find the object / last logged on date") EndSelect Func ScanForObject($ArrayOfDcs, $OUtoScan, $ObjectToLookFor) For $DC IN $ArrayOfDcs dim $oMyError = ObjEvent("AutoIt.Error", "MyErrFunc") dim $sServer = $DC & ".MYDOM.co.uk" dim $sUserPath = $ObjectToLookFor & "," & $OUtoScan & ",dc=MYDOM,dc=co,dc=uk" dim $oUser, $oLastLogon, $iLastLogon = 0 ; Get user object Local $oUser = ObjGet("LDAP://" & $sServer & "/" & $sUserPath) If IsObj($oUser) Then $oLastLogon = $oUser.Get("lastLogon") If @error Then ;MsgBox(16, 'Debug', 'Error occured retreiving $oUser.Get("lastLogon").' & @CRLF & _ ; 'This attribute may not exist for this object.') $LogonInfo[0] = "Error" ;Continue Looping Else ; Convert IADsLargeInteger parts to 100ns count $iLastLogonHigh = $oLastLogon.HighPart $iLastLogonLow = $oLastLogon.LowPart If $iLastLogonLow < 0 Then $iLastLogonHigh += 1; Compensate for IADsLargeInteger interface error $iLastLogon = $iLastLogonHigh * 2 ^ 32 $iLastLogon += $iLastLogonLow ; Check if user ever logged in If $iLastLogon = 0 Then ;MsgBox(64, "Last Logon", "User has never logged on.") $LogonInfo[0] = "Never" ExitLoop Else ; Convert 100ns count to integer seconds $iSeconds = Floor($iLastLogon / 10000000) ; Convert seconds since 12:00AM January 01, 1601 to date string $sLastLogon = _DateAdd("S", $iSeconds, "1601/01/01 00:00:00") ; Display result ;MsgBox(64, "Last Logon", "$sLastLogon = " & $sLastLogon & " Zulu (UTC)") $LogonInfo[0] = "Found" $LogonInfo[1] = $sLastLogon $LogonInfo[2] = $DC ExitLoop EndIf EndIf Else ;MsgBox(16, "Error", "$oUser is not an object, user may not exist.") $LogonInfo[0] = "Error" EndIf Next Return $LogonInfo EndFunc Func MyErrFunc() $LogonInfo[0] = "Error" ;MsgBox(16, "AutoIt COM Error", "AutoIt intercepted a COM Error:" & @CRLF & _ ; "Number is: " & Hex($oMyError.number, 8) & @CRLF & _ ; "Windescription is: " & $oMyError.windescription) SetError(1) EndFunc;==>MyErrFunc[code]
bourny Posted November 26, 2008 Author Posted November 26, 2008 The following script (based on adfunctions.au3) queries all domain controllers and returns the true last login time: expandcollapse popupGlobal $objConnection = ObjCreate("ADODB.Connection") ; Create COM object to AD $objConnection.ConnectionString = "Provider=ADsDSOObject" $objConnection.Open("Active Directory Provider") ; Open connection to AD Global $objRootDSE = ObjGet("LDAP://RootDSE") Global $strDNSDomain = $objRootDSE.Get("defaultNamingContext") ; Retrieve the current AD domain name Global $strHostServer = $objRootDSE.Get("dnsHostName") ; Retrieve the name of the connected DC Global $strConfiguration = $objRootDSE.Get("ConfigurationNamingContext") ; Retrieve the Configuration naming context Global $objOpenDS = ObjGet("LDAP:") Global $DCList, $LastLogin=0 _ADListDomainControllers($DCList) For $i =1 to $DCList[0] $sTmp = StringSplit($DCList[$i],",") $sTmp = StringSplit($sTmp[1],"CN=",1) $sTmp = _GetLogin($sTmp[2]) If $sTmp > $LastLogin Then $LastLogin = $sTmp Next ConsoleWrite($LastLogin) Func _GetLogin($strHostServer) $strQuery = "<LDAP://" & $strHostServer & "/" & $strDNSDomain & ">;(sAMAccountName=" & @UserName & ");ADsPath;subtree" $objRecordSet = $objConnection.Execute($strQuery) ; Retrieve the FQDN for the object $ldap_entry = $objRecordSet.fields(0).value $oObject = ObjGet($ldap_entry) ; Retrieve the COM Object for the object $result = $oObject.LastLogin $oObject.PurgePropertyList If $result = "" Then Return "" Else Return $result EndIf EndFunc ; _ADListDomainControllers ; Retrieves the names of all domain controllers in the current Domain Func _ADListDomainControllers(ByRef $DCList) $objCommand = ObjCreate("ADODB.Command") $objCommand.ActiveConnection = $objConnection $objCommand.Properties("Page Size") = 1000 $objCommand.Properties("Searchscope") = 2 $objCommand.CommandText = "Select distinguishedName FROM 'LDAP://" & $strHostServer & "/ou=Domain Controllers," & $strDNSDomain & "' WHERE objectclass='computer'" $objRecordSet = $objCommand.Execute Dim $DCList[$objRecordSet.RecordCount + 1] $objRecordSet.MoveFirst Do $DCList[0] += 1 $objCommand.CommandText = "<LDAP://" & $strHostServer & "/" & $objRecordSet.Fields("distinguishedName" ).Value & ">;;serverReferenceBL;Range=0-*;base" $objRecSet2 = $objCommand.Execute $objRecSet2.MoveFirst Do $temparray = $objRecSet2.Fields(0).Value $DCList[$DCList[0]] = $temparray[0] $objRecSet2.MoveNext Until $objRecSet2.EOF $objRecordSet.MoveNext Until $objRecordSet.EOF $objCommand = 0 $objRecordSet = 0 Return EndFunc ;==>_ADListDomainControllers Looks better than My attempt - Bit more dynamic not having to specify the DC`s - Where do I put the object I want to search for ... Looking but not finding it anywhere - Maybe too late in the day for my eyes to take any more scripts.
bourny Posted November 26, 2008 Author Posted November 26, 2008 The following example script (based on adfunctions.au3) queries all domain controllers and returns the true last login time for computer PCTS29 (the sAMAccountName for a computer is the comptuername followed by a dollar sign). The get the true last login for a user just use @username or the sAMAccountName of the desired user. expandcollapse popupGlobal $objConnection = ObjCreate("ADODB.Connection") ; Create COM object to AD $objConnection.ConnectionString = "Provider=ADsDSOObject" $objConnection.Open("Active Directory Provider") ; Open connection to AD Global $objRootDSE = ObjGet("LDAP://RootDSE") Global $strDNSDomain = $objRootDSE.Get("defaultNamingContext") ; Retrieve the current AD domain name Global $strHostServer = $objRootDSE.Get("dnsHostName") ; Retrieve the name of the connected DC Global $strConfiguration = $objRootDSE.Get("ConfigurationNamingContext") ; Retrieve the Configuration naming context Global $objOpenDS = ObjGet("LDAP:") Global $DCList, $LastLogin=0 _ADListDomainControllers($DCList) For $i =1 to $DCList[0] $sTmp = StringSplit($DCList[$i],",") $sTmp = StringSplit($sTmp[1],"CN=",1) $sTmp = _GetLogin($sTmp[2],"PCTS29$") If $sTmp > $LastLogin Then $LastLogin = $sTmp Next ConsoleWrite($LastLogin) Func _GetLogin($strHostServer,$sAMAccountName) $strQuery = "<LDAP://" & $strHostServer & "/" & $strDNSDomain & ">;(sAMAccountName=" & $sAMAccountName & ");ADsPath;subtree" $objRecordSet = $objConnection.Execute($strQuery) ; Retrieve the FQDN for the object $ldap_entry = $objRecordSet.fields(0).value $oObject = ObjGet($ldap_entry) ; Retrieve the COM Object for the object $result = $oObject.LastLogin $oObject.PurgePropertyList If $result = "" Then Return "" Else Return $result EndIf EndFunc ; _ADListDomainControllers ; Retrieves the names of all domain controllers in the current Domain Func _ADListDomainControllers(ByRef $DCList) $objCommand = ObjCreate("ADODB.Command") $objCommand.ActiveConnection = $objConnection $objCommand.Properties("Page Size") = 1000 $objCommand.Properties("Searchscope") = 2 $objCommand.CommandText = "Select distinguishedName FROM 'LDAP://" & $strHostServer & "/ou=Domain Controllers," & $strDNSDomain & "' WHERE objectclass='computer'" $objRecordSet = $objCommand.Execute Dim $DCList[$objRecordSet.RecordCount + 1] $objRecordSet.MoveFirst Do $DCList[0] += 1 $objCommand.CommandText = "<LDAP://" & $strHostServer & "/" & $objRecordSet.Fields("distinguishedName" ).Value & ">;;serverReferenceBL;Range=0-*;base" $objRecSet2 = $objCommand.Execute $objRecSet2.MoveFirst Do $temparray = $objRecSet2.Fields(0).Value $DCList[$DCList[0]] = $temparray[0] $objRecSet2.MoveNext Until $objRecSet2.EOF $objRecordSet.MoveNext Until $objRecordSet.EOF $objCommand = 0 $objRecordSet = 0 Return EndFunc ;==>_ADListDomainControllers When running this I get (64) : ==> Subscript used with non-Array variable.: $DCList[$DCList[0]] = $temparray[0] $DCList[$DCList[0]] = $temparray^ ERROR
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now