Active Directory How-To pages

Active Directory Auditing Tool

Get a comprehensive history of the logon audit trail of any user in your
Active Directory infrastructure

Get Your Free Trial Free, fully functional 30-day trial
Active Directory Auditing Tool

The Who, Where and When information is very important for an administrator to have complete knowledge of all activities that occur on their Active Directory. This helps them identify any desired / undesired activity happening. ADAudit Plus assists an administrator with this information in the form of reports. In real-time, ensure critical resources in the network like the Domain Controllers are audited, monitored and reported with the entire information on AD objects - Users, Groups, GPO, Computer, OU, DNS, AD Schema and Configuration changes with 200+ detailed event specific GUI reports and email alerts.

Get a comprehensive history of the logon audit trail of any user in your
Active Directory infrastructure

Account Management » Active Directory How-To pages

How to check all users' login history in Active Directory?

Use the following script to list the AD users logon information, including the computers from which they logged on by inspecting the Kerberos TGT Request Events(EventID 4768) from domain controllers.You can also list the users who had logged on previously.

Define the following parameters to suit your need:

MaxEvent :Specify the number of all events to search for TGT

Requests:Default is 1000.

LastLogonOnly:Display only the list of users' last logon.

OuOnly:Do not display the full path of users/computers. Only OU is displayed.

param( [switch]$LastLogonOnly,[switch]$OuOnly,[int]$MaxEvent=1000)
requesting Kerberos TGT, skipping Exchange Health Mailbox request and extracting Users/Client names,IP Addresses ####
$Domain = (Get-WmiObject Win32_Computersystem).domain
$read_log={
Param ($MaxEvent,$OuOnly,$Domain)
## Define parameter to pass maxevent to scripblock
$EventInfo=Get-WinEvent -FilterHashTable
@{LogName="Security";ID=4768} -MaxEvents 200000 | select -first
$MaxEvent | where {$_.Message -notmatch "SM_" } | where { $_.Message -notmatch "\$" } |
select @{N="Authenticated DC";Exp={$_.MachineName}},
@{N="LoggedOn Time";Exp={$_.TimeCreated}},
@{N="User"; Exp={ $SplitAccountName=(($_.Message -Split "\n") -match
"Account Name") -split
':';$SplitAccountName[$SplitAccountName.Length-1].Trim() }},
@{N="User Location";Exp={}}, @{N="Workstation";Exp={}},
@{N="IP Address"; Exp={if((($_.Message -split "\n") -match "Client
Address:").Trim() -match "::1" ) {"localhost"}
else { $SplitClientAddress=(($_.Message -Split "\n") -match "Client
Address") -split ':'; $splitClientAddress[$splitClientAddress.Length-1].Trim() }}},
@{N="Computer Location";Exp={}}

$EventInfo | foreach {
$IPAddress=$_."Client Address"

if ($_."IP Address" -eq "localhost") {
$Client_Name=[system.net.dns]::GetHostbyName($env:computername).hostname }
else
{###### Resolve the PTR record to find AD computer information ################
#$Client_Name=(Resolve-DnsName $_."IP Address").NameHost
if ((Resolve-dnsname $_."IP Address" -Type PTR -TcpOnly -DnsOnly -ErrorAction "SilentlyContinue").Type -eq "PTR")
{
$Client_Name = (Resolve-dnsname $_."IP Address" -Type PTR -TcpOnly -DnsOnly).NameHost
}
else
{ $Client_Name = "NOT FOUND" }
} ## $_."Authenticated DC"=($_."Authenticated DC" -split "."+$Domain)[0]
##Uncomment this line if you want to strip off domain name in
"Authenticated DC" list
$user=$_.user
############# Find the User account in AD and if not found, throw an exception ###########
$Full_User_Property=0
Try ##
Need Try statement to test and supress error
{
$Full_User_Property = (Get-AdUser $_.user -Properties *)
$_."User Location" =
$Full_User_Property.CanonicalName.TrimStart($Domain).SubString(1)
} catch {}
## The $_."User Location" is not passed to catch statement and therefore needs another statement (mentioned below) to set value
If (!$Full_User_Property)
{ $_."User Location"="NOT FOUND" }
$Full_User_Property=0

If($OuOnly -AND ($_."User Location" -ne "NOT FOUND"))
{
$_."User Location"= $_."User Location".Remove($_."User Location".LastIndexOf("/"))
##Trim the last user nameif -OuOnly flag is set
}$_."Workstation"=($Client_Name -split "."+$Domain)[0] ## remove the domain suffix
########## Find the Computer account in AD and if not found, throw an exception ###########
$Full_Workstation_Property = 0
{
$Full_Workstation_Property = Get-AdComputer $_."Workstation" -Properties *
$_."Computer Location"=
$Full_Workstation_Property.CanonicalName.TrimStart($Domain).SubString(1)
}
catch
{}
########## Here the catch exception does not work in Invoke session. So we need to manually set the "NOT FOUND" value ######
If (!$Full_Workstation_Property)
{ $_."Computer Location" = "NOT FOUND"}
$Full_Workstation_Property=0

If ($OuOnly -AND ($_."Computer Location" -ne "NOT FOUND"))
##Trim the last computer if -OuOnly flag is set
{
$_."Computer Location"=$_."Computer
Location".Remove($_."Computer Location".LastIndexOf("/"))
}
Return $_
}
}

########### Job starts to query replica domain controllers #############
$result=@()
$RemoteJob=@()
## Make array of remote jobs

$DomainControllers = (Get-ADDomainController -Filter { isGlobalCatalog -eq $true -or isGlobalCatalog -eq $false}).Name
############### Start the Local Job and Remote Job to find the event id ################
$LocalJobExists=0
If ($DomainControllers -contains $(hostname))
## Check if the computer running the script is Domain Controller itself
{
$LocalJob = Start-Job -scriptblock $read_log -ArgumentList
$MaxEvent,$OuOnly,$Domain;$LocalJobExists=1 ## If so, start job to query local domain controller
}

$DomainControllers | where {$_ -ne $(hostname)} | foreach {
## Start remote jobs on everydomain controller
$RemoteJob+= Invoke-Command -ComputerName $_ -ScriptBlock
$read_log -ArgumentList $MaxEvent,$OuOnly,$Domain -AsJob
}

If ($LocalJobExists)
{
$result = $LocalJob | Wait-Job | Receive-Job; Remove-Job $LocalJob
## If the computer running the script is not a domain controller(RSAT is installed), then all jobs will be remote jobs
}

$RemoteJob | foreach { $result+=$_ | Wait-Job | Receive-Job ;
Remove-Job $_} ## Wait and Receive remote jobs on each remote DC and add to Local job result

If ($LastLogonOnly)
{
$result | Sort-Object "LoggedOn Time" -Descending | Group-Object User | foreach { $_ | Select -ExpandProperty Group | select * -First 1 -ExcludeProperty PsComputerName,RunSpaceID,PsShowComputerName } ## the Last LoggedOn time of Each User
}
else
{
$result | Sort-Object "LoggedOn Time" -Descending | Select * -ExcludeProperty PsComputerName,RunSpaceID,PsShowComputerName ## Normal Results
}