Do you ever find yourself staring at a wall of plaintext log entries, scrolling endlessly to find that one error buried somewhere in the middle?

If you work with PowerShell scripts, Microsoft Intune deployments, or anything that generates log files, having the right log viewer makes all the difference. For me, that tool has always been CMTrace - and the CMTrace-compatible log format has become my go-to convention for every script I build.

I first discovered CMTrace through colleagues and peers who worked with Microsoft Configuration Manager. I have never worked with Configuration Manager myself, but CMTrace quickly spread through the community as the go-to log viewer - and for good reason. Once you experience a proper log viewer with structured columns and real-time updates, plain Notepad just does not cut it anymore.

The challenge is that CMTrace ships as part of Configuration Manager. So how do you get it if you are not running Configuration Manager in your environment? And why would you bother writing your logs in a specific format when a simple text file works just fine? Those are the questions worth exploring.

What is CMTrace?

CMTrace is a log file viewer originally built for Configuration Manager. It is designed to read and display log files generated by Configuration Manager components - both client-side and server-side. But its usefulness extends far beyond Configuration Manager.

CMTrace is just a single executable file - no installation required - which makes it easy to carry around and use on any Windows computer. It can open any text-based log file, and when the log follows the CMTrace-compatible format, it unlocks powerful features that make troubleshooting significantly easier.

What makes CMTrace stand out is how it presents log data. Instead of showing you raw text, CMTrace parses each log entry and displays it in a structured table with columns for the message, component, timestamp, and thread. Errors and warnings are highlighted in red and yellow, making it easy to spot problems at a glance.

Some of the features that make CMTrace invaluable for daily troubleshooting:

  • Real-time monitoring: CMTrace can tail a log file as new entries are written, so you can watch your script or deployment progress live.
  • Severity highlighting: Errors appear in red, warnings in yellow, and informational messages in white - no more scanning line by line.
  • Merge multiple logs: Open several log files and merge them into a single chronological view. This is incredibly useful when troubleshooting issues that span multiple components.
  • Filtering: Filter log entries by text, component, or severity to focus on what matters.
  • One-click error navigation: Jump directly to the next error or warning entry in the log.

The CMTrace-compatible log format

The CMTrace-compatible log format follows a Microsoft convention rather than a strict schema. There is no official name for it, but it is commonly referred to as the “CMTrace-compatible log format” or “ConfigMgr log format.”

A typical CMTrace-compatible log entry looks like this:

<![LOG[This is the log message]LOG]!><time="08:30:00.000+000" date="06-15-2023" component="MyScript" context="" type="1" thread="1234" file="MyScript.ps1">

CMTrace-compatible log entry structure

The key elements of each entry are:

ElementDescription
MessageThe actual log text, wrapped in <![LOG[...]LOG]!>
TimeTimestamp with milliseconds and timezone offset
DateDate in MM-DD-YYYY format
ComponentThe component or script name generating the entry
TypeSeverity level: 1 (Information), 2 (Warning), 3 (Error)
ThreadThe process or thread ID
FileThe source file name generating the entry
CMTrace log entry elements

The beauty of this format is that CMTrace can parse it automatically. When you open a log file written in this format, CMTrace displays each entry neatly in its column view with proper severity highlighting.

How to get CMTrace

How to get CMTrace is the question I get asked most often when I recommend it. CMTrace is not available as a standalone download from Microsoft, but there are a few legitimate ways to get it.

From a Configuration Manager client

Getting CMTrace from a Configuration Manager client is the easiest option if you already have one in your environment. You can find it at:

C:\Windows\CCM\CMTrace.exe

Since CMTrace is portable, you can simply copy the executable to a USB drive or a network share and use it on any Windows computer.

From the Configuration Manager evaluation media

Downloading the Configuration Manager evaluation media is the most straightforward official method if you do not have Configuration Manager in your environment. You can get the evaluation version of Microsoft Configuration Manager from the Microsoft Evaluation Center .

You do not need to install Configuration Manager. Simply download the installer and extract it - either by running the executable or using a tool like 7-Zip. Once extracted, navigate to:

SMSSETUP\Tools\CMTrace.exe

This is the official Microsoft-signed version. The evaluation license covers using the tools included in the evaluation release, so you are fully licensed to use CMTrace this way.

From the Configuration Manager toolkit

Microsoft also includes CMTrace as part of the Configuration Manager tools . The toolkit contains several other useful utilities alongside CMTrace that can help with troubleshooting and diagnostics.

Writing CMTrace-compatible logs in PowerShell

Writing CMTrace-compatible logs in PowerShell brings consistency and structure to script troubleshooting. Whether the script is a Microsoft Intune deployment, an app wrapper, an automation helper, or a maintenance task, I always include a Write-Log function that follows the CMTrace log convention. This means every log file can be opened in CMTrace with structured columns and timestamps.

Most Microsoft Intune log files have adopted this same format. If you have ever looked at IntuneManagementExtension.log or other log files in the ..\IntuneManagementExtension\Logs folder, you will recognize it immediately. This is also my preferred folder to write custom log files to, since the content of this folder can be collected using Microsoft Intune diagnostics.

Here is a simplified version of the Write-Log function I use. If you want to explore a more complete implementation, you can find one in my Windows Gecko  project on GitHub.

# Description: Writes a log entry in CMTrace-compatible format
# Elevation may be required - Default log path is under ProgramData

function Write-Log {
    <#
    .SYNOPSIS
        Writes a log entry in CMTrace-compatible format.

    .DESCRIPTION
        The Write-Log function creates structured log entries that follow the CMTrace-compatible
        log format convention. Each entry includes a message, severity level, component name,
        timestamp, and process ID - all formatted so CMTrace can parse and display them in
        a structured column view with severity highlighting.

    .PARAMETER Message
        The log message to write. This is the main text that appears in the CMTrace message
        column.

    .PARAMETER Severity
        The severity level of the log entry. Valid values are Information (1), Warning (2),
        and Error (3). Defaults to Information. CMTrace highlights warnings in yellow and
        errors in red.

    .PARAMETER Component
        The name of the component or script generating the log entry. Defaults to the file
        name of the calling script. This value appears in the CMTrace component column.

    .PARAMETER LogFile
        The full path to the log file. This parameter is required and determines where the
        log entry is written.

    .EXAMPLE
        Write-Log -Message "Configuration failed" -Severity "Error"

    .EXAMPLE
        Write-Log -Message "Script execution started" -LogFile "C:\ProgramData\Logs\Example.log"

    .EXAMPLE
        Write-Log -Message "Retrying operation" -Severity "Warning" -Component "RetryHandler"
    #>
    param (
        [Parameter(Mandatory = $true)]
        [string]$Message,

        [Parameter(Mandatory = $false)]
        [ValidateSet("Information", "Warning", "Error")]
        [string]$Severity = "Information",

        [Parameter(Mandatory = $false)]
        [string]$Component = $($MyInvocation.ScriptName | Split-Path -Leaf),

        [Parameter(Mandatory = $true)]
        [string]$LogFile = $logFile
    )

    # Map severity string to CMTrace type integer
    switch ($Severity) {
        "Information" { $type = 1 }
        "Warning"     { $type = 2 }
        "Error"       { $type = 3 }
    }

    # Build timestamp and datestamp in CMTrace-expected format
    $timestamp = Get-Date -Format "HH:mm:ss.fff+000"
    $datestamp = Get-Date -Format "MM-dd-yyyy"

    # Construct the CMTrace-compatible log entry
    $logEntry = "<![LOG[$Message]LOG]!>" +
        "<time=`"$timestamp`" " +
        "date=`"$datestamp`" " +
        "component=`"$Component`" " +
        "context=`"`" " +
        "type=`"$type`" " +
        "thread=`"$PID`" " +
        "file=`"$Component`">"

    # Write to log file with UTF8 encoding
    Add-Content -Path $LogFile -Value $logEntry -Encoding "UTF8" -ErrorAction "Stop"
}

Write-Log function for CMTrace-compatible logging

Using the function

Using the Write-Log function is straightforward once it is included in your script:

# Description: Example script demonstrating CMTrace-compatible logging
# Elevation is not required - Demonstration script only

$logFile = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\Example.log"

Write-Log -Message "Script execution started"
Write-Log -Message "Processing configuration items..."

try {
    # Your script logic here
    Write-Log -Message "Configuration applied successfully"
}
catch {
    Write-Log -Message "Failed to apply configuration: $_" -Severity "Error"
    exit 1
}

Write-Log -Message "Script execution completed"
exit 0

Example: Using Write-Log in a script

When you open the resulting log file in CMTrace, each entry is displayed in a structured view with the message, component name, and timestamp neatly separated into columns.

Associating CMTrace with log files

One of the most convenient features of CMTrace is the ability to associate it with log file extensions. Once configured, you can open any .log file by simply double-clicking it - CMTrace opens automatically instead of Notepad.

To set up the file association:

  1. Run CMTrace as an administrator.
  2. When CMTrace launches for the first time, it will prompt you to make it the default log viewer. Select Yes.
  3. If you missed the initial prompt, you can set the association manually through Windows settings by associating the .log extension with CMTrace.

You can also associate additional extensions like .lo_ and .lg_ with CMTrace, which are common extensions for archived Configuration Manager log files.

Alternative log viewers

Alternative log viewers are worth knowing about for situations where CMTrace is not available on the machine you are working on. Any text editor - including Notepad - can open a CMTrace-compatible log file since it is still plain text underneath. You lose the structured columns and severity highlighting, but the data is all there.

If you use Visual Studio Code, the CMTrace Log Parser  extension by MPearon brings basic CMTrace-style log parsing directly into the editor. The extension has not been updated in a while, but it still handles the fundamentals - parsing entries into a readable format and making log files easier to navigate without leaving your editor. For those who spend most of their day in Visual Studio Code, it can be a practical fallback when CMTrace itself is not at hand.

That said, for any serious log analysis or real-time monitoring, CMTrace remains the better tool.

Final thoughts

CMTrace has been my preferred log viewer for years, and the CMTrace-compatible log format has become my standard for every PowerShell script that involves logging. The combination of structured log entries and real-time monitoring makes troubleshooting significantly faster and more effective.

If you are writing PowerShell scripts for Microsoft Intune or any other management scenario, I encourage you to adopt this log convention. Your future self - and anyone else who has to troubleshoot your scripts - will thank you.

Happy exploring!

–Jesper

Header image attribution: Image created with help from Adobe Firefly