SMDR phone logging
2012-Apr-09, Monday 10:59 amAmong the hodge-podge of responsibilities I have at my job, I also manage 6 PBX phone systems of the Mitel / Intertel CS-5000 family. Thanks to a useful hint that my boss found in a Perl script via Google, I was able to establish phone system logging using Powershell. My programming will save us over $10,000 that we would have been charged by our vendor. That's half my annual salary, so I've earned my keep for a while. :)
I've redacted some of the details from my code for security reasons, but I wanted to make the source code public so it's easier for the next person to find useful material through a web search engine.
# log-smdr.ps1
# This Powershell script connects to a Mitel/Intertel CS-5000 series phone system,
# directs it to open its SMDR stream, then logs the results to a text file.
# Station Message Detail Recording (SMDR) is a system feature that provides
# a detailed record of outgoing and incoming calls.
# This script is intended to be restarted at midnight each night.
# Turning on SMDR reporting is a two-step process in DbStudio Session Manager.
# 1) System / Maintenance / SMDR, set "SMDR Output Active" to yes
# ("Output Port" should already be set to "NONE")
# 2) System / Sockets / SMDR, set "Enable" to yes
# (System / Cabinet / Sockets / SMDR, in some older systems)
# http://technologyordie.com/mitel-5000-smdr-script (example perl script)
# http://www.codeproject.com/Articles/12893/TCP-IP-Chat-Application-Using-C
param ([string]$site='needparm', [string]$logdir='C:\script\log\', [boolean]$debug=$false)
# convert $site parameter into ip/port combination
switch ($site) {
'S1' { $ip='192.168.0.1'; $port=4000 }
'S2' { $ip='192.168.0.1'; $port=4000 }
'S3' { $ip='192.168.0.1'; $port=4000 }
default { $ip='192.168.0.1'; $port=4000 }
}
# find a new filename for logging this session
$scriptps1 = $MyInvocation.MyCommand.Name
$scriptname = $scriptps1.substring(0,($scriptps1.length - 4))
$datelog = get-date -f 'yyyyMMdd'
$version = 0
do {
$version += 1
$filelog = $logdir + $scriptname + '.' + $datelog + '.' + $site + '.' + $version + '.txt'
} while (test-path $filelog)
set-content $filelog $null
if ($debug) {write-host 'logfile:' $filelog}
# create a tcp socket and a destination
# fyi, the TcpClient object did not work with SMDR (perhaps some default values interfered?)
# so I took it down a layer to the Socket object which works nicely
$sockfam = [System.Net.Sockets.AddressFamily]::InterNetwork
$socktype = [System.Net.Sockets.SocketType]::Stream
$sockpro = [System.Net.Sockets.ProtocolType]::TCP
$socket = New-Object System.Net.Sockets.Socket $sockfam, $socktype, $sockpro
$ipaddr = [System.Net.IpAddress]::Parse($ip)
$ipdest = New-Object System.Net.IPEndPoint $ipaddr, $port
# establish the connection
if ($debug) {write-host 'connecting:' $ip ':' $port}
$socket.Connect($ipdest)
if ($socket.Connected -eq $false) {
if ($debug) {write-host 'connection: FAILED'}
return
}
if ($debug) {write-host 'connection: OPEN'}
# send the SMDR command ASCII character string (no password)
# 2 002 02 00000010 STX Start of Text
# 0 000 00 00000000 NUL Null char
# 132 204 84 10000100 „ Double low-9 quotation mark
$cmd = @([byte]2,[byte]0,[byte]0,[byte]0,[byte]132,[byte]0)
$socket.Send($cmd)
if ($debug) {write-host 'connection: CMD SENT'}
# the socket's .Receive() will Block, causing the program to freeze until bytes are received,
# so set up a stream which provides the useful .DataAvailable property instead
# incoming records are always 86 bytes long
$bytes = new-object System.Byte[] 86
$stream = new-object System.Net.Sockets.NetworkStream($socket)
do {
start-sleep -m 1000
if ($stream.DataAvailable) {
$socket.Receive($bytes) | out-null # script hangs here until bytes are received
$result = [System.Text.Encoding]::ASCII.GetString($bytes[0..84]) # ignore trailing CR/LF
if ($debug) {write-host $result}
add-content $filelog $result # append data to text log file
}
$datetest = get-date -f 'yyyyMMdd'
} while ($datetest -eq $datelog)
if ($debug) {write-host 'connection: CLOSING'}
$socket.close()
if ($debug) {write-host 'connection: CLOSED'}
$socket = $null
You turn on SMDR by using the DbStudio Session Manager software that comes with your PBX system. That application directory also contains \DiagMon\Diagmon.exe, a program that can also be used to monitor (but not log, that I can tell) SMDR output from your phone panels. I intend to use DiagMon with packet sniffing software to reverse engineer the protocol for handling password-enabled SMDR. It's really hard to come by programmer-focused PBX documentation. I even contacted Mitel, but they defer to local vendors who have a financial disincentive to provide such documentation. :(Here's a redacted version of the debug output from this script:
My next project will take these .TXT log files, parse them, and store the data fields in a SQL Server table. Then I can do lots of fun stuff like calculate the average length of time that people are spending in our phone tree before they reach a live person, or determine if people are hanging up in frustration before reaching any person.connecting to 192.168.0.1 : 4000 connection: OPEN 6 connection: CMD SENT Q Station Message Detailed Recording 17:01:24 04-07-2012 Q TYP EXT# TRUNK DIALED DIGITS START ELAPSED COST ACCOUNT CODE Q R NET 1234 P0001 94567 17:11 00:03:34 $00.00 R NET 1234 P0001 95678 17:16 00:00:09 $00.00 R NET 2345 P0001 96789 17:21 00:00:14 $00.00 R IN 3456 90001 17:19 00:04:56 $00.00