I like to log things when I code, especially while debugging. I also like how I can watch logs real time with CMTrace, so I wrote a function that writes out the log entries in a format CMTrace can read. To use it, at the beginning of the script you are writing, these are the parameters to add for logging.
1 2 3 4 5 6 7 |
#Parameters in script for New-LogEntry [Parameter(Mandatory=$false,HelpMessage="Sets the Log Level, 1 - Informational, 2 - Warning, 3 - Error")] [Int32]$LogLevel = 2, [Parameter(Mandatory=$false,HelpMessage="Log File Directory")] [String]$LogFileDir = 'C:\Temp\', [Parameter(Mandatory=$false,HelpMessage="Clear any existing log file")] [Switch]$ClearLog |
The LogLevel parameter specifies what level of entries to log. The thing to remember is that you set the level of each entry when you call the script. So you can set the LogLevel to 1 when debugging and 2 or 3 when running the final script. The default is 2.
The LogFileDir parameter specifies the directory where the log file will be put, the default is C:\Temp.
The ClearLog parameter will delete the existing log file in the LogFileDir if it exists.
1 2 3 4 5 6 7 8 9 10 |
#Build variables for New-LogEntry Function $ScriptName = $MyInvocation.MyCommand.Name if(-not ($LogFileDir -match '\\$')){$LogFileDir = "$LogFileDir\"} $LogFile = $ScriptName -replace '(.*)\.ps1', '$1' $LogFile = $LogFileDir + $LogFile + '.log' if($ClearLog) { if(Test-Path $Logfile) {Remove-Item $LogFile} } |
This portion of the script sets the log file name to LogFileDir\ScriptName.log, and clears the logfile if the flag is set.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#Begin New-LogEntry Function Function New-LogEntry { # Writes to the log file Param ( [Parameter(Position=0,Mandatory=$true)] [String] $Entry, [Parameter(Position=1,Mandatory=$false)] [INT32] $type = 1, [Parameter(Position=2,Mandatory=$false)] [String] $component = $ScriptName ) Write-Verbose $Entry if ($type -ge $Script:LogLevel) { if ($Entry.Length -eq 0) { $Entry = 'N/A' } $TZOffset = ([TimeZoneInfo]::Local).BaseUTcOffset.TotalMinutes $TZOffset = "$(Get-Date -Format "HH:mm:ss.fff")+$(-$TZOffset)" $Entry = "<![LOG[{0}]LOG]!><time=""{2}"" date=""{1}"" component=""{5}"" context="""" type=""{4}"" thread=""{3}"">" -f $Entry, (Get-Date -Format "MM-dd-yyyy"), $TZOffset, $pid, $type, $component $Entry | Out-File $Script:LogFile -Append -Encoding ascii } } #End New-LogEntry |
And here’s the function! When you call the function, you pass one required and two optional paramemters. The first, and mandatory, parameter is the entry. This is the information to be logged.
The second parameter is the loglevel, if left out, it will be 1. If you put 2 or 3 it will be registered as warning and highlighted yellow or critical and highlighted red respectively when CMTrace displays the log.
The third parameter is component. I generally put the function name or something that identifies what component in the script is generating the log.
You may have seen this is some of my previous scripts but have added the ClearLog switch.
You can see here, the component changes on the last three lines. That is where the function is calling the log entry.

Hope you can use this little snippet in your code! In parting, here is an example script with all the pieces in place
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# # Below are the parameters the function expects to be passed from the command line, right now it's just the Log parameters # PARAM ( #Parameters in script for New-LogEntry [Parameter(Mandatory=$false,HelpMessage="Sets the Log Level, 1 - Informational, 2 - Warning, 3 - Error")] [Int32]$LogLevel = 2, [Parameter(Mandatory=$false,HelpMessage="Log File Directory")] [String]$LogFileDir = 'C:\Temp\', [Parameter(Mandatory=$false,HelpMessage="Clear any existing log file")] [Switch]$ClearLog ) #Begin New-LogEntry Function. Function New-LogEntry { # Writes to the log file Param ( [Parameter(Position=0,Mandatory=$true)] [String] $Entry, [Parameter(Position=1,Mandatory=$false)] [INT32] $type = 1, [Parameter(Position=2,Mandatory=$false)] [String] $component = $ScriptName ) Write-Verbose $Entry if ($type -ge $Script:LogLevel) { if ($Entry.Length -eq 0) { $Entry = 'N/A' } $TZOffset = ([TimeZoneInfo]::Local).BaseUTcOffset.TotalMinutes $TZOffset = "$(Get-Date -Format "HH:mm:ss.fff")+$(-$TZOffset)" $Entry = "<![LOG[{0}]LOG]!><time=""{2}"" date=""{1}"" component=""{5}"" context="""" type=""{4}"" thread=""{3}"">" -f $Entry, (Get-Date -Format "MM-dd-yyyy"), $TZOffset, $pid, $type, $component $Entry | Out-File $Script:LogFile -Append -Encoding ascii } } #End New-LogEntry #And now for the variable build. #Build variables for New-LogEntry Function $ScriptName = $MyInvocation.MyCommand.Name if(-not ($LogFileDir -match '\\$')){$LogFileDir = "$LogFileDir\"} $LogFile = $ScriptName -replace '(.*)\.ps1', '$1' $LogFile = $LogFileDir + $LogFile + '.log' if($ClearLog) { if(Test-Path $Logfile) {Remove-Item $LogFile} } #Now everything is set. My script can begin New-LogEntry 'Starting Script' #This will create an informational log entry with the script name as the component New-LogEntry "ClearLog - $ClearLog" 2 'Demo' #This will create a warning, showing the variable and having Demo as the component. |