SingAbout Martin
asked on
Looping through each DC for most recent LastLogon
Thanks to an expert from this site, I got the following script which is supposed to loop through each Domain Controller, obtain the LastLogon attribute and pick the most recent LastLogon value. However I have found that it does not pick the most recent value.
When I query each DC manually for the LastLogon, I see two different values and in the resulting export the oldest value is shown.
Any ideas on how to fix this?
When I query each DC manually for the LastLogon, I see two different values and in the resulting export the oldest value is shown.
Any ideas on how to fix this?
$DataAValues = @{}
foreach($DomainController in $DomainControllers) {
$DomainControllerHostname = $DomainController.HostName
$dataAParams = @{
SearchBase = $OrganizationalUnit
SearchScope = 'OneLevel'
Properties = 'samaccountname', 'LastLogon', 'whenCreated', 'distinguishedname','PasswordLastSet'
Filter = { LastLogon -le $Time -AND enabled -eq $true -AND whenCreated -le $Time }
Server = $DomainControllerHostname
}
Get-ADUser @dataAParams |
Select-Object SamAccountName,
Name,
@{Name='LastLogon'; Expression={ [DateTime]::FromFileTime($_.lastLogon).ToString('yyyy-MM-dd hh:mm:ss') }},
WhenCreated,
PasswordLastSet,
@{Name='ReferenceDate'; Expression={ $CurrentTimeStamp }},
@{Name='ADAccountDaysInactive'; Expression={ ((Get-Date) - ([DateTime]::FromFileTime($_.lastLogon))).Days }},
distinguishedname |
ForEach-Object {
if ($DataAValues.Contains($_.SamAccountName)) {
if ($DataAValues[$_.SamAccountName].LastLogon -lt $_.LastLogon) {
$DataAValues[$_.SamAccountName].LastLogon = $_.LastLogon
}
} else {
$DataAValues.Add($_.SamAccountName, $_)
}
}
}
$DataA = $DataAValues.Values | Select-Object *
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Hi
I have run this through once so that $dataa gets defined and then check the first 10 users using this modified version to verify the results
replacing it with "YouUsernametoTestHere" with each username in $dataa . The script seems to to what u want and return the most recent date for each user , and i am unable to get to fail.
I hope this helps
Joe
I have run this through once so that $dataa gets defined and then check the first 10 users using this modified version to verify the results
$DataAValues = @{}
$domainControllers = (Get-ADForest).Domains | %{ Get-ADDomainController -Filter * -Server $_ }
foreach($DomainController in $DomainControllers) {
$DomainControllerHostname = $DomainController.HostName
$dataAParams = @{
SearchBase = $OrganizationalUnit
SearchScope = 'OneLevel'
Properties = 'samaccountname', 'LastLogon', 'whenCreated', 'distinguishedname','PasswordLastSet'
Filter = {enabled -eq $true} #{ LastLogon -le $Time -AND enabled -eq $true -AND whenCreated -le $Time }
Server = $DomainControllerHostname
}
Get-ADUser @dataAParams | where {$_.samaccountname -eq "YouUsernametoTestHere"} |
Select-Object SamAccountName,
Name,
@{Name='LastLogon'; Expression={ [DateTime]::FromFileTime($_.lastLogon).ToString('yyyy-MM-dd hh:mm:ss') }},
WhenCreated,
PasswordLastSet,
@{Name='ReferenceDate'; Expression={ $CurrentTimeStamp }},
@{Name='ADAccountDaysInactive'; Expression={ ((Get-Date) - ([DateTime]::FromFileTime($_.lastLogon))).Days }},
distinguishedname
}
replacing it with "YouUsernametoTestHere" with each username in $dataa . The script seems to to what u want and return the most recent date for each user , and i am unable to get to fail.
I hope this helps
Joe
ASKER
Thank you Joe, but this is not exactly what I mean. The script you provided does return the LastLogon attribute value from all available Domain Controllers. However, it returns all time stamps. I only want to return the most recent logon time stamp. Because that is the value that I will be working with.
Hi
The modified code i provided was to assist you in validating the output from your original script. I believe that your script is working , and your previous validation may of been the issue , and not the script.
to validate your results try the following
run your original script and store the results into a file ( $dataa | export-csv ADusers.csv -notypeinformation )
open this file and select some random users ,
enter them one at a time into the script i supplied top verify the date in the file , is the most recent date
Please let me know if i can help further
Joe
The modified code i provided was to assist you in validating the output from your original script. I believe that your script is working , and your previous validation may of been the issue , and not the script.
to validate your results try the following
run your original script and store the results into a file ( $dataa | export-csv ADusers.csv -notypeinformation )
open this file and select some random users ,
enter them one at a time into the script i supplied top verify the date in the file , is the most recent date
Please let me know if i can help further
Joe
ASKER
Hi Joe,
With your script it still doesn't export the most recent value. This makes sense because I think it needs to make a calculation, which is supposedly done in the ForEach-Object section of the original script I posted (but that doesn't work properly). In your script, I don't see where it is calculating the highest value and putting that forward.
With your script it still doesn't export the most recent value. This makes sense because I think it needs to make a calculation, which is supposedly done in the ForEach-Object section of the original script I posted (but that doesn't work properly). In your script, I don't see where it is calculating the highest value and putting that forward.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Good one oBdA, but unfortunately, still the older value is returned.
Hi
how are you determining the older value is being returned ?
and line 22 was correct before
@obda good catch with the HH in the date formatting.
how are you determining the older value is being returned ?
and line 22 was correct before
f ($DataAValues[$_.SamAccountName].LastLogon -lt $_.LastLogon) {
@obda good catch with the HH in the date formatting.
ASKER
Using this script, then after running this, querying $DataA. If I change the $DomainControllers to what you suggested, this makes no difference in the result.
$DaysInactive = 60
$Time = (Get-Date).Adddays(-($DaysInactive))
$CurrentTimeStamp = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
$OrganizationalUnit = 'OU=Users,DC=Contoso,DC=Local'
$DomainControllers = Get-ADDomainController -Filter {Name -like "*"}
$ErrorActionPreference = 'SilentlyContinue'
$DataAValues = @{}
foreach($DomainController in $DomainControllers) {
$DomainControllerHostname = $DomainController.HostName
$dataAParams = @{
SearchBase = $OrganizationalUnit
SearchScope = 'OneLevel'
Properties = 'samaccountname', 'LastLogon', 'whenCreated', 'distinguishedname','PasswordLastSet'
Filter = { LastLogon -le $Time -AND enabled -eq $true -AND whenCreated -le $Time }
Server = $DomainControllerHostname
}
Get-ADUser @dataAParams |
Select-Object SamAccountName,
Name,
@{Name='LastLogon'; Expression={ [DateTime]::FromFileTime($_.lastLogon).ToString('yyyy-MM-dd HH:mm:ss') }},
WhenCreated,
PasswordLastSet,
@{Name='ReferenceDate'; Expression={ $CurrentTimeStamp }},
@{Name='ADAccountDaysInactive'; Expression={ ((Get-Date) - ([DateTime]::FromFileTime($_.lastLogon))).Days }},
distinguishedname |
ForEach-Object {
if ($DataAValues.Contains($_.SamAccountName)) {
if ($DataAValues[$_.SamAccountName].LastLogon -lt $_.LastLogon) {
$DataAValues[$_.SamAccountName].LastLogon = $_.LastLogon
}
} else {
$DataAValues.Add($_.SamAccountName, $_)
}
}
}
$DataA = $DataAValues.Values | Select-Object *
Hi
I think you should try the following which is based on Obda script , it does the same as your script , and now outputs the same fields
so you will not need to change any surrounding code. the only thing to change would be the filter on line 5 to include the the following from
-Filter {Enabled -eq $true}
to
-Filter {LastLogon -le $Time -AND enabled -eq $true -AND whenCreated -le $Time }
I think you should try the following which is based on Obda script , it does the same as your script , and now outputs the same fields
so you will not need to change any surrounding code. the only thing to change would be the filter on line 5 to include the the following from
-Filter {Enabled -eq $true}
to
-Filter {LastLogon -le $Time -AND enabled -eq $true -AND whenCreated -le $Time }
$SearchBase = "OU=Whatever,DC=domain,DC=local"
$CurrentTimeStamp = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
$DataA = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName | ForEach-Object {
"Processing $_ ..." | Write-Host
Get-ADUser -Server $_ -SearchBase $SearchBase -Filter {Enabled -eq $true} -Properties Name, LastLogon,whenCreated,distinguishedname,PasswordLastSet|
Select-Object Name ,
@{Name='LastLogon'; Expression={ [DateTime]::FromFileTime($_.lastLogon).ToString('yyyy-MM-dd HH:mm:ss') }},
whencreated,Passwordlastset,@{Name='ReferenceDate'; Expression={ $CurrentTimeStamp }},
@{Name='ADAccountDaysInactive'; Expression={ ((Get-Date) - ([DateTime]::FromFileTime($_.lastLogon))).Days }},
distinguishedname
} | Group-Object -Property SamAccountName | ForEach-Object { $_.Group | sort lastlogon,name -desc } | sort distinguishedname -Unique
$DataA
ASKER
Hi Joe,
That might be a smart idea, but the whole point of the script is to identify users that have not logged on for at least 60 days. So if I adjust the filter to your suggestion, this will no longer be the case and I will see the LastLogon for very user in the specified OU, which is not the purpose of the script. But I appreciate your suggestion!
That might be a smart idea, but the whole point of the script is to identify users that have not logged on for at least 60 days. So if I adjust the filter to your suggestion, this will no longer be the case and I will see the LastLogon for very user in the specified OU, which is not the purpose of the script. But I appreciate your suggestion!
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Anyone ideas?
Well, have you tested m yrevised script at https:#a42108648 ?
I have tested it successfully on my Domain controllers.
Somehow it returns one record that was dated back year 1601 ?
Somehow it returns one record that was dated back year 1601 ?
That account never logged on.
Great, in that case I'd say the script does works correctly.
Thanks for sharing.
You are very helpful in this forum.
Thanks for sharing.
You are very helpful in this forum.
ASKER
Hi Obda,
I have tested your script and I can confirm that it does not return the most recent logon time. In the export I have UserABC with a logon time in January 2017, but when I query my Domain Controllers I have at least one Domain Controller with a logon time in April 2017 for this UserABC.
I have tested your script and I can confirm that it does not return the most recent logon time. In the export I have UserABC with a logon time in January 2017, but when I query my Domain Controllers I have at least one Domain Controller with a logon time in April 2017 for this UserABC.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Hi
did you actually try my script as it did work for and returned the correct results here it is again I have included the filter statement
Please try and let me know your results
did you actually try my script as it did work for and returned the correct results here it is again I have included the filter statement
Please try and let me know your results
$SearchBase = "OU=Whatever,DC=domain,DC=local"
$CurrentTimeStamp = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
$minage = (Get-Date).adddays(-60)
$DataA = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName | ForEach-Object {
"Processing $_ ..." | Write-Host
Get-ADUser -Server $_ -SearchBase $SearchBase -Filter {LastLogon -le $minage -and enabled -eq $true -AND whenCreated -le $minage } -Properties Name, LastLogon,whenCreated,distinguishedname,PasswordLastSet|
Select-Object Name ,
@{Name='LastLogon'; Expression={ [DateTime]::FromFileTime($_.lastLogon).ToString('yyyy-MM-dd HH:mm:ss') }},
whencreated,Passwordlastset,@{Name='ReferenceDate'; Expression={ $CurrentTimeStamp }},
@{Name='ADAccountDaysInactive'; Expression={ ((Get-Date) - ([DateTime]::FromFileTime($_.lastLogon))).Days }},
distinguishedname
} | Group-Object -Property SamAccountName | ForEach-Object { $_.Group | sort lastlogon,name -desc } | sort distinguishedname -Unique
$DataA
ASKER
Thanks both for your help! However, neither solution worked appropriately.
@OBda: When I try your script, it returns for most users the logon times for each Domain Controller. It's a step in the good direction, but not exactly what I'm looking for. Also, for a number of users I only get to see the logon time from a single Domain Controller, which also happens to be the oldest logon date of all. So for example, I have a user named UserA and that user has two logon times, one on DC01 and one on DC02. In the results of your script, for some users, I see for UserA only the logon time from DC01, while DC02 is the most recent one.
@Joe Klimis: It is not working properly in my environment (Windows Server 2008 R2). In the resulting export I have a user with a logon time showing its last logon time was in January, while I have verified using PowerShell that another Domain Controller has a more recent logon time for this user in April.
@OBda: When I try your script, it returns for most users the logon times for each Domain Controller. It's a step in the good direction, but not exactly what I'm looking for. Also, for a number of users I only get to see the logon time from a single Domain Controller, which also happens to be the oldest logon date of all. So for example, I have a user named UserA and that user has two logon times, one on DC01 and one on DC02. In the results of your script, for some users, I see for UserA only the logon time from DC01, while DC02 is the most recent one.
@Joe Klimis: It is not working properly in my environment (Windows Server 2008 R2). In the resulting export I have a user with a logon time showing its last logon time was in January, while I have verified using PowerShell that another Domain Controller has a more recent logon time for this user in April.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Excellent!!! Thank you very much Obda, now it makes completely sense. Tested it & verified that it returned only the most recent logon time for each users. Perfect, thanks a lot.
ASKER