Getting True LastLogonDate

This topic contains 5 replies, has 5 voices, and was last updated by  David Flores 4 days, 16 hours ago.

  • Author
    Posts
  • #79891

    Andy
    Participant

    I don't know if anyone else has a hybrid 365 environment, but I am faced with a frustrating dilemma. Based on a support ticket with Microsoft and my research there is no synchronization between 365 and your local active directory for lastlogondate. This means if a user authenticates to a local AD resource vs a 365 cloud resource you can/will have a lastlogondate mismatch. Why is this so concerning you may ask.

    Based on security parameters I would like to disable(disuser) accounts that have not be used in a set number of days. That is no problem already have a powershell script to achieve this. What I am trying to figure out is what is the best way to compare the date in my local AD vs the 365 environment to store the true(correct) lastlogondate?

    Anyone else that has any feedback it would greatly be appreciated.

  • #79906

    Andy
    Participant

    EXAMPLE

    365 LastLogonDate

    get-mailboxstatistics -identity doe.john | select lastlogontime
    

    LastLogonTime
    ————-
    9/15/2017 8:50:55 AM

    AD On-Premise LastLogonDate

    PS C:\scripts\ActiveScheduledScripts>  Get-ADUser -Filter * -SearchBase "cn=doe.john,ou=axb,dc=site,dc=org" -Res
    ultPageSize 0 -Prop CN,lastLogonTimestamp | Select CN,@{n="lastLogonDate";e={[datetime]::FromFileTime($_.lastLogonTimest
    amp)}}
    

    lastLogonTimeStamp
    ————-
    8/24/2016 2:06:23 PM

  • #79910

    Ian Hockett
    Participant

    Hi Andy,

    I ran into this recently as well. The problem is lastLogonTimestamp is designed for auditing stale accounts, and therefore it is only accurate up to around 14 days or so. If you want to see who hasn't logged in for a year, this is great. But if you want the literal last time someone logged into the domain, that is a little trickier.

    There is another attribute called lastLogon, which is the literal last time a user logged into a specific domain controller. The problem is that this attribute is not replicated to the other domain controllers. What I did was write a script to go to each domain controller and pull that attribute, convert to datetime like you did above, and then sort by LastLogon descending and select the first 1. To do this you would run Get-AdUser with the -Server param and specify the domain controller.

    Hope this helps.

  • #80212

    Juliën Zweverink
    Participant

    Hi,

    The Last Logon time stap is only saved on 1 DC not on all and its not replicated.
    Here is a way to get it

    Function Get-ADUserLastLogon {
    	param
    	(
    		[Parameter(Mandatory = $true,
    				   ValueFromPipeline = $true,
    				   ValueFromPipelineByPropertyName = $true,
    				   ValueFromRemainingArguments = $false,
    				   Position = 0)]
    		[ValidateNotNullOrEmpty()]
    		[Alias('Identity')]
    		[string[]]$Username
    	)
    	
    	begin {
    		Write-Verbose -Message "[BEGIN  ] Starting: $($MyInvocation.Mycommand)"
    		
    		Write-Verbose -Message "[BEGIN  ] Finding All Domain Controllers"
    		$ADDomainControllers = Get-ADDomainController -Filter {
    			Name -like "*"
    		}
    		$NumberofDCs = ($ADDomainControllers | Measure-Object).count
    		Write-Verbose -Message "[BEGIN  ] Number of Domain Controllers Found: $NumberofDCs"
    	} #Begin
    	Process {
    		$lastLogon = 0
    		Foreach ($user in $Username) {
    			Write-Verbose -Message "[Process] Testing Username: $user"
    			foreach ($ADDomainController in $ADDomainControllers) {
    				$DCHostname = $ADDomainController.HostName
    				Write-Verbose -Message "[Process] Checking on Domain Controller: $DCHostname"
    				try {
    					$paramGetADUser = @{
    						Identity = $user
    						Server = $DCHostname
    						ErrorAction = 'Stop'
    						Properties = 'lastLogon'
    					}
    					
    					$ADUser = Get-ADUser @paramGetADUser
    				} #Try
    				Catch {
    					Write-Warning "Failed to Connect to Domain Controller: $DCHostname"
    				}
    				Write-Verbose -Message "[Process]`t Converting To DateTime"
    				$ADUserlastLogon = [DateTime]::FromFileTime($ADUser.lastLogon)
    				Write-Verbose -Message "[Process]`t LastLogon Date: $ADUserlastLogon"
    				
    				if ($ADUserLastLogon -gt $lastLogon) {
    					$lastLogon = $ADUserlastLogon
    				} # If Logon is GT
    			} #ForEach DC
    			
    			Write-Verbose -Message "[Process] Returning Result"
    			$props = @{
    				Username = $user
    				LastLogon = $lastLogon
    			}
    			return New-Object -TypeName System.Management.Automation.PSObject -Property $props
    			
    		} #Foreach User in Username
    	} #Process
    	End {
    		Write-Verbose -Message "[End    ] Ending:   $($MyInvocation.Mycommand)"
    	}
    } #Function
    
    Get-ADUserLastLogon -Username 'value1'
    

    Hope it helps

  • #80215

    edwin arlington
    Participant

    You can try this script:

    function Get-LastLogonTime 
    { 
     
        [CmdletBinding()] 
        Param( 
            [Parameter(Mandatory=$True, 
                        ValueFromPipeline=$true, 
                        ValueFromPipelineByPropertyName=$true)] 
            [String[]]$ComputerName 
        ) 
     
        BEGIN 
        { 
            Write-Host "" 
            Write-Verbose "Checking Users . . ." -Verbose 
        } 
     
        PROCESS 
        { 
            foreach ($Computer in $ComputerName) 
            { 
                if ( Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue ) 
                { 
                    Try 
                    { 
                        $Process = Get-WmiObject -Class Win32_Process -filter "Name = 'explorer.exe'" -ComputerName $Computer -ErrorAction Stop -Verbose:$false 
     
                        $Prop = [ordered]@{ 
                            'ComputerName' = $Computer 
                            'Status' = 'Connected' 
                            'UserName' = $Process.GetOwner().User 
                            'LogonTime' = ($Process.ConvertToDateTime($Process.CreationDate)) 
                            'SID' = $Process.GetOwnerSid().sid 
                        } 
                    } 
                    Catch 
                    { 
                        Write-Verbose "Couldn't get the process on the remote computer: $Computer . . ." 
                        $Prop = [ordered]@{ 
                            'ComputerName' = $Computer 
                            'Status' = 'Disconnected' 
                            'UserName' = $Null 
                            'LogonTime' = $Null 
                            'SID' = $Null 
                        } 
                    } 
                    Finally 
                    { 
                        $Obj = New-Object -TypeName PSObject -Property $Prop 
                        $obj.psobject.typenames.insert(0,'Get.Last.Logon.Time') 
                        Write-Output $Obj 
                    } 
                } 
                else 
                { 
                    Write-Warning "$Computer is offline ..." 
                } 
            } 
        } 
     
        END 
        { 
        } 
    }
    
    

    Additionally, you can also try this automated solution which assists to get last logon report.

  • #80219

    David Flores
    Participant

    One more interesting factoid about LastLogonTimestamp that you may not be aware of (and that I recently discovered much to my dismay). An update to LastLogonTimestamp can be triggered by a third party process that doesn't even possess the affected account's credentials!

    To see this in action try this: pick an account in your domain that hasn't logged in for some time (greater than 2 weeks). Now open up the security properties on some object with an ACL (a fileshare for instance). Now run an "effective permissions" against that account. Wait a few minutes and check the LastLogonTimestamp value for that account and you'll see that it got updated.

    And there are applications out there (such as SharePoint) that regularly run the equivalent of an "effective permissions" against large sets of users.

    I've lost a lot of faith in the validity of LastLogonTimestamp since learning this and really wish Microsoft would fix this issue.

You must be logged in to reply to this topic.