#region Function Import-CMTLogFile
Function Import-CMTLogFile {
<#
.SYNOPSIS
Imports SMS/SCCM CMT-formatted log files into a PSObject
.DESCRIPTION
Parses log files that conforms to CMTrace32 structure.
Returns a PScustomObject with the following properties:
LogPath
Size
Entries
Line
Date
Informations
Warnings
Errors
.PARAMETER LogFile
Full path to the CMT-formatted logfile.
Supports WildCard path, too!
.EXAMPLE
Import-CMTLogFile -LogFilePath "$SCCMLogFolder\InventoryAgent.log"
.EXAMPLE
$InventoryLogObj = Import-CMTLogFile -LogFilePath "$SCCMLogFolder\InventoryAgent.log"
ForEach( $Line in $($InventoryLogObj.Entries) ) {
If ( $Line.Message -match "Inventory: Opening store for action" ) {
Write-log "Found Opening store[$($Line.Message)]"
} ElseIf ( ($Line.Message -match "Inventory: Successfully sent report.") -and $ActionName ) {
Write-log "Found Inv Success [$($Line.Date)]"
} ElseIf ( $Line.Message -match "End of message processing" ) {
write-log "Found End ************************ [$($Line.Date)]"
}
}
.NOTES
Author: Denis St-Pierre (Ottawa, Canada)
-NOT tested on Windows 10.
-Based on https://gallery.technet.microsoft.com/scriptcenter/Parse-Log-af34186e
-Added handling BackAss American Date format (otherwise it only works for the first 12 days each month!)
-Added merging multi-line CMT entries into ONE line instead of blowing up
-Added Error handling
-Tested on CM2007
#>
[CmdletBinding()]
Param (
[parameter(Mandatory=$true)]
[ValidateNotNullorEmpty()]
[String]$LogFilePath
)
begin {
## Get the name of this function and write header
[string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
}
process {
Try {
#NOTE: If Path Validation is done in Params, Entire Function errors out. So we do it here
If (-not ( $(Try {Test-Path -LiteralPath $LogFilePath -PathType 'Leaf' } Catch { $false }) ) ) {
Write-Log "Unable to find [$LogFilePath]: $($_.Exception.Message)" -Source ${CmdletName} -Severity 3
Return
}
$LogFileObj = Get-ChildItem $LogFilePath -Force
$LogFilePathObject = New-Object psobject
Add-Member -InputObject $LogFilePathObject -MemberType NoteProperty -Name LogPath -Value $LogFileObj.FullName | Out-Null
Add-Member -InputObject $LogFilePathObject -MemberType NoteProperty -Name Size -Value $($LogFileObj.Length) | Out-Null
[Int32]$ERR = 0
[Int32]$WARN = 0
[Int32]$INFO = 0
[Array]$LogEntries = @()
[Array]$LogContent = Get-Content -Path $LogFilePath
Foreach($LogLine in $LogContent) {
#merge multi-line entries into ONE line
If ($LogLine -notmatch ']LOG]!><time="') {
$LogLinePart = $LogLinePart+$LogLine
Continue #Skip to grab next chuck $LogLine
} elseif ( ( $LogLinePart ) -and ($LogLine -match ']LOG]!><time="') ) {
#Oh, we have the line with the Time stamp. combine and let it goes through
$LogLinePart = $LogLinePart+$LogLine
$LogLine = $LogLinePart
Remove-Variable LogLinePart -ErrorAction SilentlyContinue
}
$LineObj = New-Object psobject
Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Message -Value $($($LogLine.Replace("<![LOG[","")) -split ']LOG]!>')[0] | Out-Null
#Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Time -Value $($($LogLine -split 'time="')[-1] -split '"')[0] | Out-Null
#Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Date -Value $(Get-Date $($($LogLine -split 'date="')[-1] -split '"')[0]) | Out-Null
#Make it handle BackAss American Date format (otherwise it only works for the first 12 days each month!)
[String]$DTString = $($($($($LogLine -split 'date="')[-1] -split '"'))[0] + '.' + $($($($LogLine -split 'time="')[-1] -split '"')[0].Split('.'))[0])
Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Date -Value $([datetime]::ParseExact( $DTString,"MM-dd-yyyy.HH:mm:ss",$null)) | Out-Null
Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Component -Value $($($LogLine -split 'component="')[-1] -split '"')[0] | Out-Null
Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Context -Value $($($LogLine -split 'context="')[-1] -split '"')[0] | Out-Null
Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Thread -Value ([int]$($($LogLine -split 'thread="')[-1] -split '"')[0]) | Out-Null
Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Source -Value $($($LogLine -split 'file="')[-1] -split '"')[0] | Out-Null
Add-Member -InputObject $LineObj -MemberType NoteProperty -Name Servity -Value ([int]$($($LogLine -split 'type="')[-1] -split '"')[0]) | Out-Null
Switch($LineObj.Servity) {
1{$INFO++}
2{$WARN++}
3{$ERR++}
}
$LogEntries += $LineObj
Remove-Variable LineObj -Force -ErrorAction SilentlyContinue | Out-Null
}
Add-Member -InputObject $LogFilePathObject -MemberType NoteProperty -Name Entries -Value $LogEntries | Out-Null
Add-Member -InputObject $LogFilePathObject -MemberType NoteProperty -Name Informations -Value $INFO | Out-Null
Add-Member -InputObject $LogFilePathObject -MemberType NoteProperty -Name Warnings -Value $WARN| Out-Null
Add-Member -InputObject $LogFilePathObject -MemberType NoteProperty -Name Errors -Value $ERR | Out-Null
$LogFilePathObject #Returns PS object
} Catch {
Write-Log "Unable to parse line [$LogLine] of [$LogFilePath]: $($_.Exception.Message)" -Source ${CmdletName} -Severity 3
Return
}
}
end {
Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -Footer
}
}
#endregion Function Import-CMTLogFile