It’s easy to dump output to a text file in a script, but for enterprise-class logging, the two standards are the Event Log and ULS (Unified Logging System). First ULS.
Below in PowerShell I grab a reference to the SPDiagnosticsService, define a SPDiagnosticsCategory, then call the writeTrace() method:
$diagSrc = [Microsoft.SharePoint.Administration.SPDiagnosticsService]::Local $diacategory = new-object Microsoft.SharePoint.Administration.SPDiagnosticsCategory("MyTestCategory",[Microsoft.SharePoint.Administration.TraceSeverity]::Monitorable, [Microsoft.SharePoint.Administration.EventSeverity]::ErrorCritical) $diagSrc.WriteTrace(98765, $diacategory, [Microsoft.SharePoint.Administration.TraceSeverity]::Monitorable, "Write your log description here" ) |
ULS is a good standard central way to go, but let’s move onto writing into the Event Log, which is extra useful given we are first going to create a custom application log:
New-EventLog -LogName MyCustomScripts -Source scripts |
First challenge is if the logfile exists, then it will throw an error, even if you try encapsulating in a try/catch. the trick is to leverage the Get-EventLog CmdLet.
First, to see what exists, format as a list:
Get-EventLog -list |
You now have your very own Event Log, and can write into it with your own event IDs, and messages, and severity levels. Here’s two worknig examples:
Write-EventLog -LogName MyCustomScripts -Source Scripts -Message "trying 4142 it works ... COOL!" -EventId 4142 -EntryType information Write-EventLog -LogName MyCustomScripts -Source Scripts -Message "trying 4942 as an error" -EventId 4942 -EntryType error |
Now let’s simplify for re-use and consistency. Let’s declare some basics at the top of all scripts:
$Eventing = $true; #determine if any events are written to the event log $LogName = "JoelScripts" $SourceName = "Scripts" $ScriptID = 3; # unique number per script |
Here’s a one-line function to make life simpler for our scripts:
function Write-MyLog([int] $EventID, [string] $Description, [system.Diagnostics.EventLogEntryType] $Severity) { if ($Eventing) { Write-EventLog -LogName $LogName -Source $SourceName -Message $Description -EventId $EventID -EntryType $Severity } } |
Now let’s add a line at the start and end of the scripts to trigger an information event on what’s running. Note that references to $MyInvocation contain information about the currently running script:
Write-MyLog -Description "Start of $($MyInvocation.MyCommand.Path)" -EventId $ScriptID -Severity information Write-MyLog -Description "End of $($MyInvocation.MyCommand.Path)" -EventId $ScriptID -Severity information |
Lastly, here’s a sample normal message evented for warning, and next for error:
Write-MyLog -Description $RunStatus -EventId $ScriptID -Severity Warning Write-MyLog -Description $RunStatus -EventId $ScriptID -Severity Error |
A nice way to write events is to use the “Source” to map back to the script name or some other useful value for filtering. However sources need to be pre-defined. Here’s how to define a source:
New-EventLog -LogName $LogName -Source "X" |
The challenge is when to create this source. I find it’s best to declare the source only if it does not exist:
try { $Sources = Get-EventLog -LogName $logname | Select-Object Source -Unique $found = $false; foreach ($OneSource in $Sources) { if ($OneSource.source -eq $Source) { $found=$true; } } } catch { Write-Host "cannot find logfile, so we are in deep trouble" } if (!$found) { New-EventLog -LogName $LogName -Source $Source Write-Host "Created new Source $($Source) in log name $($LogName)" } |
Want to talk?
Drop us a line. We are here to answer your questions 24*7.