|
#requires -version 5.1 |
|
#requires -module ActiveDirectory |
|
|
|
#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 |
|
#the format file should be in the same folder as this file. |
|
Update-FormatData -AppendPath $psscriptroot\adaudittrail.format.ps1xml |