Search code examples
powershellautomationactive-directory

Exporting last logon date for inactive users via PowerShell


I have a command that will export a list of users who have logged in for 12 months but I am struggling to export the last login date and time.

The command is as follows:

Search-ADAccount –AccountInActive -UsersOnly –TimeSpan 365:00:00:00 –ResultPageSize 2000 –ResultSetSize $null |?{$_.Enabled –eq $True} | Select-Object Name, SamAccountName, DistinguishedName, lastLogon| Export-CSV “C:\Users\Me\Desktop\InactiveUsers.CSV” –NoTypeInformation

But lastLogon is showing a blank in the CSV file.

I am new to PowerShell I understand the command can be made much smoother.

Any help on this is much appreciated.


Solution

  • Search-ADAccount doesn't have an option to pull other attributes from the AD Objects than the default ones, you can use Get-ADUser with an elaborate filter to query the users who haven't logged on for the past year. One option is to query the user's lastLogonTimeStamp attribute however by doing so you're risking not getting accurate results because this attribute is not replicated in real time. To get accurate results one must query the user's lastLogon attribute but, since this attribute is not replicated across the Domain, one must query all Domain Controllers to get the latest logon from the user.

    For more information on this topic, please check this excellent TechNet Article: Understanding the AD Account attributes - LastLogon, LastLogonTimeStamp and LastLogonDate.

    $dateLimit = [datetime]::UtcNow.AddYears(-1).ToFileTimeUtc()
    
    $AllDCs = Get-ADDomainController -Filter *
    $logons = @{}
    
    # NOTE:
    #    - Use `!` for Enabled objects only: "(!userAccountControl:1.2.840.113556.1.4.803:=2)"
    #      or remove the clause to find both, Enabled and Disabled users.
    #    - The "(lastLogon<=$dateLimit)" clause can be removed to find all users latest login.
    $params = @{
        LDAPFilter = -join @(
            '(&'                                                    # AND, all conditions must be met
                '(!samAccountName=krbtgt)'                          # exclude krbtgt from this query
                '(!samAccountName=Guest)'                           # exclude Guest from this query
                '(userAccountControl:1.2.840.113556.1.4.803:=2)'    # Disabled objects only
                "(lastLogon<=$dateLimit)"                           # lastLogon is below the limit
            ')'                                                     # close AND clause
        )
        Properties = 'lastLogon'
        # Add `SearchBase = "OUPath"` here if targeting a specific OU
    }
    
    foreach ($DC in $AllDCs) {
        $params['Server'] = $DC
    
        foreach ($user in Get-ADUser @params) {
            # this condition is always met on first loop iteration due to ldap filtering condition
            if ($logons[$user.samAccountName].LastLogon -lt $user.LastLogon) {
                $logons[$user.samAccountName] = $user
            }
        }
    }
    
    $logons.Values | ForEach-Object {
        [PSCustomObject]@{
            Name              = $_.Name
            SamAccountName    = $_.SamAccountName
            DistinguishedName = $_.DistinguishedName
            lastLogon         = [datetime]::FromFileTimeUtc($_.lastLogon).ToString('u')
        }
    } | Export-Csv 'C:\Users\Me\Desktop\InactiveUsers.CSV' -NoTypeInformation