mellowtigger: (penguin coder)
[personal profile] mellowtigger
phone operatorThe more I learn about phone system technology, the more I wonder how anything ever works (successfully).

Among 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)

# (example perl script)

param ([string]$site='needparm', [string]$logdir='C:\script\log\', [boolean]$debug=$false)

# convert $site parameter into ip/port combination
switch ($site) {
    'S1' { $ip=''; $port=4000 }
    'S2' { $ip=''; $port=4000 }
    'S3' { $ip=''; $port=4000 }
    default { $ip=''; $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}
if ($socket.Connected -eq $false) {
    if ($debug) {write-host 'connection: FAILED'}
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)
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'}
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:
connecting to : 4000
connection: OPEN
connection: CMD SENT
Q   Station Message Detailed Recording                          17:01:24 04-07-2012
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
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.

Date: 2016-07-12 11:44 pm (UTC)
From: [personal profile] jeremyfish
Hello Mellowtigger,

I know this is a pretty old post, but I am hoping you are available for more information regarding how you accomplished this.


mellowtigger: (Default)

September 2017

1718192021 2223
2425262728 2930

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Oct. 20th, 2017 06:48 am
Powered by Dreamwidth Studios