VSCode script template with logging

I recently created an alternative version of the script template. This one is for PowerShell scripts and includes additions for the logging that I do both within a log file and Event Viewer. I am including the template and the code to add to VSCode to make it a snippet. I also have the code and snippets for adding the logging within the script.

Template

<#
.SYNOPSIS
Script synopsis

.SYNTAX
Script syntax

.DESCRIPTION
Script description

.PARAMETER Parameter input descriptions and repeat this as needed for each parameter

.INPUTS
Input description if used

.OUTPUTS
Output description if used

.NOTES
FileName:
Author: Michael Schultz
Contact:
Created: 20180606
Modified:
Version:

.EXAMPLE
Example description and example

#>


#-----Parameters-----

Param (

)

#-----Initializations and Module Imports-----

#-----Variables-----

#set Event Log Name, Event Log Source and Log file unique name
$evntlog = ''
$source = ''

# set Log File path and Log File name
$logpath = ''
$logfile = $logpath + $source + '.log'

#-----Functions-----

#-----Logging-----

#set Event Log logging as the source needs to exist prior to writing to the log this will check for it and create if not there
if ([System.Diagnostics.EventLog]::SourceExists($source) -eq $False)
{
New-EventLog -LogName $evntlog -Source $source
}

#Check for logfile, remove log file if bigger than 5MB to prevent bloat, and create new logfile
If (Test-Path $Logfile )
{
if ((Get-Item $Logfile ).Length -gt 5MB)
{
remove-item $Logfile
}
}
else
{
new-item -Path $Logfile –itemtype file
}

#-----Execution-----

Code for snippet in VSCode

"Template with Logging": {
"prefix": "temp_log",
"body": [
"<#",
".SYNOPSIS",
"Script synopsis",
"",
".SYNTAX",
"Script syntax",
"",
".DESCRIPTION",
"Script description",
"",
".PARAMETER ",
"Parameter input descriptions and repeat this as needed for each parameter",
"",
".INPUTS",
"Input description if used",
"",
".OUTPUTS",
"Output description if used",
"",
".NOTES",
"FileName: ",
"Author: Michael Schultz",
"Contact: ",
"Created: $CURRENT_YEAR$CURRENT_MONTH$CURRENT_DATE",
"Modified: ",
"Version: ",
"",
".EXAMPLE",
"Example description and example",
"",
"#>",
"",
"#-----Parameters-----",
"",
"Param (",
"",
"",
")",
"",
"#-----Initializations and Module Imports-----",
"",
"#-----Variables-----",
"",
"#set Event Log Name, Event Log Source and Log file unique name",
"$$evntlog = ''",
"$$source = ''",
"",
"# set Log File path and Log File name",
"$$logpath = ''",
"$$logfile = $$logpath + $$source + '.log'",
"",
"#-----Functions-----",
"",
"#-----Logging-----",
"",
"#set Event Log logging as the source needs to exist prior to writing to the log this will check for it and create if not there",
"if ([System.Diagnostics.EventLog]::SourceExists($$source) -eq $$False)",
"{",
" New-EventLog -LogName $$evntlog -Source $$source",
"}",
"",
"#Check for logfile, remove log file if bigger than 5MB to prevent bloat, and create new logfile",
"If (Test-Path $$Logfile )",
"{",
" if ((Get-Item $$Logfile ).Length -gt 5MB) ",
" {",
" remove-item $$Logfile ",
" }",
"}",
"else",
"{",
" new-item -Path $$Logfile –itemtype file",
"}",
"",
"#-----Execution-----"
],
"description": "PowerShell Template with Logging"
},
}

It is a good idea to decide on Event IDs if you are going to write custom Event Logs. These are the IDs I decided to use for Compliance Settings.
• 17 – compliance check starting
• 42 – success (hitchhiker’s guide)
• 1984 – error (1984)
• 1822 – needs remediation (Babbage)
• 1138 – Remediation starting (THX-1138)
• 1949 – Remediation finished with some errors and may still be non-compliant (John von Neumann’s article on the “Theory of self-reproducing automata” is published)
• 1936 – successful remediation (Turing)

Now that we have a template to use for a script that has logging features, how do we handle the actual logging? The Write-EventLog cmdlet is used to write to an Event Log. You need the name of the log, the source, entry type, Event ID, and the message. The template already includes variables used for the log name and source.

Here is the code I use to write to an Event Log.

Write-EventLog –LogName $evntlog –Source $source –EntryType Information –EventID –Message ''

What if you want to capture and write an error message to the Event Log? This is where –ErrorVariable comes into play. Using –ErrorVariable, we write the error message to a variable and then use that variable with the Write-EventLog cmdlet.

The code follows a cmdlet to write any error messages to a variable. It then checks if the variable is NULL. If it is, then an error message wasn’t captured. If it is not NULL, it writes the variable to the Event Log, sets the variable back to NULL and also sets a new variable as true. This last variable isn’t needed, but I use it at the end of my script so I know if it completed running the script and an error message was captured. This goes with my custom Event ID of 1949 which is remediation of a compliance setting configuration item finished with some errors and may not be compliant.

Here is what that code looks like.

-ErrorVariable ProcessError
if ($ProcessError -ne $null)
{
Write-EventLog –LogName $evntlog –Source $source –EntryType Error –EventID –Message '$ProcessError'
$ProcessError = null
$err = 'true'
}

We can do pretty much the same thing in write to a log file and not to an event log. This is done with the Add-content cmdlet and what I use looks like this.

$mydate = Get-Date
Add-content $Logfile -value '$mydate; '
-ErrorVariable ProcessError
if ($ProcessError -ne $null)
{
$mydate = Get-Date
Add-content $Logfile -value '$mydate; $ProcessError'
$ProcessError = null
$err = 'true'
}

Below is the code to add to VSCode to use for your code snippets.

"EventLog ": {
"scope": "powershell",
"prefix": "event",
"body": [
"Write-EventLog –LogName $$evntlog –Source $$source –EntryType Information –EventID –Message ''"
],
"description": "Write to Event Log"
},

"EventLog_ErrorCatch": {
"scope": "powershell",
"prefix": "event",
"body": [
" -ErrorVariable ProcessError",
"if ($$ProcessError -ne $$null)",
"{",
" Write-EventLog –LogName $$evntlog –Source $$source –EntryType Error –EventID –Message '$$ProcessError'",
" $$ProcessError = $null",
" $$err = 'true'",
"}",
],
"description": "Error Process and write error to Event Log"
},

"LogFile": {
"scope": "powershell",
"prefix": "log",
"body": [
"$$mydate = Get-Date",
"Add-content $$Logfile -value '$$mydate; '"
],
"description": "Write to log file"
},

"LogFile_ErrorCatch": {
"scope": "powershell",
"prefix": "log",
"body": [
" -ErrorVariable ProcessError",
"if ($$ProcessError -ne $$null)",
"{",
" $$mydate = Get-Date",
" Add-content $$Logfile -value '$$mydate; $$ProcessError'",
" $$ProcessError = $null",
" $$err = 'true'"
"}",
],
"description": "Error Process and write error to log file"
},

Additional reading and information:
Using VSCode snippets to apply your script template – http://michaelschultz.net/tech/using-vscode-snippets-to-apply-your-script-template/
Write-EventLog – https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/write-eventlog?view=powershell-5.1
Error handling in PowerShell – https://blogs.technet.microsoft.com/heyscriptingguy/2014/07/09/handling-errors-the-powershell-way/