powershell script - timegenerated in security log - powershell

i need some help with this code, as i'm a super-beginner with powershell but trying to get a report to my manager who is looking to see failed external attempts to remote into our system.
trying to pull out 4625 events from the security log and get the following fields into a csv file: Username (if it's an internal user), date of event, origin IP. I have this code so far based on what i could find (a.k.a. leech) online and customized a bit. everything is correct at this point except for the date (timegenerated). and i believe it's because of the replacementstring number listed. it's pulling the SubjectUserSid from the log. i'm not quite sure i understand how to find that replacementstring number, so maybe if someone can explain that to me, that would help.
thanks
$Date = [DateTime]::Now.AddDays(-1)
$Server = "SERVER"
$logName = '{0}{1}_security4625_log.csv' -f "C:\temp\",
$Date.tostring("MM-dd-yyyy_HH,mm,ss")
Get-EventLog -LogName 'Security' -Computer $Server `
-InstanceId 4625 `
-After $Date |
Select-Object #{
Name='TargetUserName'
Expression={$_.ReplacementStrings[5]}
},
#{
Name='WorkstationName'
Expression={$_.ReplacementStrings[1] -replace '\$$'}
},
#{
Name='IpAddress'
Expression={$_.ReplacementStrings[-2]}
},
#{
Name='TimeGenerated'
Expression={$_.ReplacementStrings[0]}
} |
Export-Csv -Path $logName -NoTypeInformation

Change the #{Name='TimeGenerated';Expression={$_.ReplacementStrings[0]} to simply TimeGenerated and you should be all set.
The ReplacementStrings are the variables from the Message field. Such as, the following log entry:
EventID : 4656
MachineName : AmazingLaptop.ChinchillaFarm.com
Data : {}
Index : 23277285
Category : (12804)
CategoryNumber : 12804
EntryType : FailureAudit
Message : A handle to an object was requested.
Subject:
Security ID: S-1-5-21-2127521184-6397854128-1234567890-12345678
Account Name: TMTech
Account Domain: ChinchillaFarm
Logon ID: 0xb8f705b
Object:
Object Server: SC Manager
Object Type: SERVICE OBJECT
Object Name: Schedule
Handle ID: 0x0
Resource Attributes: -
Process Information:
Process ID: 0x2b4
Process Name: C:\Windows\System32\services.exe
Access Request Information:
Transaction ID: {00000000-0000-0000-0000-000000000000}
Accesses: %%7186
%%7188
Access Reasons: -
Access Mask: 0x14
Privileges Used for Access Check: -
Restricted SID Count: 0
Source : Microsoft-Windows-Security-Auditing
ReplacementStrings : {S-1-5-21-2127521184-6397854128-1234567890-12345678, TMTech, ChinchillaFarm, 0xb8f705b...}
InstanceId : 4656
TimeGenerated : 11/20/2015 11:06:39 AM
TimeWritten : 11/20/2015 11:06:39 AM
UserName :
Site :
Container :
The ReplacementStrings are the values for all the fields like 'Security ID', 'Account Name', and 'Account Domain' within the Message property. Instead using one of those for the date/time you can just use the TimeGenerated property and it'll work just as well for your CSV.
Updated script:
$Date = [DateTime]::Now.AddDays(-1)
$Server = "SERVER"
$logName = '{0}{1}_security4625_log.csv' -f "C:\temp\",
$Date.tostring("MM-dd-yyyy_HH,mm,ss")
Get-EventLog -LogName 'Security' -Computer $Server `
-InstanceId 4625 `
-After $Date |
Select-Object #{
Name='TargetUserName'
Expression={$_.ReplacementStrings[5]}
},
#{
Name='WorkstationName'
Expression={$_.ReplacementStrings[1] -replace '\$$'}
},
#{
Name='IpAddress'
Expression={$_.ReplacementStrings[-2]}
},
TimeGenerated |
Export-Csv -Path $logName -NoTypeInformation

Related

Get-WinEvent and Select-string filter line result

I´m trying to use get-winevent + select string to filter and get the IP from events 4625.
After get-winevent I want to filter the results to show only "Source Network Address:" line, which will provide me the list of IP´s I need to block.
Below is an example of the results, thanks in advance!
PS C:\Users\Administrator> Get-WinEvent -FilterHashtable #{LogName='Security';ID=4625} -MaxEvents 1 | fl
TimeCreated : 15/02/2023 07:43:25
ProviderName : Microsoft-Windows-Security-Auditing
Id : 4625
Message : An account failed to log on.
Subject:
Security ID: S-1-0-0
Account Name: -
Account Domain: -
Logon ID: 0x0
Logon Type: 3
Account For Which Logon Failed:
Security ID: S-1-0-0
Account Name: ADMINISTRATOR
Account Domain:
Failure Information:
Failure Reason: Unknown user name or bad password.
Status: 0xC000006D
Sub Status: 0xC0000064
Process Information:
Caller Process ID: 0x0
Caller Process Name: -
Network Information:
Workstation Name: -
Source Network Address: 209.45.48.94
Source Port: 0
Detailed Authentication Information:
Logon Process: NtLmSsp
Authentication Package: NTLM
Transited Services: -
Package Name (NTLM only): -
Key Length: 0
Get-WinEvent -FilterHashtable #{LogName='Security';ID=4625} -MaxEvents 100 | Select-String -Pattern "Source Network Address:" tried this way but no results showed
(Get-WinEvent -FilterHashtable #{LogName='Security';ID=4625} -MaxEvents 1).Message.split(':') -split("`t") | ? { $_ -match '\d+\.\d+\.\d+.\d+'} | % {$_ -replace ("`n","")}
As it seems you need to extract an IP-address, I would suggest to use a regex for matching it.
$regex = [regex]::new("\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b")
Get-WinEvent -FilterHashtable #{LogName='Security';ID=4625} -MaxEvents 100 | Foreach {$regex.Match($_.Message).Value}
This code loops through each result which Get-WinEvent returns and checks with the regex for an IP-address in the message property. When no match is found it will return an empty line.
To get information from the Windows Event log, it is cumbersome to try and parse that out of the Message string.
Better look at the XML where the values can be found under their own attribute names:
$result = Get-WinEvent -FilterHashtable #{LogName='Security';ID=4625} -MaxEvents 100 | ForEach-Object {
# convert the event to XML and grab the Event node
$eventXml = ([xml]$_.ToXml()).Event
# output the values from the XML representation
[PsCustomObject]#{
UserName = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
IpAddress = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'IpAddress' }).'#text'
EventDate = [DateTime]$eventXml.System.TimeCreated.SystemTime
}
}
Now, if all you want from this is the list of IP addresses, just do
$result.IpAddress
Thank you all, for quick reply!

How to print process ıd in event log?

Im trying to get process id from my Get-Eventlog. I can not parse the process id from the message. How ı can get it from there ? I tried With Select string -Pattern but it did not worked. My powershell code :
$directory = E:\BpLnfgDsc2.txt
$message = Get-EventLog -log Security -InstanceId 4663 -Newest 1 | Where {$_.message -match "Object Name:\s*$directory"} | foreach {$_.Message}
And here is my output:
PS C:\WINDOWS\system32> $message
An attempt was made to access an object.
Subject:
Security ID: Some-id
Account Name: tester
Account Domain: DESKTOP
Logon ID: Some-Id
Object:
Object Server: Security
Object Type: File
Object Name: E:\BpLnfgDsc2.txt
Handle ID: Some-Id
Resource Attributes: S:AI
Process Information:
Process ID: 0xd34
Process Name: C:\Windows\explorer.exe
Access Request Information:
Accesses: %%4423
Access Mask: 0x80
My expected output:
0xd34
You can extend your regex matching pattern a bit more to also capture the process ID and output it with the automatically populated variable $matches.
I've chosen a capture group name for clarity, you could also just use number captured groups. I also added (?s) at the beginning of the pattern to treat the multiline message string as a single line
$message = Get-EventLog -log Security -InstanceId 4663 -Newest 1 |
Where-Object {$_.message -match "(?s)Object Name:\s*$directory.+Process ID:\s+(?<ProcessID>\S+)"} |
ForEach-Object {$matches.ProcessID}

Powershell to count and group Event ID 4625?

How can I get the total number of Event ID error 4625 and for each and every Windows Server in my AD domain using the below Powershell script?
$DCServers = Get-ADDomainController -filter * | select -ExpandProperty hostname
$events = #()
$totalCt = 0
$servers = #()
Foreach ($Server in $DCServers)
{
Write-Host "Calling Get-WinEvent for $Server"
$serverEvents = Get-WinEvent -ComputerName $Server -FilterHashtable #{ logname = 'Security'; id = 4625 } -EA 0
if (!$?)
{
Write-Host "Get-WinEVent failure for $Server"
continue
}
if ($null -ne $serverEvents)
{
$totalCt += $serverEvents.Count
$servers += [PsCustomObject] #{ $server = $serverEvents.Count }
Write-Host $server $serverEvents.Count
}
$serverEvents | ForEach-Object {
$events += [PsCustomObject] #{
Date = $_.TimeCreated
"Event Id" = $_.Id
"User Name" = $_.Properties[6].Value + "\" + $_.Properties[5].Value ## fixed
"IPAddress" = $_.Properties[21].Value
"FailureReason" = (($_.message -split "\n") | Select-String -Pattern "Failure Reason:\s+(.+)").matches[0].groups[1].value
"Status Code" = $_.message -split '\s{4}' | Select-String -Pattern "Status"
"Logon Type" = $_.Properties[10].Value
"DC Logged On" = $_.Properties[13].value ## this is "workstation that processed the request", not the DC Logged On
}
}
}
$HTML = '<h1>Head</h1>'
$GetDate = Get-Date
$Report = 'C:\clu\temp-4625.html'
#convert the array of events to HTML
$Events |
Select-Object Date, "Event Id", "User Name", "FailureReason", "Status Code", "DC Logged On", "Logon Type" |
Convertto-html -head $HTML -PreContent "<H2>Accounts that Failed to Log On</H2>", "<H2>$GetDate </H2>" -PostContent "<p></p>Total 4625 records: $totalCt <p></p>" |
Out-File $Report -append
Write-Host "Total 4625 records: $totalCt"
Write-Host "4625 records per server:"
$servers | ft -auto
Write-Host "4625 records grouped by user"
$events | group "User Name" | sort Count
The goal is to see which servers have Event 4625 and group it by the content to see which IP or AD account failed logins where possible?
Before digging into how to extract the workstation IP address and how to group the events by specific properties, let me suggest rewriting your existing code slightly, given your goal.
Doing $event = New-Object psobject |Select listOfPropertyNames and then assigning the values to each property separately is going to be slow - something I imagine you might want to avoid if you have many servers to query.
Since PowerShell 3.0, we can instantiate a new custom object in one go with the following syntax:
$newObject = [pscustomobject]#{
PropertyName = "Value"
}
So, refactoring your existing code, we end up with something like:
$events += [pscustomobject]#{
Date = $_.TimeCreated
"Event Id" = $_.Id
"User Name" = $_.Properties[5].Value + "\" + $_.Properties[6].Value
"FailureReason" = (($_.Message -split "\n") | Select-String -Pattern "Failure Reason:\s+(.+)").Matches[0].Groups[1].Value
"Status Code" = $_.Message -split '\s{4}' | Select-String -Pattern "Status"
"Logon Type" = $_logontype[ [int] $_.Properties[10].Value ]
"DC Logged On" = $_.Properties[13].Value
}
Another change we might wanna make is change the data type of $events - when you instantiate an empty array with #(), PowerShell will allow you to add new items to the array with +=, but there's a catch - arrays are of a fixed size, so if you keep adding new items via +=, PowerShell will have to stop and resize the array by creating a larger underlying array and then copying the existing array items into the new, larger array. This obviously takes some time and might incur unnecessary memory acquisition as well.
To work around this, use a list instead - lists are designed with dynamic sizing in mind, so will perform better even when you add a 1000s of items to it:
$events = New-Object 'System.Collections.Generic.List[psobject]'
Now, back to the question - how to group all the events by IP address - first of all, we need to extract the workstation IP address in order to me able to group on it later, so let's add an extra property to the custom object we created:
$events += [pscustomobject]#{
# ...
IPAddress = $_.Properties[21].Value
}
Now that the IPAddress is present, grouping the objects based on it is as simple as:
$events | Group-Object IPAddress
Note that you can also get these fields from the xml of the event:
$a = Get-WinEvent -Max 1 #{logname='Security'; id=4625}
$xml = [xml]$a.ToXml()
$xml.event.EventData.data
Name #text
---- -----
SubjectUserSid S-1-5-18
SubjectUserName COMP$
SubjectDomainName DOM
SubjectLogonId 0x3e7
TargetUserSid S-1-0-0
TargetUserName admin
TargetDomainName COMP
Status 0xc000006d
FailureReason %%2313
SubStatus 0xc000006a
LogonType 7
LogonProcessName User32
AuthenticationPackageName Negotiate
WorkstationName COMP
TransmittedServices -
LmPackageName -
KeyLength 0
ProcessId 0xa60
ProcessName C:\Windows\System32\svchost.exe
IpAddress 127.0.0.1
IpPort 0
Compare with .Properties
$a.properties
Value
-----
S-1-5-18
COMP$
DOM
999
S-1-0-0
admin
COMP
-1073741715
%%2313
-1073741718
7
User32
Negotiate
COMP
-
-
0
2656
C:\Windows\System32\svchost.exe
127.0.0.1
0

How do I delete duplicate information on the output log in PowerShell

Hi I'm am really new to the Powershell scene, currently I am working on a simple task related to IIS, where I have to retrieve every "information" event and write it to a file.
Thing is, it writes a lot of repeated info and I want it to write only the most recent events
here's the original output:
20/05/2020 16:49:09 Application-Info STARTED
Filtering 'Information/Warning Levels' related to IIS
Provider Name: Microsoft-Windows-WAS
Time Created ** : 12/05/2020 14:57:20
**Id ** : 5186
**LevelDisplayName : Information
TimeCreated : 12/05/2020 10:42:36
Id : 5186
LevelDisplayName : Information
TimeCreated : 08/05/2020 15:18:07
Id : 5186
LevelDisplayName : Information
TimeCreated : 08/05/2020 10:57:38
Id : 5186
LevelDisplayName : Information
TimeCreated : 07/05/2020 20:20:54
Id : 5211
LevelDisplayName : Information
here's the PS script:
Clear-Host
Remove-Item E:\www\EvApp_Info_Logs\Application-info*.txt
$log = "E:\www\EvApp_Info_Logs\Application-info-$(get-date -f yyyy-MM-dd_hh-mm).txt"
$(Get-Date).ToString() + " Application-Info STARTED" | out-file -FilePath $log -Append
"Filtering 'Information/Warning Levels' related to IIS" | out-file -FilePath $log -Append
Get-WinEvent -FilterXml ([xml](Get-Content C:\WEBIIS-content-information.xml))|
fl -GroupBy ProviderName -Property TimeCreated, Id, LevelDisplayName |
Out-File -FilePath $log -Append
$(Get-Date).ToString() + " Application-Info ENDED" | out-file -FilePath $log -Append
If I use the "get-unique" cmdlet right after
"Get-WinEvent -FilterXml ([xml](Get-Content C:\WEBIIS-content-information.xml))|
fl -GroupBy ProviderName -Property TimeCreated, Id, LevelDisplayName, Message | get-unique"
it writes only the latest info related to every ProviderName, ignoring the rest of the EventId's.
What I want is for the script to ignore repeated EventId's so the output can look like this:
20/05/2020 16:49:09 Application-Info STARTED
Filtering 'Information/Warning Levels' related to IIS
ProviderName: Microsoft-Windows-WAS
TimeCreated ** : 12/05/2020 14:57:20
**Id ** : 5186
**LevelDisplayName : Information
TimeCreated : 07/05/2020 20:20:54
Id : 5211
LevelDisplayName : Information
Once again I'm really new in this, any help will be appreciated.
Actually, fl requires a sorted list. Also, we use Sort-Object to group by (ProviderName and) Id to eliminate duplicates on other properties.
$list | Sort-Object ProviderName, Id -Unique | fl -GroupBy ProviderName -Property TimeCreated, Id, LevelDisplayName

Getting values from get-eventlog Powershell call

Sorry to ask such a question, but I've spent 1/2 hour on this and no good solution.
I want to get the latest date from the Event Log for a particular app. So far, my code is:
$event = get-eventlog -logname 'Windows PowerShell' -source mpkLogParser -newest 1 | Format-List
echo $event
this yields:
Index : 51
EntryType : Information
InstanceId : 3001
Message : MPKLogParser successfully parsed the log file u_ex100118.log
Category : (1)
CategoryNumber : 1
ReplacementStrings : {MPKLogParser successfully parsed the log file u_ex100118.log}
Source : mpkLogParser
TimeGenerated : 1/28/2010 11:24:08 AM
TimeWritten : 1/28/2010 11:24:08 AM
UserName :
So how do I extract the TimeWritten part from $event?
Any help with this and I can sleep better. :)
Don't use Format-List unless you are displaying to the host. That is, don't use Format-List when assigning to a variable. Try this:
$name = 'Windows PowerShell'
$event = get-eventlog -logname $name -source mpkLogParser -newest 1
$event.TimeWritten