Script for CMTrace compatible logging

This is a repost of my script for creating cmtrace compatible log entries. I know there are several out there, but this is mine, and I like it! So here it is! I have this on my github site as well (see link above).

I tried to put the description of what I’m doing in the comments, so you’ll find most of the information in there.

function New-CmnLogEntry {
    <#
    .SYNOPSIS
        Writes log entry that can be read by CMTrace.exe

    .DESCRIPTION
        If you set 'logEntries' to $true, it writes log entries to a file. If the file is larger then MaxFileSize, it will rename it to
        *yyyymmdd-HHmmss.log and start a new file. You can specify if it's an (1) informational, (2) warning, or (3) error message as well.
        It will also add time zone information, so if you have machines in multiple time zones, you can convert to UTC and make sure you know
        exactly when things happened.
        
        Will always write the entry verbose for troubleshooting

    .PARAMETER entry
        This is the text that is the log entry.

    .PARAMETER type
        Defines the type of message, 1 = Informational (default), 2 = Warning, and 3 = Error.

    .PARAMETER component
        Specifies the Component information. This could be the name of the function or thread, or whatever you like, to further help identify what is being logged.

    .PARAMETER logFile
        File for writing logs to (default is C:\Windows\temp\error.log).

    .PARAMETER logEntries
        Set to $true to write to the log file. Otherwise, it will just be write-verbose (default is $false).

    .PARAMETER maxLogSize
        Max size for the log (default is 5MB).

    .PARAMETER maxLogHistory
        Specifies the number of history log files to keep (default is 5).

    .EXAMPLE
        New-CmnLogEntry -entry "Machine $computerName needs a restart." -type 2 -component 'Installer' -logFile $logFile -logEntries -MaxLogSize 10485760

        This will add a warning entry, after expanding $computerName from the compontent Installer to the logfile and roll it over if it exceeds 10MB

    .LINK
        http://configman-notes.com

    .NOTES
        Author:     James Parris
        Contact:    jim@ConfigMan-Notes.com
        Created:    2016-03-22
        Updated:    2017-03-01  Added log rollover
                    2018-10-23  Added Write-Verbose
                                Added adjustment in TimeZond for Daylight Savings Time
                                Corrected time format for renaming logs because I'm an idiot and put 3 digits in the minute field.
        PSVer:	    3.0
        Version:    2.0
    #>
    
    [CmdletBinding(ConfirmImpact = 'Low')]
    Param
    (
        [Parameter(Mandatory = $true, HelpMessage = 'This is the text that is the log entry.')]
        [String]$entry,

        [Parameter(Mandatory = $true, HelpMessage = 'Defines the type of message, 1 = Informational (default), 2 = Warning, and 3 = Error.')]
        [ValidateSet(1, 2, 3)]
        [INT32]$type,

        [Parameter(Mandatory = $true, HelpMessage = 'Specifies the Component information. This could be the name of the function or thread, or whatever you like, to further help identify what is being logged.')]
        [String]$component,

        [Parameter(Mandatory = $false, HelpMessage = 'File for writing logs to (default is C:\Windows\temp\error.log).')]
        [String]$logFile = 'C:\Windows\temp\error.log',

        [Parameter(Mandatory = $false, HelpMessage = 'Set to $true to write to the log file. Otherwise, it will just be write-verbose (default is $false).')]
        [Boolean]$logEntries = $false,

        [Parameter(Mandatory = $false, HelpMessage = 'Max size for the log (default is 5MB).')]
        [Int]$maxLogSize = 5242880,

        [Parameter(Mandatory = $false, HelpMessage = 'Specifies the number of history log files to keep (default is 5).')]
        [Int]$maxLogHistory = 5
    )

    # Get Timezone info
    $now = Get-Date
    $tzInfo = [System.TimeZoneInfo]::Local
    
    # Get Timezone Offset
    $tzOffset = $tzInfo.BaseUTcOffset.Negate().TotalMinutes
    
    # If it's daylight savings time, we need to adjust
    if ($tzInfo.IsDaylightSavingTime($now)) {
        $tzAdjust = ((($tzInfo.GetAdjustmentRules()).DaylightDelta).TotalMinutes)[0]
        $tzOffset -= $tzAdjust
    }

    # Now, to figure out the format. if the timezone adjustment is posative, we need to represent it as +###
    if ($tzOffset -ge 0) {
        $tzOffset = "$(Get-Date -Format "HH:mm:ss.fff")+$($tzOffset)"
    }
    # Otherwise, we need to represent it as -###
    else {
        $tzOffset = "$(Get-Date -Format "HH:mm:ss.fff")$tzOffset"
    }

    # Create entry line, properly formatted
    $cmEntry = "<![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

    if ($PSBoundParameters['logEntries']) {
        # Now, see if we need to roll the log
        if (Test-Path $logFile) {
            # File exists, now to check the size
            if ((Get-Item -Path $logFile).Length -gt $MaxLogSize) {
                # Rename file
                $backupLog = ($logFile -replace '\.log$', '') + "-$(Get-Date -Format "yyyymmdd-HHmmss").log"
                Rename-Item -Path $logFile -NewName $backupLog -Force
                # Get filter information
                # First, we do a regex search, and just get the text before the .log and after the \
                $logFile -match '(\w*).log' | Out-Null
                # Now, we add a trailing * for the filter
                $logFileName = "$($Matches[1])*"
                # Get the path for the log so we know where to search
                $logPath = Split-Path -Path $logFile
                # And we remove any extra rollover logs.
                Get-ChildItem -Path $logPath -Filter $logFileName | Where-Object { $_.Name -notin (Get-ChildItem -Path $logPath -Filter $logFileName | Sort-Object -Property LastWriteTime -Descending | Select-Object -First $maxLogHistory).name } | Remove-Item
            }
        }
        # Finally, we write the entry
        $cmEntry | Out-File $logFile -Append -Encoding ascii
    }
    # Also, we write verbose, just incase that's turned on.
    Write-Verbose $entry
} # End New-CmnLogEntry

Leave a Reply

Your email address will not be published. Required fields are marked *