Log-Event

Recently I had a need to write to the event logs using PowerShell.  I knew there was a built in command for this action so I decided to test it out.  After some time using the Write-EventLog cmdlet, I kept getting errors generated which seemed to be symptoms from the following constraints of the event log itself.  When using the cmdlet, the following apply:

-You must specify a source and a log (Application, System, etc) to write to.  An example of a source would be “Windows Error Reporting” in the Application log.

- A source can only be associated with one event log.  If you attempt to write an event using the source “Windows Error Reporting” to the System log, you will get the following error: The source 'Windows Error Reporting' is not registered in log 'System'. (It is registered in log 'Application'.)

Since the Write-EventLog cmdlet makes you specify the log to write to with the mandatory –LogName parameter, this can be problematic because you have to know which log the source is associated with.  From a programmatic perspective, you can’t guarantee all computers everywhere have the source “AutomationLogs” registered, and you also can’t guarantee which event log this is registered to.

I developed the following function to assist me in writing to the event logs that I plan to implement in a lot of my scripts moving forward.  I wanted to be able to call a command and specify what I want to write and not have to worry about sources, log locations, registering new event logs if needed, and so on.

The function first checks to see if the source is already registered with an existing log.  If the source exists, the function leverages the static method LogNameFromSourceName from the System.Diagnostics.EventLog class to determine which log to write to.  If the return from this function is null or an empty string, we know the source does not exist and will have to register a new event source to the desired log (as passed in by the caller). 

This function requires administrative access in an elevated command prompt, because it needs to check the Security log, and this access is also required when registering new sources.

According to the MSDN documentation regarding creation of event sources – after registering a new event source, it should not be immediately used.  I am not sure exactly how long we should wait but I assumed 5 seconds is ample time for whatever replication/post-processing tasks need to happen on the back end before we use this.

I have tested this on Server 2012 and 2012 R2, but any machine with PowerShell 3 or later should be able to leverage the function.  The function is below and can also be found on the TechNet Script Gallery here.

 

function Log-Event {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [String]$Message,

        [ValidateNotNullorEmpty()]
        [String]$Source = "ScriptOutput",

        [int32]$EventID = 1,

        $LogName = "Application",

        [System.Diagnostics.EventLogEntryType]$Type = "Information"
    )
    try {
        $SourceLogName = [System.Diagnostics.EventLog]::LogNameFromSourceName($source, ".")
        if (![string]::IsNullOrEmpty($SourceLogName)) {
            Write-EventLog -LogName $SourceLogName -Source $Source -Message $Message -EntryType $Type -EventId $EventID
        }
        else {
            New-EventLog -Source $Source -LogName $LogName
            #After register new event source, do not use right away, accoring to MSDN:
            #https://msdn.microsoft.com/en-us/library/2awhba7a(v=vs.110).aspx
            Sleep 5
            Write-EventLog -LogName $LogName -Source $Source -Message $Message -EntryType $Type -EventId $EventID
        }
    }
    catch {
        Write-Warning "Unexpected error occured while attempting to write to log."
        Write-Warning "Caller command: $((Get-PSCallStack)[1].Command)"
        Write-Warning "Error: $($_.exception.message)"
    }
}