Powershell - Get-WinEvent Replace Text - powershell

I have a large script which looks at certain event logs. Part of it is the following command:
Get-EventLog -ComputerName $computer -InstanceId 4625 -LogName Security -After $date -ErrorAction Stop | Select TimeWritten,#{n='Reason for Failure';e={$_.ReplacementStrings[8]}}
I receive the following output:
TimeWritten Reason for Failure
----------- ------------------
08/05/2018 10:55:06 %%2313
08/05/2018 09:19:24 %%2313
08/05/2018 07:49:22 %%2304
08/05/2018 07:49:22 %%2304
Is it possible to change the output in the reason for failure column to some other message. I know of the -replace operator but I am struggling on how to incorporate this?

This should get you headed in the right direction:
$failures = #{'%%2313' = 'Unknown User Name or Bad Password';
'%%2304' = 'An Error occured during Logon'
}
Get-EventLog -ComputerName $computer -InstanceId 4625 -LogName Security -After $date -ErrorAction Stop | Select TimeWritten,#{n='Reason for Failure';e={$failures[$_.Message]}}
Change $_.Message to be whichever field has the error code.

Related

Powershell code to filter login/logout times (id 7001, 42)

I am trying to create code in Powershell that will track the user login/logout times with the id codes of 7001 (login), and 42 (computer goes to sleep), and then export it as a csv.
My current problem is that sometimes the user will login/logout throughout the day, but I just want the earliest login and latest logout so I can track the total hours.
My current code works, but it gets every login/logout events of the day, seen below:
$startDate = (get-date).AddDays(-1)
$FileName = "Y:\Powershell_ " + $startDate.ToString('MMddyy') + ".csv"
$log_time = get-WinEvent -FilterHashtable #{logname='system';id='7001', '42'}
$log_time| Select Id, MachineName, Message, TimeCreated | export-csv $FileName
Thank you in advance
You have to filter by the day you working on first.
Since you can catch the output of a for each loop with a parameter, this is a way you can achieve your goal:
$startDate = (get-date).AddDays(-1).GetDateTimeFormats()[0]
$FileName = "somepath.csv"
$log_time = get-WinEvent -FilterHashtable #{logname='system';id='7001', '42'}
$daily_events = foreach($event in $log_time)
{
if ($event.timecreated.GetDateTimeFormats()[0] -like "*$startDate*"){$event}
}
$daily_events | Select Id, MachineName, Message, TimeCreated | export-csv -Path $Filename
You can add this to track about the first and last while execution:
#The sort is by default from newer to older
$first_event = $daily_events[-1].TimeCreated #last element of the array
$last_event = $daily_events[0].TimeCreated #first element of the array
Write-Host "First event was $first_event in and the last event was in $last_event"
You can use Get-Eventlog to make sure only events from the current day are retrieved. From there:
$Results =[System.Collections.Generic.List[PSObject]]::new()
$Date = (get-date).Date
$FirstLogin = Get-EventLog -LogName System -InstanceId 7001 -After $Date -Before $Date.AddDays(1) | Select -Last 1
$LastLogout = Get-EventLog -LogName System -InstanceId 42 -After $Date -Before $Date.AddDays() -Newest 1
$Results.Add($FirstLogin)
$Results.Add($LastLogout)
$Results | Select Id, MachineName, Message, TimeCreated | export-csv -Path $Filename

Apply conditional to output of a commandlet

I want to output the result of the commandlet (Invoke-Command) on success and add a custom message if the result is null. The code as shown below produces the desired results except in the event of a null response, it simply outputs nothing on that line.
I can not pipe directly to an if statement, nor can I output on 2 opposing conditions (True & False). Is it possible to get a custom response on $null while not suppressing the normal output on success?
Invoke-Command -ComputerName PC1, PC2, PC3 -Scriptblock {get-eventlog system | where-object {$_.eventid -eq 129} | select MachineName, EventID, TimeGenerated, Message -last 1}
If you run the example code block assuming that PC1 and PC3 have the event ID but PC2 does not, the output will simply skip PC2.
I want to output something like "Event Not found" in that case.
Placing the entire thing in a loop and then running the results through another conditional loops destroys performance so that is not an ideal solution.
I would create a new object for returning from Invoke-Command. So you are sure you will receive from every host something even the event log is not present. And might you can change get-eventlog to Get-WinEvent. Get-WinEvent was for my tasks the most time faster than get-eventlog.
[System.Management.Automation.ScriptBlock]$Scriptblock = {
[System.Collections.Hashtable]$Hashtable = #{
WinEvent = Get-WinEvent -FilterHashtable #{ LogName = 'System'; Id = 129 } -MaxEvents 1 -ErrorAction SilentlyContinue #-ErrorAction SilentlyContinue --> otherwise there is an error if no event is available
}
return (New-Object -TypeName PSCustomObject -Property $Hashtable)
}
Invoke-Command -ComputerName 'PC1', 'PC2', 'PC3' -Scriptblock $Scriptblock

Powershell: How can I extract time from the message field of eventlog?

I'm trying to get unexpected shutdown times of Windows Sever 2008 machines via Get-EventLog in Powershell. I can get close by searching for events with an EventID of 6008 and selecting only message, but I need to parse within the field to grab the time it occurred (not the time the event fired).
I've tried to use replacementstrings[x] but I can't find how to specify the field to use (messages) and can't get a result.
get-eventlog -LogName System -ComputerName svr-name | Where-Object {$_.EventID -eq 6008 -AND $_.timegenerated -gt (get-date).adddays(-30)}| select message
Produces this:
Message
-------
The previous system shutdown at 3:35:32 AM on ‎7/‎29/‎2014 was unexpected.
The previous system shutdown at 3:40:06 PM on ‎7/‎10/‎2014 was unexpected.`
Retrieving all events from a remote host and filtering them on the local machine ususally doesn't perform too well, because that way you transmit tons of unrelated events over the network, just to throw them away. Get-EventLog has options for filtering messages by Event ID or before/after a given timestamp on the source, so better use those for pre-selecting the messages you're actually interested in. The timestamp of the crash can be extracted from the Message field with a regular expression and parsed into a DateTime value via ParseExact():
$log = 'System'
$server = 'svr-name'
$id = [uint64]"0x80000000" + 6008
$date = (Get-Date).AddDays(-30)
$fmt = 'h:mm:ss tt on M\/d\/yyyy'
$culture = [Globalization.CultureInfo]::InvariantCulture
Get-EventLog -LogName $log -ComputerName $server -InstanceId $id -After $date | ? {
$_.Message -match 'at (\d+:\d+:\d+ [ap]m on \d+/\d+/\d+) was unexpected'
} | select MachineName, TimeGenerated,
#{n='Crashtime';e={[DateTime]::ParseExact($matches[1], $fmt, $culture)}}
The pipeline produces a list of objects with the properties MachineName, TimeGenerated and Crashtime (the last one being a calculated property). If you collect the output of the pipeline in a variable (e.g. $evt) you can access the Crashtime property of the third object like this:
$evt = .\script.ps1
$evt[2].Crashtime
Using regex, you can pull it out as such.
$Messages = (get-eventlog -LogName System -ComputerName svr-name | Where-Object {$_.EventID -eq 6008 -AND $_.timegenerated -gt (get-date).adddays(-30) }| select message)
$Messages | ForEach-Object {
$Matched = $_.Message -match "([0-9]{1,2}:.*[0-9]{4})"
if ($Matched) {
Write-Output "System rebooted at $($Matches[1])"
}
}
There might be a better way, but I do not know what :)
Example Output from my System
System rebooted at 4:34:30 PM on ‎4/‎20/‎2014
System rebooted at 1:48:38 PM on ‎1/‎21/‎2014
System rebooted at 1:37:12 PM on ‎1/‎21/‎2014
System rebooted at 1:22:01 PM on ‎1/‎21/‎2014
System rebooted at 4:41:21 PM on ‎11/‎22/‎2013
More easy
get-eventlog system | where-object {$_.EventID -eq "6008"} | fl

PowerShell (Eventlogs: How to compare dates/time?)

Till now I never used PowerShell, but now I have to. (Don’t worry I know how to program in other languages.)
What I have to do:
There are 2 eventlogs:
“EventID equals 3317 and Event Level equals Error" and "EventID equals 3317 and Event Level equals Information"
If there is an event with the level “Error” without an event with the level “Information” afterwards, then the output has to be “Critical”.
If there is an event with the level “Information” after this event with the level “Error” the output has to be “Ok”.
(If there is no event with that ID everything is "Ok".)
Now the problem is that I don’t know how to compare both date values I get from those lines...
get-eventlog -log application -EntryType error –newest 1 | where {$_.eventID -eq 3317}
get-eventlog -log application -EntryType information –newest 1 | where {$_.eventID -eq 3317}
Other solutions are appreciated as well. ;)
Greetings,
Cédric
EDIT (The code):
#Error:
$e_error = (get-eventlog -log application -EntryType error | where {$_.eventID -eq 3317} | Select -First 1).TimeGenerated
write-host "Error: $e_error"
#Information:
$e_info = (get-eventlog -log application -EntryType information | where {$_.eventID -eq 3317} | Select -First 1).TimeGenerated
write-host "Information: $e_info"
if (($e_error) -and ($e_info)) { #If $e_error (Error) & $e_info (Information) are not empty (events exists)
$timediff = (new-timespan –start $e_error -end $e_info).TotalSeconds #Difference
if ($timediff -gt 0) { #If $e_info (Information) newer than $e_error (Error)
$res = "Ok"
} else { #If one of them or both are empty
$res = "Critical"
}
} else {
if (($e_error) -and (!($e_info))) { #If $e_error (Error) exists but not $e_info (Information)
$res = "Critical"
} else { #If non of both or only Information exists
$res = "Ok"
}
}
write-host $res
The TimeWritten or TimeGenerated values will give you dates and times to compare...
get-eventlog -log application -EntryType error –newest 1 | where {$_.eventID -eq 3317} | Select TimeGenerated, TimeWritten
You can also do this to just pull that attribute
(get-eventlog -log application -EntryType error –newest 1 | where {$_.eventID -eq 3317}).TimeGenerated
The other recommendation I'd make is to filter the events prior to selecting the last error. Otherwise you may miss an entry if another error occurs in quick succession. So the basis of your query should look like this:
get-eventlog -log application -EntryType error | where {$_.eventID -eq 3317} | | Select -First 1

Powershell: filtering event logs

Ive written a small script to retreive event logs from application for the last 10 days but i receive the error. Any ideas why the error appear?
Where-Object : Cannot bind parameter 'FilterScript'. Cannot convert
value "False" to type "System.Management.Automation.ScriptBlock".
Error: "Invalid cast from 'System.Boolean' to
'System.Management.Automation.ScriptBlock'."
#Sets the application log to query
$Log ="Application"
$FilterHashTable = #{LogName=$Log}
#stores the computer name
$ComputerName = $env:COMPUTERNAME
#sets the date 10 days ago
$DeleteDate = Get-Date
$DeleteDate = $DeleteDate.AddDays(-10)
Write-Verbose $DeleteDate
#retrieve WMIevent and logs the information
$Winevent = Get-WinEvent -ComputerName $ComputerName -FilterHashTable $FilterHashTable -ErrorAction SilentlyContinue
# Filter on time
$Winevent | where-object ($_.timecreated -gt $DeleteDate)
Where-Object needs a scriptblock parameter - use curly braces {...} not parentheses (...) to contain your filter logic.
Currently PS is checking your criteria and returning a boolean, instead of applying it as a filter.