This page will show all the detailed SCCM component logs if they are on warning or critical status. It requires PowerShell Universal to display the data on the website. ( You can also just use the code generated just to use HTML & IIS to show the data)
# SCCM Server Log on Components
# Rui Qiu
# 9/3/2021
# Setup Parameters
$SiteServer = "XXX"
$SiteCode = "XXX"
$script:SMSMSGSLocation = "$env:SMS_ADMIN_UI_PATH\00000409"
$script:dataSource = 'XXX'
$script:database = 'CM_XXX'
# Number of Status messages to report
$SMCount = 20
# Tally interval - see https://docs.microsoft.com/en-us/sccm/develop/core/servers/manage/about-configuration-manager-tally-intervals
$TallyInterval = '0001128000100008'
# Function to sql data
function Get-SQLData {
param($Query)
$connectionString = "Server=$dataSource;Database=$database;Integrated Security=SSPI;"
$connection = New-Object -TypeName System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = $Query
$reader = $command.ExecuteReader()
$table = New-Object -TypeName 'System.Data.DataTable'
$table.Load($reader)
$connection.Close()
return $Table
}
# Function to get the status message description
function Get-StatusMessage {
param (
$MessageID,
[ValidateSet("srvmsgs.dll","provmsgs.dll","climsgs.dll")]$DLL,
[ValidateSet("Informational","Warning","Error")]$Severity,
$InsString1,
$InsString2,
$InsString3,
$InsString4,
$InsString5,
$InsString6,
$InsString7,
$InsString8,
$InsString9,
$InsString10
)
# Set the resources dll
Switch ($DLL)
{
"srvmsgs.dll" { $stringPathToDLL = "$SMSMSGSLocation\srvmsgs.dll" }
"provmsgs.dll" { $stringPathToDLL = "$SMSMSGSLocation\provmsgs.dll" }
"climsgs.dll" { $stringPathToDLL = "$SMSMSGSLocation\climsgs.dll" }
}
# Load Status Message Lookup DLL into memory and get pointer to memory
$ptrFoo = $Win32LoadLibrary::LoadLibrary($stringPathToDLL.ToString())
$ptrModule = $Win32GetModuleHandle::GetModuleHandle($stringPathToDLL.ToString())
# Set severity code
Switch ($Severity)
{
"Informational" { $code = 1073741824 }
"Warning" { $code = 2147483648 }
"Error" { $code = 3221225472 }
}
# Format the message
$result = $Win32FormatMessage::FormatMessage($flags, $ptrModule, $Code -bor $MessageID, 0, $stringOutput, $sizeOfBuffer, $stringArrayInput)
if ($result -gt 0)
{
# Add insert strings to message
$objMessage = New-Object System.Object
$objMessage | Add-Member -type NoteProperty -name MessageString -value $stringOutput.ToString().Replace("%11","").Replace("%12","").Replace("%3%4%5%6%7%8%9%10","").Replace("%1",$InsString1).Replace("%2",$InsString2).Replace("%3",$InsString3).Replace("%4",$InsString4).Replace("%5",$InsString5).Replace("%6",$InsString6).Replace("%7",$InsString7).Replace("%8",$InsString8).Replace("%9",$InsString9).Replace("%10",$InsString10)
}
Return $objMessage
}
# Start the job
# SQL query for component status
$Query = "
Select
ComponentName,
ComponentType,
Case
when Status = 0 then 'OK'
when Status = 1 then 'Warning'
when Status = 2 then 'Critical'
End as 'Status',
Case
when State = 0 then 'Stopped'
when State = 1 then 'Started'
when State = 2 then 'Paused'
when State = 3 then 'Installing'
when State = 4 then 'Re-installing'
when State = 5 then 'De-installing'
End as 'State',
Case
When AvailabilityState = 0 then 'Online'
When AvailabilityState = 3 then 'Offline'
When AvailabilityState = 4 then 'Unknown'
End as 'AvailabilityState',
Infos,
Warnings,
Errors
from vSMS_ComponentSummarizer
where TallyInterval = N'$TallyInterval'
and MachineName = '$SiteServer'
and SiteCode = '$SiteCode '
and Status in (1,2)
Order by Status,ComponentName
"
$Results = Get-SQLData -Query $Query | ForEach-Object {
@{
ComponentName = $_.ComponentName
Status = $_.Status
Infos = $_.Infos
Warnings = $_.Warnings
Errors = $_.Errors
}
}
# Setting up the table columns
$Columns = @(
New-UDTableColumn -Property ComponentName -Title "Component Name"
New-UDTableColumn -Property Status -Title Status
New-UDTableColumn -Property Infos -Title Infos
New-UDTableColumn -Property Warnings -Title Warnings
New-UDTableColumn -Property Errors -Title Errors
)
# Setting up a table to display the summery data
New-UDTable -Data $Results -Columns $Columns -ShowSort -Title 'Components in a Warning or Error State' -ShowSearch -Dense -Export
New-UDElement -tag 'div' -attributes @{
style = @{
height = '20px'
}
}
# If any components are on warning or critial status, will get detailed log
If ($Results)
{
# Start PInvoke Code
$sigFormatMessage = @'
[DllImport("kernel32.dll")]
public static extern uint FormatMessage(uint flags, IntPtr source, uint messageId, uint langId, StringBuilder buffer, uint size, string[] arguments);
'@
$sigGetModuleHandle = @'
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
'@
$sigLoadLibrary = @'
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string lpFileName);
'@
$Win32FormatMessage = Add-Type -MemberDefinition $sigFormatMessage -name "Win32FormatMessage" -namespace Win32Functions -PassThru -Using System.Text
$Win32GetModuleHandle = Add-Type -MemberDefinition $sigGetModuleHandle -name "Win32GetModuleHandle" -namespace Win32Functions -PassThru -Using System.Text
$Win32LoadLibrary = Add-Type -MemberDefinition $sigLoadLibrary -name "Win32LoadLibrary" -namespace Win32Functions -PassThru -Using System.Text
#End PInvoke Code
$sizeOfBuffer = [int]16384
$stringArrayInput = {"%1","%2","%3","%4","%5", "%6", "%7", "%8", "%9"}
$flags = 0x00000800 -bor 0x00000200
$stringOutput = New-Object System.Text.StringBuilder $sizeOfBuffer
# Process each resulting component
Foreach ($Result in $Results)
{
# Query SQL for status messages
$Component = $Result.ComponentName
$SMQuery = "
select
top $SMCount
smsgs.RecordID,
CASE smsgs.Severity
WHEN -1073741824 THEN 'Error'
WHEN 1073741824 THEN 'Informational'
WHEN -2147483648 THEN 'Warning'
ELSE 'Unknown'
END As 'SeverityName',
case smsgs.MessageType
WHEN 256 THEN 'Milestone'
WHEN 512 THEN 'Detail'
WHEN 768 THEN 'Audit'
WHEN 1024 THEN 'NT Event'
ELSE 'Unknown'
END AS 'Type',
smsgs.MessageID,
smsgs.Severity,
smsgs.MessageType,
smsgs.ModuleName,
modNames.MsgDLLName,
smsgs.Component,
smsgs.MachineName,
smsgs.Time,
smsgs.SiteCode,
smwis.InsString1,
smwis.InsString2,
smwis.InsString3,
smwis.InsString4,
smwis.InsString5,
smwis.InsString6,
smwis.InsString7,
smwis.InsString8,
smwis.InsString9,
smwis.InsString10
from v_StatusMessage smsgs
join v_StatMsgWithInsStrings smwis on smsgs.RecordID = smwis.RecordID
join v_StatMsgModuleNames modNames on smsgs.ModuleName = modNames.ModuleName
where smsgs.MachineName = '$SiteServer'
and smsgs.Component = '$Component'
and smsgs.Severity in ('-1073741824','-2147483648')
Order by smsgs.Time DESC
"
$StatusMsgs = Get-SQLData -Query $SMQuery
# Put desired fields into an object for each result
$StatusMessages = @()
foreach ($Row in $StatusMsgs)
{
$Params = @{
MessageID = $Row.MessageID
DLL = $Row.MsgDLLName
Severity = $Row.SeverityName
InsString1 = $Row.InsString1
InsString2 = $Row.InsString2
InsString3 = $Row.InsString3
InsString4 = $Row.InsString4
InsString5 = $Row.InsString5
InsString6 = $Row.InsString6
InsString7 = $Row.InsString7
InsString8 = $Row.InsString8
InsString9 = $Row.InsString9
InsString10 = $Row.InsString10
}
$Message = Get-StatusMessage @params
$StatusMessage = New-Object psobject
Add-Member -InputObject $StatusMessage -Name Severity -MemberType NoteProperty -Value $Row.SeverityName
Add-Member -InputObject $StatusMessage -Name Type -MemberType NoteProperty -Value $Row.Type
Add-Member -InputObject $StatusMessage -Name SiteCode -MemberType NoteProperty -Value $Row.SiteCode
Add-Member -InputObject $StatusMessage -Name "Date / Time" -MemberType NoteProperty -Value $Row.Time
Add-Member -InputObject $StatusMessage -Name System -MemberType NoteProperty -Value $Row.MachineName
Add-Member -InputObject $StatusMessage -Name Component -MemberType NoteProperty -Value $Row.Component
Add-Member -InputObject $StatusMessage -Name Module -MemberType NoteProperty -Value $Row.ModuleName
Add-Member -InputObject $StatusMessage -Name MessageID -MemberType NoteProperty -Value $Row.MessageID
Add-Member -InputObject $StatusMessage -Name Description -MemberType NoteProperty -Value $Message.MessageString
$StatusMessages += $StatusMessage
}
#Displaying Data
$StatusMessages| ForEach-Object {
@{
Severity = $_.Severity
Date = $_.'Date / Time'
Description = $_.Description
}
}
$Columns = @(
New-UDTableColumn -Property Description -Title Description
New-UDTableColumn -Property Severity -Title Severity
New-UDTableColumn -Property 'Date / Time' -Title Date
)
New-UDTable -Data $StatusMessages -Columns $Columns -ShowSort -Title $Component -ShowSearch -Dense -Export
New-UDElement -tag 'div' -attributes @{
style = @{
height = '20px'
}
}
}
}