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".
Related
I'm setting up a contacts file in .csv format, as downloaded from google, to read with powershell on my windows 10 laptop. I have a long way to go to make this practical, but the first thing I've tried, and almost succeeded in, is to write a script that prompts the user to enter a name and then responds with the phone number for them. That script looks like this:
Param(
[Parameter(Mandatory=$true, Position=0, HelpMessage="What's their name?")]
$TheirNameIs
)
Import-Csv "*MYPATH*.csv" |
Sort 'Family name' -descending |
Where-object {$_.Name -eq $TheirNameIs} |
Select-Object -Property 'Name','Phone 1 - Type','Phone 1 - Value'
The problem I am having is Where-object works with -eq to find exact matches to the name the user enters, but I wanted to use -contains so that I could type in a first name and get all the contacts with that value in their name. I tried replacing -eq with -contains but wasn't getting any output unless I used the exact contact name
Where am I going wrong with the Where-object cmdlet?
You could replace the -eq operator by the -like operator and insert wildcards:
Param(
[Parameter(Mandatory=$true, Position=0, HelpMessage="What's their name?")]
$TheirNameIs
)
Import-Csv "*MYPATH*.csv" |
Sort 'Family name' -descending |
Where-object {$_.Name -like "*$TheirNameIs*"} |
Select-Object -Property 'Name','Phone 1 - Type','Phone 1 - Value'
You could also go for regular expressions and use the -match operator like #Olaf already mentioned. A solution could look like this:
Param(
[Parameter(Mandatory=$true, Position=0, HelpMessage="What's their name?")]
$TheirNameIs
)
Import-Csv "*MYPATH*.csv" |
Sort 'Family name' -descending |
Where-object {$_.Name -match ".*$TheirNameIs.*"} |
Select-Object -Property 'Name','Phone 1 - Type','Phone 1 - Value'
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
}
}
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
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}
}}
In interactive mode, this works:
Get-Eventlog -log application -after ((get-date).addMinutes(-360)) -EntryType Error
Now I want to filter out certain messages, the following didn't filter the desired word:
Get-Eventlog -log application -after ((get-date).addMinutes(-360)) -EntryType Error | where-object {$_.$Message -notlike "*Monitis*"}
Also, how do I put in multiple conditions on the where-object?
In my script, I'm getting errors on the -and statement:
$getEventLog = Get-Eventlog -log application -after ((get-date).addMinutes($minutes*-1)) -EntryType Error
# list of events to exclude
$getEventLogFiltered = $getEventLog | where-object {$_.Message -notlike "Monitis*"
-and $_.Message -notlike "*MQQueueDepthMonitor.exe*"
}
$tableFragment = $getEventLogFiltered | ConvertTo-Html -fragment
Error:
-and : The term '-and' is not recognized as the name of a cmdlet, function, script file, or operable program. Check
the spelling of the name, or if a path was included, verify that the path is correct and try again.
At D:\scripts\EventLogExtract2.ps1:24 char:40
+ -and $_.Message -notlike "*MQQueueDepthMo ...
+ ~~~~
In your 2nd code snippet remove the dollar sign right before "Message". Reads like the following. If you're using PowerShell ISE, you'll see that "Message" should be in black instead of red.
Get-Eventlog -log application -after ((get-date).addMinutes(-360)) -EntryType Error | where-object {$_.Message -notlike "*Monitis*"}
For the 3rd code snippet, I placed a grave accent before starting a newline in the Where-Object filter. This tells PowerShell you're continuing a line instead of beginning a new one. Also, in PowerShell ISE, the comparison operators (-and & -notlike) turn from blue and black to grey.
$getEventLog = Get-Eventlog -log application -after ((get-date).addMinutes($minutes*-1)) -EntryType Error
# list of events to exclude
$getEventLogFiltered = $getEventLog | where-object {$_.Message -notlike "Monitis*" `
-and $_.Message -notlike "*MQQueueDepthMonitor.exe*"
}
$tableFragment = $getEventLogFiltered | ConvertTo-Html -fragment
Date simplification:
((get-date).addMinutes($minutes*-1)) has the same output of
((get-date).addMinutes(-1))
and the same output of
(get-date).addMinutes(-1)
Also I find addDays(-1) to be more useful.