My coworker and I have recently had a little bit of fun with status messages, using them to trigger emails and other alerts to admins etc. In playing with them, I was curious on just how many there were, or could be rather. I then stumbled across this technet gallery post. So, yes you can do whatever you are trying to track and view all status messages that are sent to CM but, this may be useful in helping narrow that down ahead of time.
So, here we go.
Using and expanding on the PowerShell script in the technet post, I think I was able to derive all the possible status messages from the DLLs.
If you browse to <ConfigurationManager>\bin\X64\system32\smsmsgs. Here you will find 3 DLLs. Each DLL accounts for the 3 different Sources of status messages:
- climsgs.dll -- Client
- provmsgs.dll -- SMS Provider
- srvmsgs.dll -- Site Server
Now, using this modified version of the script (turned into a function)...
Function Get-CMStatusMessages{
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$false,
HelpMessage="Which state messages should I choose")]
[ValidateSet('Client','SMSProvider','SiteServer')]
[string]$MessageSource,
[Parameter(Mandatory=$false,ValueFromPipeline=$false)]
[string]$CMInstallDir = (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\SMS\Identification).'Installation Directory',
[Parameter(Mandatory=$false,ValueFromPipeline=$false)]
[string]$OutputCSV
)
#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
$colMessages = @()
switch ($MessageSource){
'Client'{$stringPathToDLL = "$CMInstallDir\bin\X64\system32\smsmsgs\climsgs.dll"}
'SMSProvider'{$stringPathToDLL = "$CMInstallDir\bin\X64\system32\smsmsgs\provmsgs.dll"}
'SiteServer'{$stringPathToDLL = "$CMInstallDir\bin\X64\system32\smsmsgs\srvmsgs.dll"}
}
#Load Status Message Lookup DLL into memory and get pointer to memory
$ptrFoo = $Win32LoadLibrary::LoadLibrary($stringPathToDLL.ToString())
$ptrModule = $Win32GetModuleHandle::GetModuleHandle($stringPathToDLL.ToString())
#Find Informational Status Messages
for ($iMessageID = 1; $iMessageID -ile 99999; $iMessageID++)
{
$result = $Win32FormatMessage::FormatMessage($flags, $ptrModule, 1073741824 -bor $iMessageID, 0, $stringOutput, $sizeOfBuffer, $stringArrayInput)
if( $result -gt 0)
{
$objMessage = New-Object System.Object
$objMessage | Add-Member -type NoteProperty -name MessageID -value $iMessageID
$objMessage | Add-Member -type NoteProperty -name MessageString -value $stringOutput.ToString().Replace("%11","").Replace("%12","").Replace("%3%4%5%6%7%8%9%10","")
$objMessage | Add-Member -type NoteProperty -name Severity -value "Informational"
$objMessage | Add-Member -type NoteProperty -name Source -value "$MessageSource"
$colMessages += $objMessage
}
}
#Find Warning Status Messages
for ($iMessageID = 1; $iMessageID -ile 99999; $iMessageID++)
{
$result = $Win32FormatMessage::FormatMessage($flags, $ptrModule, 2147483648 -bor $iMessageID, 0, $stringOutput, $sizeOfBuffer, $stringArrayInput)
if( $result -gt 0)
{
$objMessage = New-Object System.Object
$objMessage | Add-Member -type NoteProperty -name MessageID -value $iMessageID
$objMessage | Add-Member -type NoteProperty -name MessageString -value $stringOutput.ToString().Replace("%11","").Replace("%12","").Replace("%3%4%5%6%7%8%9%10","")
$objMessage | Add-Member -type NoteProperty -name Severity -value "Warning"
$objMessage | Add-Member -type NoteProperty -name Source -value "$MessageSource"
$colMessages += $objMessage
}
}
#Find Error Status Messages
for ($iMessageID = 1; $iMessageID -ile 99999; $iMessageID++)
{
$result = $Win32FormatMessage::FormatMessage($flags, $ptrModule, 3221225472 -bor $iMessageID, 0, $stringOutput, $sizeOfBuffer, $stringArrayInput)
if( $result -gt 0)
{
$objMessage = New-Object System.Object
$objMessage | Add-Member -type NoteProperty -name MessageID -value $iMessageID
$objMessage | Add-Member -type NoteProperty -name MessageString -value $stringOutput.ToString().Replace("%11","").Replace("%12","").Replace("%3%4%5%6%7%8%9%10","")
$objMessage | Add-Member -type NoteProperty -name Severity -value "Error"
$objMessage | Add-Member -type NoteProperty -name Source -value "$MessageSource"
$colMessages += $objMessage
}
}
If($OutputCSV){
$colMessages|Export-Csv -Path $OutputCSV -NoTypeInformation -Append
}else{
$colMessages
}
}
I can derive what I think are all the possible status messages with these:
Get-CMStatusMessages -MessageSource Client -OutputCSV C:\statusmessages.csv
Get-CMStatusMessages -MessageSource SiteServer -OutputCSV C:\statusmessages.csv
Get-CMStatusMessages -MessageSource SMSProvider -OutputCSV C:\statusmessages.csv
And just like that, we have a list of over 2800 status messages that includes the Message ID, Description, Severity, and Source
Anyway. Maybe this is useful to someone... :)
Add new comment