PowerShell: get-eventlog takes too long to complete - powershell

I am trying to script the review of the past 30 days of the Application and System Event Logs on remote servers, looking for only Warnings, Errors, or Critical entries.
Borrowing from what I have found here and in other forums, I have come up with:
$Date = Get-Date
$Range = $Date.AddDays(-30)
$Range = $range.ToShortDateString();
$LogName = Read-Host "Which Log? (Application, System)"
$Server = Read-Host "Please Enter Server Name"
get-eventlog $LogName -ComputerName $Server -After $range | where {$_.EntryType -eq "Error" -or $_.EntryType -eq "Warning" -or $_.EntryType -eq "Critical"}
This seems to run fairly quickly, but then hangs several (5-10+) minutes before returning to a prompt, if it does....
Note: if I remove the code:
-After $range
I can simply break the output with ctrl-c and get on with my day, but I'd rather it run as intended and then stop...
So: Any ideas on how to eliminate this hang?
I am also open to ideas on how to make the code more elegant (and faster)!
And I wouldn't mind the script checking both the Application and System logs without having to run twice....

Using the -EntryType string-array parameter on Get-EventLog is much faster than retrieving the entire event log and then filtering with Where-Object
Try get-eventlog -Logname System -EntryType ("Error", "Warning")
However... if I put "Critical" in the -EntryType array, I get: The argument "Critical" does not belong to the set "Error,Information,FailureAudit,SuccessAudit,Warning" specified by the ValidateSet attribute. which makes me wonder whether you should be heeding the advice as listed in Get-Help Get-EventLog:
The cmdlets that contain the EventLog noun (the EventLog cmdlets) work
only on classic event logs. To get events from logs that use the
Windows Event Log technology in Windows Vista and later versions of
Windows, use Get-WinEvent.
Using Get-WinEvent instead, I think this is what you want:
Get-Winevent -FilterHashtable #{LogName="System","Application"; Level=1,2,3; startTime=$range}
That will check for events of level 1, 2, or 3 (Critical, Error, Warning, respectively), and search both the Application and System logs in the same invocation.

I found that for remote systems, I could query several systems at once faster than I could individually, using the same command, if I wrapped it into an Invoke-Command. This is my solution. The more systems, the more time it saved. YMMV
$command = {Get-EventLog -LogName Application -After (Get-Date).AddHours("-24")}
Invoke-Command -ComputerName "foo1","foo2","foo3","foo4" -ScriptBlock $command

Related

Powershell Get-EventLog from computers.txt and save data

I have some problems getting EventLog and save data. I am able to get my EventLogs but not logs from network computers.
Here is the code I am running:
$logFileName = "Application"
$path = $MyInvocation.MyCommand.Path +"\Output\"
$path = $PSScriptRoot+"\Output\"
new-item $path -ItemType directory
$array = ("System", "Security")
$file = $PSScriptRoot +"\computers.txt"
$users = ForEach ($machine in $(Get-Content $file)) {
$pathMachine = $path+$machine
new-item $pathMachine -ItemType directory
ForEach ($logFileName in $array){
# do not edit
$logFileName
$exportFileName = (get-date -f yyyyMMdd) + "_" + $logFileName + ".evt"
$logFile = Get-WmiObject Win32_NTEventlogFile -ComputerName $machine | Where-Object {$_.logfilename -eq $logFileName}
$logFile
$exportFileName
$pathMachine
$temp = $pathMachine + "\"+ $exportFileName
$temp
$fff = $logFile.BackupEventLog($temp)
}
}
This could e considered a duplicate of this.
Reading event log remotely with Get-EventLog in Powershell
# swapped from this command
get-eventlog -LogName System -computername <ServerName>
# to this
invoke-command {get-eventlog -LogName System} -ComputerName <ServerName>
Don't struggle with writing this from scratch. Well, unless it's a learning exercise. There are pre-built script for you to leverage as is and or tweak as needed.
Running commands on Remote host require using the Invoke cmdlet, and or an established PSRemoting session to that host.
Get Remote Event Logs With Powershell
Gather the remote event log information for one or more systems using wmi, alternate credentials, and multiple runspaces. Function supports custom timeout parameters in case of wmi problems and returns Event Log information for the specified number of past hours.
Download: Get-RemoteEventLogs.ps1
The script is too long (it's 100+ lines) to post here, but here in the Synopsis of it.
Function Get-RemoteEventLogs
{
<#
.SYNOPSIS
Retrieves event logs via WMI in multiple runspaces.
.DESCRIPTION
Retrieves event logs via WMI and, if needed, alternate credentials. This function utilizes multiple runspaces.
.PARAMETER ComputerName
Specifies the target computer or comptuers for data query.
.PARAMETER Hours
Gather event logs from the last number of hourse specified here.
.PARAMETER ThrottleLimit
Specifies the maximum number of systems to inventory simultaneously
.PARAMETER Timeout
Specifies the maximum time in second command can run in background before terminating this thread.
.PARAMETER ShowProgress
Show progress bar information
.EXAMPLE
PS > (Get-RemoteEventLogs).EventLogs
Description
-----------
Lists all of the event logs found on the localhost in the last 24 hours.
.NOTES
Author: Zachary Loeber
Site: http://www.the-little-things.net/
Requires: Powershell 2.0
Version History
1.0.0 - 08/28/2013
- Initial release
#>
Or this one.
PowerShell To Get Event Log of local or Remote Computers in .csv file
This script is handy when you want to extract the eventlog from remote or local machine. It has multiple filters which will help to filter the data. You can filter by logname,event type, source etc. This also have facility to get the data based on date range. You can change th
Download : eventLogFromRemoteSystem.ps1
Again, too big to post here because the length is like the other one.
I am working on some assumptions but maybe this will help.
When I Ran your Code I got
Get-Content : Cannot find path 'C:\computers.txt' because it does not exist.
I had to make the C:\computers.txt file, then I ran your code again and got this error.
Get-Content : Cannot find path 'C:\Output\computers.txt' because it does not exist.
I made that file in that location, then I ran your code again and I got the event log file. Maybe try creating these two missing files with a command like
Get-WmiObject Win32_NTEventlogFile -ComputerName $machine
mkdir C:\Output\$machine
$env:computername | Out-File -FilePath c:\Output\Computers.txt
You may also want to setup a Network share and output to that location so you can access the event logs from a single computer. Once the share is setup and the permissions just drop the unc path in.

Powershell Write-EventLog / Get-WinEvent Message issues

The first command creates an entry in the event log, it seems to be working because I can see the message data in event viewer. The issue is when reading it back from powershell the message field is empty.
write-eventlog System -source 'Microsoft-Windows-Kernel-General' -eventid 999 -message 'Kernel something or other'
get-winevent -filterHashTable #{Logname = 'System'; ID = '999'}| select-object -first 10
Maybe this picture explains it better. Notice the message column is blank.
The event is being written correctly, to read it back use this:
get-winevent -filterHashTable #{Logname = 'System'; ID = '999'}|
select-object -first 10 | select timecreated,providername,
#{n="Message";e={$_.properties.Value}}
The reason you can't see it in the message column is evident when launching eventvwr:
The description for Event ID 999 from source Microsoft-Windows-Kernel-General cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.
If you want to write custom messages from custom sources use New-EventLog cmdlet, here is the Scripting Guy's tutorial: http://blogs.technet.com/b/heyscriptingguy/archive/2013/06/20/how-to-use-powershell-to-write-to-event-logs.aspx
Here is the snip that ended up making it work. Credit to Raf for the link where I found this answer.
$source = "Some Name"
If ([System.Diagnostics.EventLog]::SourceExists("$source") -eq $false)
{New-EventLog -LogName $log -Source "$source"}

powershell takes a long time to close connection?

I'm trying to run this powershell script on several remote network servers, but it takes a long time to complete the task and move to the next one.
Here's a basic script that will query a single remote server and return the data I want in a fast manner, but takes a long time to complete the entire script.
Get-EventLog -ComputerName WebServer1 -LogName System -EntryType Error -After ((Get-Date).Date.AddDays(-1))
I was running it through the Powershell ISE and from the command line in Powershell and both have the same behavior.
Any help is appreciated!
Thanks
As for the reason: mjolinor outlined that - Get-EventLog parses the whole logfile, and then filters the output to meet your parameters. What we want to do right now is to parse the event log one by one from the newest entries while the condition is true.
$i = 0
$EventParser = do
{
Get-EventLog -ComputerName Localhost -LogName System -EntryType Error -Newest $i; $i++
}
while
(
(Get-EventLog -ComputerName Localhost -LogName System -EntryType Error -Newest $i | Select -Last 1).TimeWritten -ge ((Get-Date).Date.AddHours(-24))
)
$EventParser|Where-Object { $_.TimeWritten -ge ((Get-Date).Date.AddHours(-24)) } | Sort-Object -Property Index -Descending | Get-Unique -OnType
I have measured your command and the loop I have written - here is the output for my machine
For $EventParser:
TotalMilliseconds : 634,6669
For your command (I changed webserver1 to localhost)
TotalSeconds : 14,3049668
I hope the script above will do the trick to speed up log parsing.
PS.
I have ran into one thing that I couldn't figure out. As you see, I am actually filtering the output twice for, I believe, the same condition (!). If I remove the last-line Where-Object statement, I receive 35 entries for my machine and it lists output even from 4 days ago ?? (Normally I receive 19 entries both from mine and original command). I have had to, to my surprise, re-apply the filter to receive the desired scope. Can you assist with that in a comment or should I post a question on that?
EDIT:
Now the problem doesn't occur. Edit: I have tweaked the code a little bit, I noticed that in some cases it may return duplicated entries.
Best regards,
AlexP

Script uses a lot of Ram if it's running long

I have a PS Script (running all the time on a Powershell 3.0) and there is a loop, which consumes many RAM.
while(1)
{
$te = Get-Winevent -MaxEvents 1 -FilterHashtable #{logname='application';id=2}| select -expand properties
Sleep 1
}
I tried to delete the Object and call the GC explicit. But nothing works! The Script is consuming a lot of RAM
How can I solve this Issue?
Judging by your code, it seems that you want to find all events in the Application event log with the ID of 2. If so, you're going about it wrong. You should use the Get-EventLog cmdlet. Try this:
Get-EventLog -LogName Application -InstanceID 2

How to pull a range of failed services from a remote server after a reboot

Caveat: Without spiking the cpu while a Get-WmiObject call parses the whole event log to match my specified filter.
Situation: I am working on a script that remotely runs some checks, then reboots a pc. I want it to check the health once the server reboots (after sleeping for some time) to make sure services that were supposed to start did. I've been running into "Automatic" services that start and then shut down (as intended) but then my current version picks them up as failed if they've already run. It was suggested that I check the event log for "Service Control Manager" errors, and report on those, the only problem now is that with the below script, we have servers who's event log can range anywhere from 20K to several hundred thousand events, and on a 2k server with 20K, this takes roughly 20 seconds to complete, and the cpu pegs near 100% while it's running.
I'm still learning powershell/wmi, so any advice would be appreciated.
function Check_Startup_Events {
BEGIN {
$time = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime((Get-Date).AddMinutes(-15))
}
PROCESS {
$results = Get-WmiObject Win32_NTLogEvent -computername $_ -Filter "LogFile='System' and SourceName='Service Control Manager' and TimeGenerated>='$time' and EventType=1" |
Format-Table -Autosize EventCode, Message
$results
}
}
$results = Get-EventLog -ComputerName w2kserver -LogName System -After $time
foreach ($result in $results){
if ($result.Source -eq "Service Control Manager" -and $result.EntryType -eq "Error"){
Write-Host $_.Description}}
I ran this against a 60k big event log on a W2K server in our environment. It takes a while to run but runs locally and does not tax the server. Not sure how you would want to output the data but I think Get-EventLog will do what you want.