functions/get-adlog.ps1
#an earlier version of this function can be found at https://gist.github.com/jdhitsolutions/a4e6291741ec95e3bfe53f15a380da47 <# you might need to increase the size of the Security eventlog limit-eventlog -LogName security -ComputerName dom2,dom1 -MaximumSize 1024MB #> Function Get-ADUserAudit { [cmdletbinding()] Param( [Parameter(Position = 0, HelpMessage = "Specify one or more domain controllers to query.")] [ValidateNotNullOrEmpty()] [string[]]$DomainController = (Get-ADDomain).ReplicaDirectoryServers, [Parameter(HelpMessage = "Find all matching user management events since what date and time?")] [Datetime]$Since = (Get-Date).Addhours(-24), [Parameter(HelpMessage = "Select one or more user account events")] [ValidateNotNullOrEmpty()] [ValidateSet("Created", "Deleted", "Enabled", "Disabled", "Changed")] [string[]]$Events = "Created", [Parameter(HelpMessage = "Specify an alterate credential")] [PSCredential]$Credential ) Function _getNames { # a private helper function to parse out names from the eventlog message [cmdletbinding()] Param( [Parameter(Mandatory, ValueFromPipeline)] [System.Diagnostics.Eventing.Reader.EventLogRecord]$Data ) Process { #convert the record to XML which makes it easier to parse [xml]$r = $data.toxml() #Target is the user account #Subject is the admin who performed the operation $target = "{0}\{1}" -f ($r.Event.EventData.Data.Where( { $_.name -eq 'TargetDomainName' }).'#text'), ($r.Event.EventData.Data.Where( { $_.name -eq 'TargetUserName' }).'#text') $admin = "{0}\{1}" -f ($r.Event.EventData.Data.Where( { $_.name -eq 'SubjectDomainName' }).'#text'), ($r.Event.EventData.Data.Where( { $_.name -eq 'SubjectUserName' }).'#text') [pscustomobject]@{ Target = $target Administrator = $admin TimeCreated = $data.timeCreated } } #process } # close _getNames # a hashtable of user management event IDs for the Security event log $ADEvent = @{ UserChanged = 4738 UserCreated = 4720 UserDeleted = 4726 UserEnabled = 4722 UserDisabled = 4725 } $EventIDs = @() Switch ($events) { "Created" { $EventIDs += $adevent.getenumerator().Where( { $_.name -match "created" }) } "Deleted" { $eventIDs += $adevent.getenumerator().Where( { $_.name -match "deleted" }) } "Enabled" { $eventIDs += $adevent.getenumerator().Where( { $_.name -match "enabled" }) } "Disabled" { $eventIDs += $adevent.getenumerator().Where( { $_.name -match "disabled" }) } "Changed" { $eventIDs += $adevent.getenumerator().Where( { $_.name -match "changed" }) } } #this hashtable filter will be used by Get-WinEvent $filter = @{LogName = 'Security'; ID = 0; StartTime = $Since } #parameters to eventually splat to Get-WinEvent $getParams = @{ ErrorAction = "Stop" FilterHashtable = $filter Computername = "" } if ($Credential.UserName) { $getParams.add("Credential", $Credential) } Write-Verbose "Searching for AD log entries since $since" #Searching the Security event log on each domain controller foreach ($dc in $DomainController) { Write-Verbose "Processing $dc" foreach ($evt in $eventIDs) { $filter.ID = $evt.value $getParams.FilterHashtable = $filter $getParams.Computername = $DC Write-Verbose "...Looking for $($evt.name) events" Try { $logs = Get-WinEvent @getParams Write-Verbose "Found $($logs.count) log records" } Catch { Write-Warning "No matching $($evt.name) events $since found on $dc." } if ($logs.count -gt 0) { $names = $logs | _getnames $targets = ($names | Select-Object -Property Target -Unique).target $admins = ($names | Select-Object -Property Administrator -Unique).administrator [pscustomobject]@{ PSTypeName = "ADAuditTrail" DomainController = $dc ID = $evt.Value EventType = $evt.Name LogCount = $logs.count Since = $Since Targets = $targets Administrators = $admins } Remove-Variable -Name logs } } } } #close function Update-TypeData -TypeName ADAuditTrail -MemberType ScriptProperty -MemberName TargetCount -Value { $($this.targets).count } -Force |