We help IT Professionals succeed at work.

Looping through each DC for most recent LastLogon

315 Views
1 Endorsement
Last Modified: 2017-05-02
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?

$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 *

Open in new window

Comment
Watch Question

CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
Thank you oBdA for your reply, however this appears to be a little bit different from what I'm working with right now. Could you possibly motivate the reason my script is not working as expected, and how I can implement a fix in my current script? If I have to use your script I have to rebuild everything.
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

$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 
}

Open in new window



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

Author

Commented:
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

Author

Commented:
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.
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
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

f ($DataAValues[$_.SamAccountName].LastLogon -lt $_.LastLogon) {

Open in new window


@obda     good catch with the HH in the date formatting.

Author

Commented:
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 *

Open in new window

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 }


$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

Open in new window

Author

Commented:
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!
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
Anyone ideas?
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
Well, have you tested m yrevised script at https:#a42108648 ?
Senior IT System EngineerSenior Systems Engineer
CERTIFIED EXPERT

Commented:
I have tested it successfully on my Domain controllers.

Somehow it returns one record that was dated back year 1601 ?
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
That account never logged on.
Senior IT System EngineerSenior Systems Engineer
CERTIFIED EXPERT

Commented:
Great, in that case I'd say the script does works correctly.

Thanks for sharing.
You are very helpful in this forum.

Author

Commented:
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.
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
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

$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

Open in new window

Author

Commented:
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.
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
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.

Gain unlimited access to on-demand training courses with an Experts Exchange subscription.

Get Access
Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Empower Your Career
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE

Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

  • Troubleshooting
  • Research
  • Professional Opinions
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.