Get unique events from Event Log and their count - windows

I have a working script that is able to pull a report of Windows Application, Security, Setup and System logs that displays only the critical and error events in the past 30 days. However, I would also really like the script to count the number of times each reported critical or error event occurred in the past 30 days. Here's the working command:
Get-EventLog Application -ComputerName $server -After $starttime |
? { $_.entryType -Match "Error" -and "Critical" } |
Sort-Object EventID -Unique |
Select-Object TimeGenerated,EventID,Source,Message |
ft -AutoSize -Wrap |
Out-File $file -Append
And here is an example of the output in the text file:
TimeGenerated EventID Source Message
------------- ------- ------ -------
7/8/2016 1:23:20 PM 0 SQL Server Report Service Service cannot be started. Microsoft.ReportingS
ervices.Diagnostics.Utilities.InternalCatalogEx
ception: An internal error occurred on the repo
rt server. See the error log for more details.
at Microsoft.ReportingServices.Library.Nativ
e.GetSid(String name, Int32& length)
at Microsoft.ReportingServices.Library.Nativ
e.NameToSid(String name)
at Microsoft.ReportingServices.Library.Servi
ceAppDomainController.StartRPCServer(Boolean fi
rstTime)
at Microsoft.ReportingServices.Library.Servi
ceAppDomainController.Start(Boolean firstTime)
at Microsoft.ReportingServices.NTService.Rep
ortService.OnStart(String[] args)
at System.ServiceProcess.ServiceBase.Service
QueuedMainCallback(Object state)
7/8/2016 1:23:20 PM 121 Report Server Windows Service (MSSQLSERVER) The Remote Procedure Call (RPC) service failed
to start.
It would be great to have another column in the results that displays the occurrences of each EventID in the specified time period.

You could do it like so (line 3 & 4 are new and Count in Select-Object)
Technically you could also remove the -Unique from Sort-Object as after grouping them and passing through only the first item of the group is more or less the same.
Get-EventLog Application -ComputerName $server -After $starttime |
? { $_.entryType -Match "Error" -and "Critical" } |
Group-Object -Property EventID |
% { $_.Group[0] | Add-Member -PassThru -NotePropertyName Count -NotePropertyValue $_.Count } |
Sort-Object EventID -Unique |
Select-Object Count, TimeGenerated, EventID, Source, Message |
ft -AutoSize -Wrap |
Out-File $file -Append

Related

Why sometimes powershell cmdlet "select-string" does not return any value?

This command works, logfolder contains several log files, select-string will search on each file and look for the -pattern 'update'
get-childitem -recurse C:\logfolder -file | select-string -pattern "update"
But this other line won't work, it won't return any results
get-eventlog -logname system -entrytype error | select-string -pattern "terminated"
I am 100% positive that there is an event with the string "terminated", maybe I am missing some concepts here.
select-string converts the input object to a string. Unfortunately with get-eventlog this isn't very helpful. By the way, get-eventlog has been replaced by get-winevent.
get-eventlog -logname system -entrytype error | select -first 1
Index Time EntryType Source InstanceID Message
----- ---- --------- ------ ---------- -------
63255 Aug 31 07:44 Error Microsoft-Windows... 1129 The processing of Group Policy failed because o...
get-eventlog -logname system -entrytype error | select -first 1 | % { "$_" }
System.Diagnostics.EventLogEntry
get-eventlog -logname system -entrytype error | select -first 1 | select-string log
System.Diagnostics.EventLogEntry
get-eventlog -logname system -entrytype error | select -first 1 |
where message -match processing
Index Time EntryType Source InstanceID Message
----- ---- --------- ------ ---------- -------
63255 Aug 31 07:44 Error Microsoft-Windows... 1129 The processing of Group Policy failed because of lack of network connectivity to a domain controller. This may be a transient cond...
get-winevent #{logname='system';level=2} -maxevents 1 |
? message -match processing | ft -GroupBy logname
ProviderName: System
TimeCreated Id LevelDisplayName Message
----------- -- ---------------- -------
8/31/2021 7:44:27 AM 1129 Error The processing of Group Policy failed because of lack of network connectivity to a domain controller. This may be a transient condition. A success...

Query Process ID (PID) from Windows Event Log

I am trying to write a query that will extract the Process ID (PID) from a Windows Event log.
I'm dealing with Windows event ID: 1309
I have written several scripts that get me close but none that get me home. This one has come the closest:
Get-EventLog -LogName Application -Source 'ASP.NET 4.0.30319.0' -EntryType Warning -Newest 1 |
where eventid -eq 1309 |
Select message |
Format-List |
Out-File c:\temp\elogdata.txt
Select-String c:\temp\elogdata.txt -Pattern "process id:" -SimpleMatch
This is the output that I get:
C:\temp\elogdata.txt:20: Process ID: 7332
I need to pipe that "7332" , from the "Process ID:" into another command such as TaskKill or ProcDump.
Strangely enough, when I try and run the Select-String on the output in memory I get nothing:
Get-EventLog -LogName Application -Source 'ASP.NET 4.0.30319.0' -EntryType Warning -Newest 1 |
where eventid -eq 1309 |
Select message |
Format-List |
Select-String -InputObject {$_} -Pattern "process id:"
I have also tried several Get-WinEvent scripts...
Get-WinEvent -FilterHashtable #{LogName='application';ID='1309'} -MaxEvents 1 |
Format-List |
select message
Never use Format-* cmdlets when further processing of your data is intended. What you want to do is expand the Message property and adjust your pattern, so that you extract the actual PID instead of the entire line. You also don't want to use a simple match here.
... |
Select-Object -Expand Message |
Select-String -Pattern '(?<=process id:\s+)\d+' |
Select-Object -Expand Matches |
Select-Object -Expand Value
($<=...) is a so-called positive lookbehind assertion that allows you to match something in your string without including that in the match that is returned. Essentially the pattern means "match \d+ only if it's preceded by that other string".

List processes with the most CPU time.(Powershell)

How do I make it that no system services are enumerated? I would like to have both the system process as well as all other system services such as svchost not in the list.
Get-Process | Sort-Object CPU -desc | Select-Object -first 3 | Format-Table CPU,ProcessName,Id -hidetableheader
I like the other answer, but here's another possibility that doesn't need admin rights, although it might not be fool proof:
Most system services run within a process named svchost so you could simply exclude these processes with Where-Object:
Get-Process | Where-Object {$_.name -ne 'svchost'} | Sort-Object CPU -desc | Select-Object -first 3 | Format-Table CPU,ProcessName,Id -hidetableheader
You may need to be in Admin mode.
Get-Process -IncludeUserName | where {$_.UserName -notlike "NT AUTHORITY\SYSTEM"} | Sort-Object CPU -desc | Select-Object -first 3 | Format-Table CPU,ProcessName,Id -hidetableheader
Is this what you were asking for?
I like the other answers for their simplicity, however you can use the WMI class Win32_Process to retrieve a list of process and the method .GetOwner() to get the owner of the process.
As system processes do not show an owner we can easily filter on process that do have an owner, showing most non-system processes (I say most because svchost shows up under my account every now and then).
# Get all processes
$processes = Get-WMIObject -Class Win32_Process
foreach($process in $processes)
{
try
{
$processOwner = $process.GetOwner()
}
catch
{
continue
}
if ($processOwner.User -ne $null)
{
$processData = Get-Process -Id $process.ProcessId
$process | Select-Object -Property #{n='CPU';e={$processData.CPU}},Name,ID | Sort-Object -Property CPU
}
}

Powershell Get_EventLog for multiple servers

I'm a SQL DBA, n00b to Powershell, tasked with sysadmin duties at the moment
I need to query error logs across my servers for Errors and Warnings.
Using my own Google-fu and help from this thread I was able to get this working:
$computers = Get-Content "C:\Servers\ServerList_Short.txt";
# QUERY COMPUTER SYSTEM EVENT LOG
foreach($computer in $computers)
{
Get-EventLog -ComputerName $computer -LogName System -EntryType "Error","Warning" -After (Get-Date).Adddays(-7) `
| Select-Object -Property machineName, EntryType, EventID, TimeGenerated, Message `
| Format-Table -Property MachineName, TimeGenerated, EntryType, Source, Message -AutoSize ;
}
What I am missing at the moment is how to trap for a server in my .txt file that is offline, ignore it and move to the next one. After that, I will be working to dump all of this to a SQL table, results.txt, etc.
Thanks for any help :)]
Kevin3NF
There are a few different ways to handle this but I'd recommend combining a Test-Connection with a Try/Catch, the Test-Connection will make it so that you only try to query the servers which respond to ping and then the Try/Catch will handle any other errors that may come along.
foreach($computer in $computers)
{
if(Test-Connection $computer -Quiet -Count 1){
Try {
Get-EventLog -ComputerName $computer -LogName System -EntryType "Error","Warning" -After (Get-Date).Adddays(-7) `
| Select-Object -Property machineName, EntryType, EventID, TimeGenerated, Message `
| Format-Table -Property MachineName, TimeGenerated, EntryType, Source, Message -AutoSize
} Catch {
Write-Verbose "Error $($error[0]) encountered when attempting to get events from $computer"
}
} else {
Write-Verbose "Failed to connect to $computer"
}
}

Continuously monitors the CPU usage % of top X processes

I want to be able to to output to a log file the top CPU consumers every 5 seconds. That way I will be able to see who uses the most of the cpu during my tests.
I have found this answer very common:
$cpu = Get-Counter -ComputerName localhost "\Process(*)\% Processor Time" `
| Select-Object -ExpandProperty countersamples `
| where {$_.InstanceName -ne 'idle' } `
| where {$_.InstanceName -ne '_total' }`
| Select-Object -Property instancename, cookedvalue `
| Sort-Object -Property cookedvalue -Descending `
| Select-Object -First 5 `
| ft #{L='Date';E={Get-Date}}, InstanceName, #{L='CPU';E={(($_.Cookedvalue/100)/$NumberOfLogicalProcessors).toString('P')}} -HideTableHeaders `
| Format-Table -Auto | Out-String
I have 2 issues with it:
Sometimes I get:
Get-Counter : The data in one of the performance counter samples is not valid. View the Status property for each PerformanceCounterSample object to make sure it contains valid data.
I would like to get the full process name, and not
java 25%
idea64 0.8%
...
I'll try to answer your two questions at once with following script:
Get-Counter "\Process(*)\% Processor Time" -ErrorAction SilentlyContinue `
| select -ExpandProperty CounterSamples `
| where {$_.Status -eq 0 -and $_.instancename -notin "_total", "idle"} `
| sort CookedValue -Descending `
| select TimeStamp,
#{N="Name";E={
$friendlyName = $_.InstanceName
try {
$procId = [System.Diagnostics.Process]::GetProcessesByName($_.InstanceName)[0].Id
$proc = Get-WmiObject -Query "SELECT ProcessId, ExecutablePath FROM Win32_Process WHERE ProcessId=$procId"
$procPath = ($proc | where { $_.ExecutablePath } | select -First 1).ExecutablePath
$friendlyName = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($procPath).FileDescription
} catch { }
$friendlyName
}},
#{N="CPU";E={($_.CookedValue/100/$env:NUMBER_OF_PROCESSORS).ToString("P")}} -First 5 `
| ft -a -HideTableHeaders
This results in following table:
24.07.2016 21:00:53 Microsoft Edge Content Process 9,68%
24.07.2016 21:00:53 system 0,77%
24.07.2016 21:00:53 Microsoft Edge 0,39%
24.07.2016 21:00:53 runtimebroker 0,39%
24.07.2016 21:00:53 Host Process for Windows Services 0,39%
As specified, you sometimes get:
Get-Counter : The data in one of the performance counter samples is
not valid. View the Status property for each PerformanceCounterSample
object to make sure it contains valid data.
This is related to process management in windows environment. While you execute query, some processes may appear, some of them may disappear (i.e. wmiprvse process responsible for executing wmi queries). Some processes may require more permissions you have. This all leads to error when obtaining process information. It can be safely skipped using -ErrorAction SilentlyContinue switch and filtered with Status -eq 0 expression.
You also want to see more friendly process name. I don't know if there is better way of getting that name than from executable itself using GetVersionInfo method. If such information is available FileDescription property stores that value. If it's not available then non-friendly process name is used.
you get output something like this
Name CPU CPUPercent Description
---- --- ---------- -----------
chrome 10.4988673 8.79 Google Chrome
powershell_ise 6.5364419 7.16 Windows PowerShell ISE
chrome 38.0174437 4.88 Google Chrome
chrome 26.2549683 4.87 Google Chrome
chrome 16.9417086 3.16 Google Chrome
cavwp 10.2648658 2.67 COMODO Internet Security
chrome 13.1820845 2.44 Google Chrome
chrome 675.016327 2.02 Google Chrome
7.9.7_42331 1037.1570484 1.51 BitTorrent
chrome 340.8777851 1.02 Google Chrome
With
$CPUPercent = #{
Name = 'CPUPercent'
Expression = {
$TotalSec = (New-TimeSpan -Start $_.StartTime).TotalSeconds
[Math]::Round( ($_.CPU * 100 / $TotalSec), 2)
}
}
Get-Process -ComputerName $env:computername |
Select-Object -Property Name, CPU, $CPUPercent, Description |
Sort-Object -Property CPUPercent -Descending |
Select-Object -First 10 |format-table -autosize | out-file c:\pro.log
credit :http://powershell.com/cs/blogs/tips/archive/2013/04/16/documenting-cpu-load-for-running-processes.aspx
Get-Process -ComputerName $env:computername for remote computers you can have in csv
Import-CSV c:\"computers.csv" | % {
$Server = $_.ServerName
$alivetest = Test-Path "\\$Server\c$\"
If ($alivetest -eq "True")
{Get-Process -ComputerName $server |
Select-Object -Property Name, CPU, $CPUPercent, Description |
Sort-Object -Property CPUPercent -Descending |
Select-Object -First 10 |format-table -autosize | out-file c:\pro.log}
}}

Resources