If you’ve ever worked with Configuration manager you’ll understand that there are quite a few logs on the Client side. Opening and searching through them for actions that have taken place can be quite a task. I needed to find when an item was logged during initial startup/build of a vm. So I sought out tools to parse these logs to find out the status of Configuration Manager client side. This post is about the tools/scripts I found and what I added to them to make it easier to discover and parse all the log files.
I started with the need to be able to just parse the log files. I discovered that Rich Prescott in the community had done the work of parsing these log files with this script:
http://blog.richprescott.com/2017/07/sccm-log-parser.html
With that script in had I made two changes to the script. The first change was to allow for all the files in the directory to be added to the return object.
if(($Path -isnot [array]) -and (test-path $Path -PathType Container) ) { $Path = Get-ChildItem "$path\*.log" }
The second change allowed for the user to specify a tail amount. This allows for just a portion of the end of the log to be retrieved instead of the entire log. That script can be found on one of my gists at the Tail end of this article.
if($tail) { $lines = Get-Content -Path $File -tail $tail } else { $lines = get-Content -path $file } ForEach($l in $lines )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-CMLog | |
{ | |
<# | |
.SYNOPSIS | |
Parses logs for System Center Configuration Manager. | |
.DESCRIPTION | |
Accepts a single log file or array of log files and parses them into objects. Shows both UTC and local time for troubleshooting across time zones. | |
.PARAMETER Path | |
Specifies the path to a log file or files. | |
.INPUTS | |
Path/FullName. | |
.OUTPUTS | |
PSCustomObject. | |
.EXAMPLE | |
C:\PS> Get-CMLog -Path Sample.log | |
Converts each log line in Sample.log into objects | |
UTCTime : 7/15/2013 3:28:08 PM | |
LocalTime : 7/15/2013 2:28:08 PM | |
FileName : sample.log | |
Component : TSPxe | |
Context : | |
Type : 3 | |
TID : 1040 | |
Reference : libsmsmessaging.cpp:9281 | |
Message : content location request failed | |
.EXAMPLE | |
C:\PS> Get-ChildItem -Path C:\Windows\CCM\Logs | Select-String -Pattern 'failed' | Select -Unique Path | Get-CMLog | |
Find all log files in folder, create a unique list of files containing the phrase 'failed, and convert the logs into objects | |
UTCTime : 7/15/2013 3:28:08 PM | |
LocalTime : 7/15/2013 2:28:08 PM | |
FileName : sample.log | |
Component : TSPxe | |
Context : | |
Type : 3 | |
TID : 1040 | |
Reference : libsmsmessaging.cpp:9281 | |
Message : content location request failed | |
.LINK | |
http://blog.richprescott.com | |
#> | |
param( | |
[Parameter(Mandatory=$true, | |
Position=0, | |
ValueFromPipelineByPropertyName=$true)] | |
[Alias("FullName")] | |
$Path, | |
$tail =10 | |
) | |
PROCESS | |
{ | |
if(($Path -isnot [array]) -and (test-path $Path –PathType Container) ) | |
{ | |
$Path = Get-ChildItem "$path\*.log" | |
} | |
foreach ($File in $Path) | |
{ | |
if(!( test-path $file)) | |
{ | |
$Path +=(Get-ChildItem "$file*.log").fullname | |
} | |
$FileName = Split-Path –Path $File –Leaf | |
if($tail) | |
{ | |
$lines = Get-Content –Path $File –tail $tail | |
} | |
else { | |
$lines = get-Content –path $file | |
} | |
ForEach($l in $lines ){ | |
$l -match '\<\!\[LOG\[(?<Message>.*)?\]LOG\]\!\>\<time=\"(?<Time>.+)(?<TZAdjust>[+|-])(?<TZOffset>\d{2,3})\"\s+date=\"(?<Date>.+)?\"\s+component=\"(?<Component>.+)?\"\s+context="(?<Context>.*)?\"\s+type=\"(?<Type>\d)?\"\s+thread=\"(?<TID>\d+)?\"\s+file=\"(?<Reference>.+)?\"\>' | Out-Null | |
if($matches) | |
{ | |
$UTCTime = [datetime]::ParseExact($("$($matches.date) $($matches.time)$($matches.TZAdjust)$($matches.TZOffset/60)"),"MM-dd-yyyy HH:mm:ss.fffz", $null, "AdjustToUniversal") | |
$LocalTime = [datetime]::ParseExact($("$($matches.date) $($matches.time)"),"MM-dd-yyyy HH:mm:ss.fff", $null) | |
} | |
[pscustomobject]@{ | |
UTCTime = $UTCTime | |
LocalTime = $LocalTime | |
FileName = $FileName | |
Component = $matches.component | |
Context = $matches.context | |
Type = $matches.type | |
TID = $matches.TI | |
Reference = $matches.reference | |
Message = $matches.message | |
} | |
} | |
} | |
} | |
} | |
function Get-CCMLog | |
{ | |
param([Parameter(Mandatory=$true,Position=0)]$ComputerName = '$env:computername', [Parameter(Mandatory=$true,Position=1)]$path = 'c:\windows\ccm\logs') | |
DynamicParam | |
{ | |
$ParameterName = 'Log' | |
if($path.ToCharArray() -contains ':') | |
{ | |
$FilePath = "\\$($ComputerName)\$($path -replace ':','$')" | |
} | |
else | |
{ | |
$FilePath = "\\$($ComputerName)\$((get-item $path).FullName -replace ':','$')" | |
} | |
$logs = Get-ChildItem "$FilePath\*.log" | |
$LogNames = $logs.basename | |
$logAttribute = New-Object System.Management.Automation.ParameterAttribute | |
$logAttribute.Position = 2 | |
$logAttribute.Mandatory = $true | |
$logAttribute.HelpMessage = 'Pick A log to parse' | |
$logCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] | |
$logCollection.add($logAttribute) | |
$logValidateSet = New-Object System.Management.Automation.ValidateSetAttribute($LogNames) | |
$logCollection.add($logValidateSet) | |
$logParam = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName,[string],$logCollection) | |
$logDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary | |
$logDictionary.Add($ParameterName,$logParam) | |
return $logDictionary | |
} | |
begin { | |
# Bind the parameter to a friendly variable | |
$Log = $PsBoundParameters[$ParameterName] | |
} | |
process { | |
$sb2 = "$((Get-ChildItem function:get-cmlog).scriptblock)`r`n" | |
$sb1 = [scriptblock]::Create($sb2) | |
$results = Invoke-Command –ComputerName $ComputerName –ScriptBlock $sb1 –ArgumentList "$path\$log.log" | |
[PSCustomObject]@{"$($log)Log"=$results} | |
} | |
} |
I hope this helps someone.
Until then
Keep scripting
Thom
One thought on “Parsing CCM\Logs”