SharePoint ULS Critical Events – How to display them as they happen (almost) in a PowerShell Session window   Leave a comment

This will probably be quite a long post, you may want to grab coffee and cake! – Its aimed at people with intermediate to advanced Powershell knoweledge.

Monitoring our Critical ULS logs – no errors!

I’m a working techie guy who bolts Powershell together as I need it, so it comes from all over.  If you want attribution for a block of code I borrowed from the internetz that came from your blog or article some place, please do let me know and I’ll be delighted to add attribution – if I remember where I got something, I’ll attribute as I go. 🙂

As the saying goes, you can’t manage what you can’t see. – So now we *can* see! 🙂


I want reasonably immediate information about how SharePoint is performing, especially Critical Events – I want  the detail to be available to me to action ASAP.   Being a bit of a Powershell fan, I wanted to see any Critical Events that were happening to SharePoint, pop up in a Powershell session window. – And, which is most important, I want to light up a Christmas tree when I get a Critical Event!!

I can’t give you entire working scripts here, they belong to my employer.  I can however give code examples to point you in the right direction in terms of script block elements I wrote/borrowed to get this information displaying in a Powershell session window.  You’ll need to create scripts with these elements and add your own support code.  Please email me if you need assistance, time willing, I’ll do my best to help you.

Note: you can ignore script 1, if in script 2 you can define which logs you want to go look at.  Script 1 gives nice summary views of 24hrs worth of logs in HTML also, but if you don’t need that, skip to script 2 for Powershell displaying goodness…

Script 1:  Measure-ULS-Log-Events-Incidence.ps1


About a year or so ago, I wanted a html output of the number of types events happening within the ULS logs on our farm over 24hrs, to give me a clue about what was going on without me having to sit with a log viewer open 24×7 across a number of machines.


You need to back up the latest ULS logs files from your farm, from each server.

I then used MS LogParser to iterate through the logs for the information we need, in this case, just numbers of each event type per server.

foreach ($server in $servers) {

&$logParserPath\LogParser -i:tsv -o:tsv file:\\<server>\scripts$\logparser\mossukoverviewstats-<server>.sql?COMPUTER_NAME=$server


Where the above referenced sql query file contains the following:

SELECT  Area    AS [Area],

   Category     AS [Category],

   Level        AS [Level],

   COUNT(*)     AS [Count]

INTO %COMPUTER_NAME%-area-category-level.tsv


GROUP BY Area, Category, Level



These get saved out as files by log parser for us to use in a minute.

 # Get the last few files
 $logfiles = ls -r -fi *.txt | sort @{expression={$_.Name}},@{expression={$_.LastWriteTime};Descending=$true} | select Directory, Name, lastwritetime | Group-Object Name | %{$_.Group | Select -first 1}
 $logcount = $logfiles.count
 Write-Debug “Log Count: $logCount”
 # Create an Array List Object to hold results data
 $global:results = new-object system.Collections.ArrayList

# Check and make sure at least three logs to compare with
 if ($logcount -lt 3) {
 Write-Host “Not enough logs written to make a comparison – waiting until next run” -ForegroundColor Yellow;
  } Else {
   Foreach ($log in $logfiles) {
    $logFile = $log.Name
    Write-Debug “File construct : $logFile”;
    $fileData = Import-CSV $logFile
    $temp = $fileData
    $temp = add-member -input $temp -passthru -member noteproperty -name prop -value 5
    # Using .NET object
   # Display file counts over time
   #$global:results | ft
   $results | ConvertTo-Html | Out-File $htmlSummaryOutput
   $Global:TotalCountResultsArray | ConvertTo-Csv | Out-File $csvSummaryOutput

You’ll next need a function to count these events from these files, these are then output into a unique time stamped file

# Set $now to current time/date
$now = [datetime]::Now

# Convert $now to ticks
$now = $now.ticks

$Global:TotalCountResultsArray = @()
 # Declare vars at the outer most scope they are required, else things go weird.
 $critstat_total = 0 ; $medstat_total = 0 ; $unexstat_total = 0 ; $highstat_total = 0 ; $monistat_total = 0
 foreach ($server in $servers) {
   $Global:CRA = @()
   $Global:CRA  = “”  | Select Server, Critical, Medium, Unexpected, High, Monitorable
   $Global:CRA.Server = $server
  $script:statsFile = Import-Csv -Delimiter `t $server-*.tsv;
  Write-Host “$($statsFile.count)” -ForegroundColor Green
  $critical_count = 0 ; $medium_count = 0 ; $unexpected_count = 0 ; $high_count = 0 ; $monitorable_count = 0
  foreach ($stat in $statsFile) {
   if ($stat.Level -eq “Critical”){[int]$critical_count =  $stat.Count; $Global:CRA.Critical = $critical_count   };
   if ($stat.Level -eq “Medium”){[int]$Medium_count = $stat.Count; $Global:CRA.Medium = $Medium_count };
   if ($stat.Level -eq “Unexpected”){[int]$unexpected_count = $stat.Count; $Global:CRA.Unexpected = $unexpected_count };
   if ($stat.Level -eq “High”){[int]$high_count = $stat.Count; $Global:CRA.High = $high_count };
   if ($stat.Level -eq “Monitorable”){[int]$monitorable_count = $stat.Count; $Global:CRA.Monitorable = $monitorable_count };
   Write-Host `n
   # Write-Debug $stat
   Write-Host “Line count field: $($stat.Count)” -Foregroundcolor Green
    Write-Host “================ “;
   Write-Host ” “;
   Write-Host “[$server]: Critical Count  : $critical_count”
   Write-Host “[$server]: Medium Count   : $Medium_count”
   Write-Host “[$server]: Unexpected Count: $unexpected_count”
   Write-Host “[$server]: High Count      : $high_count”
   Write-Host “[$server]: Monitorable Count: $monitorable_count”
   if ($critical_count -ne $Null) {$critstat_total = $critstat_total + $critical_count; $servercrit = $server
           “<tr><td>$Server</td><td class = “”thresholdhigh””>Critical ULS Events</td></tr> ” >> \\<server>\wwwroot$\console\alertconsole.htm }
   if ($medium_count -ne $Null) {$medstat_total = $medstat_total + $medium_count}
   if ($unexpected_count -ne $Null) {$unexstat_total = $unexstat_total + $unexpected_count}
   if ($high_count -ne $Null) {$highstat_total = $highstat_total + $high_count}
   if ($monitorable_count -ne $Null) {$monistat_total = $monistat_total + $monitorable_count}
   # Add to global results array
   $Global:TotalCountResultsArray += $Global:CRA

 Write-Host “`nTotal of Stats: “;
   Write-Host “================ “;
   Write-Host ” “;
   Write-Host “Critical Count  : $critstat_total”
   Write-Host “Medium Count   : $medstat_total”
   Write-Host “Unexpected Count: $unexstat_total”
   Write-Host “High Count      : $highstat_total”
   Write-Host “Monitorable Count: $monistat_total”
   # Write the count to file / screen
   “$Now, $Critstat_total, $medstat_total, $Unexstat_total, $Highstat_total, $Monistat_total” >> $now-measuring.txt
   Write-Host “$Now, $Critstat_total, $Medstat_Total, $Unexstat_total, $Highstat_total, $Monistat_total” >> $now-measuring.txt

The next bit involves loading up these files and working out distribution of types of events, and outputting as HTML.

This script was modified lastly to spit out a CSV files, so script 2 had something easy to work with.


Script 2:  Watch-ULS-Display-New-Critical-Entries.ps1

Set a file watcher to see when scripts 1’s output CSV file is updated (if you are not bothering with script 1 – which flags when a critical event has happened), then you need to script a way to decide when you are going to parse the ULS logs).

# Create file system watcher.
 $watcher = New-Object System.IO.FileSystemWatcher
 $watcher.InternalBufferSize = 65536
 $watcher.Path = $iSearchPath

# Setup which file / directory to watch.
 if ( $iSearchFile )
  Write-Host “`nLooking for file changes only in: [$iSearchFile] in Path [$iSearchPath] filter…” -ForegroundColor Yellow;
  $watcher.Filter = $iSearchFile
 $watcher.IncludeSubdirectories = $true
 $watcher.EnableRaisingEvents = $true

 # Subscribe to the events generated by the $watcher.

$changed = Register-ObjectEvent $watcher “Changed”  -Action $changeAction
 $created = Register-ObjectEvent $watcher “Created” -Action {
     write-host “Created: $($eventArgs.FullPath)” -ForegroundColor Green; $iFile}
 $deleted = Register-ObjectEvent $watcher “Deleted” -Action {
     write-host “Deleted: $($eventArgs.FullPath)” -ForegroundColor DarkYellow; $ifile}
 $renamed = Register-ObjectEvent $watcher “Renamed” -Action {
     write-host “Renamed: $($eventArgs.FullPath)” -ForegroundColor Red; $iFile }

The $change script block defines your code for checking the CSV file and then looking through the ULS logs, in my case it recurses and checks each entry of the CSV file which gives server, and an integer for each event type.

For critical events, if it finds a number, we retrieve the server(s) value(s) name (server names) that is also in the same item.

# $change action definition.

$change = {code}

Once you know which server(s) ULS log(s) the event(s) is/are in, you can then go get that/those log(s), script 1 has already pulled the current ULS logs over to temp storage, so you can get it/them from there, or you’ll need to provide another way if script 1 is not being considered.

OK, the next thing you’d possibly want to do, is iterate through the ULS log(s).  I thought a bit about this. ULS logs can be big, very big, or titchy.  Potentially get-content “could” run out of memory to manipulate the file.  Lets not take a chance, we’ll use a streamreader thingie instead. (I think PS2 can use get-content with streamreader type behaviour)

$reader = New-Object System.IO.StreamReader($iFile)
        $regExMatch = “Critical”
        # Find the droids we are looking for…
        Write-Host “Finding Entries…” -ForegroundColor Yellow
        While ( !$reader.EndOfStream )
        $line = $reader.ReadLine();
          If ( $line -match $regExMatch )
          # These are the droids we are looking for…..
          Write-Host “These are the Droids we are looking for!” -ForegroundColor Red
          Write-Host ” [$server]: ” -NoNewline -ForegroundColor Yellow
          Write-Host $line -ForegroundColor Green -BackgroundColor Black;
          # Switch on our Tree.

That little lot parses through our ULS log, matches lines that have Critical in them, and spits out the output into our Powershell window.

Don’t forget a reader.dispose() when tidying up between logs btw 🙂

– My “Tree-On” is a nifty bit of powershell connecting to a custom DLL, via a k8055 interface board – this switches on an actual  “Alert Christmas Tree” – no expense has been spent!! (Well apart from the fiver it cost for the USB tree, and the time taken to lop the USB connector off and connect to the card outputs!)

Other bits, as we were testing the script, and re-running it, I wanted to make sure to cancel events we had registered.

This command cancels any active event subscription, and tells you what it cancels:

Get-EventSubscriber | % {Write-Host ” Cancelling Event Name: [$($_.EventName)] – Subscription ID: [$($_.SubscriptionID)]”;Unregister-Event -SourceIdentifier $_.SourceIdentifier -force }


Ok, I think thats cogent enough to let you figure the rest out, but if not, please do let me know as I’d like the community to get some use from all this 🙂



Posted September 7, 2011 by stormwalker255 in SharePoint

Tagged with

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: