The SQL Server errorlog has a misleading name. There is a lot more information in it than just errors. The version, startup parameters, memory settings and a ton more. I’ve been working with SQL Server for over 20 years and I still see messages in the errorlog that I don’t remember coming across. Since there are so many possibilities of what is being written to the errorlog, I can’t possibly search for all the things that I want to be notified of if they show up.

The answer I came up with is to do the opposite. If I look at today’s log and yesterday’s and last week’s, they all are mostly the same. With that in mind, I’m going to show you how to user PowerShell to search through the log and filter out all the normal stuff and return only the unusual.


First let’s get some errorlog records. Errorlog records from dbatools Get-DbaErrorLog look like this with each record being an object.

Get-DbaErrorLog -SqlInstance Server01 
ComputerName : Server01
InstanceName : MSSQLSERVER
SqlInstance  : Server01
LogDate      : 8/31/2021 12:00:00 AM
Source       : spid289
Text         : Microsoft SQL Server 2019 (RTM-CU10) (KB5001090) - 15.0.4123.1 (X64)
                Mar 22 2021 18:10:24
                Copyright (C) 2019 Microsoft Corporation
                Enterprise Edition: Core-based Licensing (64-bit) on Windows Server 2019 Standard 10.0  (Build 17763: )

I could look at just the Text property but I also want LogDate and SqlInstance so I know where and when the log message came from. Since I’m going to be passing this to Select-String, I going to use a Calculated Property to flatten the object.

# We'll pass the output of Get-DbaErrorLog to this.
Select-Object @{n='Log';e={"$($_.LogDate) $($_.SQLInstance): $($_.Text)"}}
Now we get an output looking something like this
2021-08-31 00:00:00 Server01: Server process ID is 10904.


To eliminate the lines I don’t care about, I’m going to use the -NotMatch switch for Select-String. This is the real hero of this story. Everything that doesn’t match a line in the filter file is returned. I create a text file with one pattern per line and use Get-Content to put it into a variable like so

$filter = Get-Content .\filter.txt

Here’s an example of what’s in my filter file.

SQL Server detected 1 sockets
SQL Server is starting
Server process
System Manufac
Authentication mode
The error log
Microsoft Corp
All rights
The service account
Database backed up

Lather, Rinse, Repeat

Now we’ve arrived at the meat of the process.

# Get the output of Get-DbaErrorLog.
$log = Get-DbaErrorLog -SqlInstance Server01 -LogNumber 0
# Flatten the output
$flat = ($log | Select-Object @{n='Log';e={"$($_.LogDate) $($_.SQLInstance): $($_.Text)"}}).log
# Get my filter list
$filter = Get-Content .\filter.txt
# Pipe the flattened log to Select-String using -NotMatch 
# We only care about the "line" property that Select-String returns
$filtered = ($flat | Select-String -Pattern $filter -NotMatch).line
# Show my results.

This is an iterative process. Run it look to see what the output is and add to your filter file. Keep running it until you only get the output you care about. Now change the -LogNumber to 1 and repeat the process. as your filter file grows you can remove the -LogNumber parameter altogether and search all the logs.

My threshold for the log output is things that I want to get paged for. Maybe have a “Email Me” filter and a “Page Me” filter.

Now in the process I pick a new server and go through it’s logs. After adding any additional filter lines I pick another server. Once I get to the point of not adding any lines I run it against all my servers.

All the Servers

Most of the dbatools commands that have a -SqlInstance parameter accept a list. I usually use my Central Management Server list using the Get-DbaRegServer

$cms = Get-DbaRegServer -SqlInstance CMSServer01 -Group AllManagedServers

I can now use $cms for the -SqlInstance parameter.

Timing is everything

If I’ve done everything right, I now have my filter set up to only give me results I care about, but I don’t want to search the whole log every time. To limit what is searched I use the -After parameter for Get-DbaErrorLog. If I run my search on a schedule every 15 minutes I want to limit my search to the last 30 minutes to have some overlap.

$log = Get-DbaErrorLog -SqlInstance $cms -After (Get-Date).AddMinutes(-30)


So there are the building blocks you can use looking through your error logs. You can schedule it, you can run it on demand or some other thing I haven’t thought of.

Hopefully this is useful to you and gives you some ideas to add to monitoring your estate.

Thanks for reading.