November 2010 (1)
August 2010 (1)
July 2010 (1)
June 2010 (3)
July 2009 (3)
June 2009 (1)
May 2009 (1)
February 2009 (1)
January 2009 (1)
November 2008 (3)
October 2008 (4)
September 2008 (9)
August 2008 (6)
July 2008 (3)
June 2008 (3)
January 2008 (1)
November 2007 (2)
October 2007 (6)
September 2007 (5)
August 2007 (22)
July 2007 (6)
June 2007 (1)
May 2007 (3)
April 2007 (27)
March 2007 (8)
February 2007 (6)
September 2006 (2)
August 2006 (4)
July 2006 (9)
June 2006 (17)
May 2006 (20)
April 2006 (12)
March 2006 (9)
February 2006 (4)
January 2006 (3)
December 2005 (2)
November 2005 (4)
October 2005 (5)
September 2005 (37)
August 2005 (83)
July 2005 (6)

Active Directory / LDAP (0)
ASP.Net (19)
Blackberry Development (4)
c# (34)
c++ (3)
Code Camp (1)
Excel (1)
Exchange (3)
Front Page 2003 (6)
FTP User Editor (4)
HTML / CSS / DHTML (8)
IIS (146)
IIS - Log Parser (7)
IIS / FTP (12)
IIS / Tools / Administration (42)
IIS / Tools / Authentication (6)
IIS / Tools / Compression (8)
IIS / Tools / Crash & Hang (12)
IIS / Tools / ISAPI Filters (17)
IIS / Tools / Log Files (17)
IIS / Tools / Scripts (28)
IIS / Tools / Security (9)
IIS / Tools / SSL (6)
IIS 7 (3)
Internet Information Server (1)
Me (Chris Crowe) (6)
MIME Types (1)
Misc (72)
Oulook Express (2)
Silverlight (1)
SQL Server (27)
SQL Server CTE (1)
Vista (15)
Vista Gadgets (8)
Visual Studio (11)
Voice over BroadBand (1)
Windows (33)
Windows Powershell (3)
Windows Sharepoint Services (0)
Windows Sharepoint Services (15)
Windows Vista (14)
Wine Cellar (1)
WMI (8)

Archive

October 2008 (4)

Sending a CISCO IP Phone a simple command using C#

Below you will find a simple application to send a simple command via a CiscoIPPhoneText XML statement.

For more details on CISCOIPPhoneText and other XML commands see http://www.cisco.com/en/US/docs/voice_ip_comm/cuipph/all_models/xsi/6_0/english/programming/guide/XSIbook.html

Below is a screen shot of the output on a 7960 series phone

IPPhoneMsg

and the console application when running

image

 

HTTP Server Requests (HTTP POST)

The following description designates how an HTTP server request is made to the phone via an HTTP POST operation:

  1. The server performs an HTTP POST in response to a case-sensitive URL of the phone with this format: http://x.x.x.x/CGI/Execute, where x.x.x.x represents the IP address of the destination Cisco Unified IP Phone.

    The form that is posted should have a case-sensitive form field name called "XML" that contains the desired XML object. For any HTTP POST operation, the server must provide basic HTTP authentication information with the POST. The provided credentials must be of a user in the global directory with a device association with the target phone.

    If the credentials are invalid, or the Authentication URL is not set properly in the Cisco Unified Communications Manager Administration, the phone will return a CiscoIPPhoneError with a value of 4 (Authentication Error) and processing will stop.
  2. The phone processes the supported HTTP headers
  3. The phone parses and validates the XML object
  4. The phone presents data and options to the user, or in the case of a CiscoIPPhoneExecute object, begins executing the URIs.

 

APP.CONFIG

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="CallManagerPushUsername" value="ccrowe-test"></add>
    <add key="CallManagerPushPassword" value="123456"></add>
  </appSettings>

</configuration>

 

Program.CS

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Web;

namespace TestApplication_SendSimpleMessageToPhone
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Send a simple XML Command to a CISCO IP Phone");
            Console.WriteLine();

            string IPAddressOfPhone = "10.3.21.228";
            int HTTPServerTimeoutMS = 30000;
            string PhoneURL = string.Format("http://{0}/CGI/Execute", IPAddressOfPhone);
            string PushXML = "";
            string ResponseXML = "";
            string ErrorCode = "";

            PushXML = @"<CiscoIPPhoneText>";
            PushXML += @"<Title>Title Text Goes Here</Title>";           // Optional Field
            PushXML += @"<Prompt>The prompt text goes here</Prompt>";    // Optional Field
            PushXML += @"<Text>The text to be displayed as the message body</Text>";

            PushXML += @"<SoftKeyItem>"; // Optional Field
            PushXML += @"<Name>Cancel</Name>";
            PushXML += @"<URL>SoftKey:Cancel</URL>";
            PushXML += @"<Position>4</Position>";
            PushXML += @"</SoftKeyItem>";

            PushXML += @"</CiscoIPPhoneText>";

            Console.WriteLine("Sending the following POST data:");
            Console.WriteLine();
            Console.WriteLine(PushXML);
            Console.WriteLine();

            PushXML = "XML=" + HttpUtility.UrlEncode(PushXML);


            WebResponse resp = null;
            try
            {
                ServicePointManager.Expect100Continue = false;
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(PhoneURL);
                req.Timeout = HTTPServerTimeoutMS;
                req.Method = "POST";
                req.Credentials = GetCredentials();
                req.Accept = "*/*";
                req.ContentType = "application/x-www-form-urlencoded";
                req.KeepAlive = false;
                req.Expect = "";

                byte[] bytes = null;
                bytes = System.Text.Encoding.UTF8.GetBytes(PushXML);
                Stream outputStream = req.GetRequestStream();
                outputStream.Write(bytes, 0, bytes.Length);
                outputStream.Close();

                resp = req.GetResponse();
                Stream s = resp.GetResponseStream();
                StreamReader stm = new StreamReader(s);
                if (stm == null)
                {
                    ErrorCode = "Timed out or no response!";
                }
                else
                {
                    ResponseXML = stm.ReadToEnd();
                    stm.Close();
                }
                s.Close();
                resp.Close();
            }
            catch (System.Net.WebException ex)
            {
                string StatusCodeString = ex.Response == null ? "" : (ex.Response as HttpWebResponse).StatusCode.ToString();
                int StatusCodeNumber = ex.Response == null ? -1 : Convert.ToInt32((ex.Response as HttpWebResponse).StatusCode);

                ErrorCode = string.Format("Web Exception : {0}\r\n\r\n" +
                                          "HTTP Status : {1} ({2})\r\n\r\n" +
                                          "Stack Trace:\r\n\r\n{3}",
                                          ex.Message.ToString(),
                                          StatusCodeString, StatusCodeNumber,
                                          ex.ToString());
            }
            catch (Exception ex)
            {
                ErrorCode = string.Format("Exception : {0}\r\n\r\n" +
                                          "Stack Trace:\r\n{1}",
                                          ex.Message.ToString(),
                                          ex.ToString());
            }
            if (ErrorCode.Length > 0)
                Console.WriteLine(ErrorCode);
            else
            {
                Console.WriteLine();
                Console.WriteLine("Received the following XML response");
                Console.WriteLine();
                Console.WriteLine(ResponseXML);
            }
            Console.WriteLine();
            Console.WriteLine("Completed... click ENTER to exit");
            Console.ReadLine();
        }

        private static ICredentials GetCredentials()
        {
            string Username = System.Configuration.ConfigurationManager.AppSettings["CallManagerPushUsername"];
            string Password = System.Configuration.ConfigurationManager.AppSettings["CallManagerPushPassword"];
            return new NetworkCredential(Username, Password);
        }
    }
}

Getting the IP Addresses of Phones from a Cisco Call Manager v6.x using C#

Recently I have needed to get the IP Address of the IP Phones from a Cisco Call Manager version 6.x

On previous versions of the platform (version 4) you should simply call a page DeviceListX.asp (under windows) to return an XML document similar to the following:

<?xml version="1.0" encoding="iso-8859-1"?>
<DeviceList>
  <Device t="115" n="SEP0018BA14AF7E" d="4330 - Sunnyvale Netlab" c="LONG-INTERNATIONAL-CSS" p="LONG-DP" i="" s="" />
  <Device t="115" n="SEP001E4AA8CC00" d="4305 - Scott Sharp" c="LONG-INTERNATIONAL-CSS" p="LONG-DP" i="10.1.206.160" s="1" />
  <Device t="35" n="SEP000E38502B1D" d="Auto 105139" c="SYSTEM-TAPS-CSS" p="SNVL-TAPS-DP" i="" s="" />
  <Device t="36" n="SEP000BFDB81799" d="Auto 105300" c="SYSTEM-TAPS-CSS" p="SNVL-TAPS-DP" i="" s="" />
</DeviceList>

Well I had a lot of problems trying to simply update my code to use the new method which was to use a technology called AXL. AVVID XML Layer (AXL) is a Cisco application programming interface (API) and web service designed to give applications access to Cisco CallManager configuration and provisioning services

For more details on AXL see http://developer.cisco.com/web/axl/home and http://developer.cisco.com/web/axl/docs

Now from what I have gathered to return the IP Address of the phones you need to do two things:

  1. Get a list of the Devices (phones)
  2. Query the RipPort service to get the real time information. the IP Address is stored in this "in memory" database

Below I will attempt to document the process I took to get this to work for me on version 6.x

To start off with

The basic idea is this:

  • Post a request to the Call Manager on port 8443.
  • The request must be made using HTTPS
  • The URI is /realtimeservice/services/{servicename}

So in my case the url was:

https://10.3.4.22:8443/realtimeservice/services/RisPort

Note: The URL is case sensitive since it is running on a Linux OS

You then need to add an HTTP Header called "SOAPAction" and provide it with the name of a SOAP action

SOAPAction : http://schemas.cisco.com/ast/soap/action/#RisPort#SelectCmDevice

Note: At this time I do not know much about this SOAPAction

You then need to craft a SOAP request and POST that to the server.

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:ExecuteCCMSQLStatement soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.cisco.com/ast/soap/">
      <ExecuteSQLInputData xsi:type="xsd:string">select name,description from Device where tkclass = 1 order by name;</ExecuteSQLInputData>
      <GetColumns soapenc:arrayType="ns1:ColumnType[2]" xsi:type="soapenc:Array" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
        <item xsi:type="ns1:ColumnType">
          <Name xsi:type="xsd:string">name</Name>
        </item>
        <item xsi:type="ns1:ColumnType">
          <Name xsi:type="xsd:string">description</Name>
        </item>
      </GetColumns>
    </ns1:ExecuteCCMSQLStatement>
  </soapenv:Body>
</soapenv:Envelope>

As you can see from the above XML I am actually issuing a SQL Query in the SOAP request.

select name,description from Device where tkclass = 1 order by name

There is a table called "Device" which holds all of the devices of the call manager.

I do not know what tkclass is for at this time.

Basically posting that request will return the name, description of the devices in your call manager in a format similar to the following:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:ExecuteCCMSQLStatementResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.cisco.com/ast/soap/">
      <ExcuteSQLOutputData soapenc:arrayType="ns1:ColumnValueType[186]" xsi:type="soapenc:Array" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
        <item xsi:type="ns1:ColumnValueType">
          <Name xsi:type="ns1:ColumnNType">name</Name>
          <Value xsi:type="ns1:ColumnVType">ATA002155021DA5</Value>
        </item>
        <item xsi:type="ns1:ColumnValueType">
          <Name xsi:type="ns1:ColumnNType">description</Name>
          <Value xsi:type="ns1:ColumnVType">4131 - XYZ Fax Machine</Value>
        </item>        
        <item xsi:type="ns1:ColumnValueType">
          <Name xsi:type="ns1:ColumnNType">name</Name>
          <Value xsi:type="ns1:ColumnVType">SEP000BFDCDBA07</Value>
        </item>
        <item xsi:type="ns1:ColumnValueType">
          <Name xsi:type="ns1:ColumnNType">description</Name>
          <Value xsi:type="ns1:ColumnVType">3931 - Chris Crowe</Value>
        </item>       
      </ExcuteSQLOutputData>
    </ns1:ExecuteCCMSQLStatementResponse>
  </soapenv:Body>
</soapenv:Envelope>

I then parsed this XML and returned a simple DataTable with the details

DataTable dt = new DataTable();
dt.Columns.Add("name", typeof(string));
dt.Columns.Add("description", typeof(string));

XmlDocument doc = new XmlDocument();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);

nsmgr.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("ns1", "http://schemas.cisco.com/ast/soap/");
doc.LoadXml(XML);

XmlNodeList items = doc.SelectNodes("/soapenv:Envelope/soapenv:Body/ns1:ExecuteCCMSQLStatementResponse/ExcuteSQLOutputData/item/Value", nsmgr);
for (int Index = 0; Index < items.Count; Index += 2) 
  {
      XmlNode Name = items[Index];
      XmlNode Description = items[Index+1];

      DataRow dr = dt.NewRow();
      dr.ItemArray = new object[] { Name.InnerText, Description.InnerText };
      dt.Rows.Add(dr);
   }
return dt;

So at this point we have a DataTable with one row for each device but no IP Address

So we now build another AXL request similar to the following:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:SelectCmDevice soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.cisco.com/ast/soap/">
      <StateInfo xsi:type="xsd:string"/>
      <CmSelectionCriteria xsi:type="ns1:CmSelectionCriteria">
        <MaxReturnedDevices xsi:type="xsd:unsignedInt">200</MaxReturnedDevices>
        <Class xsi:type="xsd:string">Phone</Class>
        <Model xsi:type="xsd:unsignedInt">255</Model>
        <Status xsi:type="xsd:string">Registered</Status>
        <NodeName xsi:type="xsd:string"/>
        <SelectBy xsi:type="xsd:string">Name</SelectBy>
        <SelectItems soapenc:arrayType="ns1:SelectItem[3]" xsi:type="soapenc:Array" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
          <item xsi:type="ns1:SelectItem">
            <Item xsi:type="xsd:string">ATA002155021DA5</Item>
          </item>
          <item xsi:type="ns1:SelectItem">
            <Item xsi:type="xsd:string">SEP000BFDCDBA07</Item>
          </item>
          <item xsi:type="ns1:SelectItem">
            <Item xsi:type="xsd:string">SEP000C8548D65D</Item>
          </item>
        </SelectItems>
      </CmSelectionCriteria>
    </ns1:SelectCmDevice>
  </soapenv:Body>
</soapenv:Envelope>

Some points about the above request:
  • I believe that there is a limit of 200 devices being requested, but I have not been able to test  it yet as our current system has less than 50 devices on it.
  • The SelectItems tag contains soapenc:arrayType="ns1:SelectItem[3]" the [3] means that there is going to be 3 SelectItem nodes specified later. If you request 50 then this needs to be set to soapenc:arrayType="ns1:SelectItem[50]"
  • Each device you want information on requires one of the following specifying the device name
    <item xsi:type="ns1:SelectItem"> <Item xsi:type="xsd:string">{DeviceName}</Item> </item>

 

SOURCE CODE

Below is the full source to a small library I created to help me get the Phone details and IP Addreses in a format that is the same as the old DeviceListX.asp script.

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Data;
using System.Xml;
using System.Reflection;

namespace AXLLibrary
{
    public enum AXLServiceType
    {
        RisPort = 1

    }

    public class AXLClass
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public string ServerNameOrIPAddress { get; set; }

        public AXLClass(string Username, string Password, string ServerNameOrIPAddress)
        {
            this.Username = Username;
            this.Password = Password;
            this.ServerNameOrIPAddress = ServerNameOrIPAddress;

        }

        // Because of a broken cert we will get an error without ignoring the errors which we do below.
        private bool ServerCertificateValidationCallbackMethod(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            //// Always accept
            //if (sslPolicyErrors != SslPolicyErrors.None)
            //{
            //    Message("<div><font color='red'>SSL Certificate Issues</div><ul>");
            //    Message("<LI>Policy Error -> <b>" + sslPolicyErrors.ToString() + "</b></LI>");
            //    Message("<LI>Issuer       -> <b>" + certificate.Issuer + "</b></LI>");
            //    Message("<LI>Expires      -> <b>" + certificate.GetExpirationDateString() + "</b></LI>");
            //    Message("<LI>Subject      -> <b>" + certificate.Subject + "</b></LI>");
            //}
            return true;
        }

        public string ExecuteSOAPRequest(string SOAPAction, string SoapRequest, AXLServiceType ServiceType)
        {
            Validate();
            try
            {
                ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(ServerCertificateValidationCallbackMethod);
                ServicePointManager.Expect100Continue = true;

                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(GetServiceURI(ServiceType));
                req.KeepAlive = false;
                req.Credentials = GetCredentials();
                req.Headers.Add("SOAPAction", "http://schemas.cisco.com/ast/soap/action/" + SOAPAction);

                req.ContentType = "text/xml";
                req.Accept = "text/xml";
                req.Method = "POST";

                Stream s = req.GetRequestStream();
                s.Write(System.Text.Encoding.ASCII.GetBytes(SoapRequest), 0, SoapRequest.Length);
                s.Close();

                WebResponse resp = req.GetResponse();
                StreamReader sr = new StreamReader(resp.GetResponseStream());
                string XMLResult = sr.ReadToEnd();
                return XMLResult;
            }
            catch (WebException ex)
            {
                throw ex;
            }
        }

        private ICredentials GetCredentials()
        {
            return new NetworkCredential(Username, Password);
        }

        private Uri GetServiceURI(AXLServiceType Service)
        {
            string URI = string.Format("https://{0}:8443/realtimeservice/services/{1}", ServerNameOrIPAddress, Service.ToString());
            return new Uri(URI);
        }

        private void Validate()
        {
            if (Username.Length == 0)
                throw new Exception("Username must have a value!");
            if (Password.Length == 0)
                throw new Exception("Password must have a value!");
            if (ServerNameOrIPAddress.Length == 0)
                throw new Exception("ServerNameOrIPAddress must have a value!");
        }

        public DataTable GetDevices()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("name", typeof(string));
            dt.Columns.Add("description", typeof(string));


            Assembly assembly = Assembly.GetExecutingAssembly();
            Stream stream = assembly.GetManifestResourceStream("AXLLibrary.GetDevices.xml");
            StreamReader streamReader = new StreamReader(stream);
            string soapRequest = streamReader.ReadToEnd();


            string XML = ExecuteSOAPRequest("#RisPort#SelectCmDevice", soapRequest, AXLServiceType.RisPort);
            
            XmlDocument doc = new XmlDocument();
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);

            nsmgr.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
            nsmgr.AddNamespace("ns1", "http://schemas.cisco.com/ast/soap/");
            doc.LoadXml(XML);


            XmlNodeList items = doc.SelectNodes("/soapenv:Envelope/soapenv:Body/ns1:ExecuteCCMSQLStatementResponse/ExcuteSQLOutputData/item/Value", nsmgr);
            for (int Index = 0; Index < items.Count; Index += 2) 
            {
                XmlNode Name = items[Index];
                XmlNode Description = items[Index+1];

                DataRow dr = dt.NewRow();
                dr.ItemArray = new object[] { Name.InnerText, Description.InnerText };
                dt.Rows.Add(dr);
            }
            return dt;

        }

        public DataTable GetDeviceIPAddresses()
        {            
            DataTable dt2 = new DataTable();
            dt2.Columns.Add("name", typeof(string));
            dt2.Columns.Add("Description", typeof(string));
            dt2.Columns.Add("IpAddress", typeof(string));
            dt2.Columns.Add("DirNumber", typeof(string));
            dt2.Columns.Add("Class", typeof(string));
            dt2.Columns.Add("Model", typeof(string));
            dt2.Columns.Add("Product", typeof(string));

            DataTable dt3 = new DataTable();
            dt3.Columns.Add("name", typeof(string));
            dt3.Columns.Add("Description", typeof(string));
            dt3.Columns.Add("IpAddress", typeof(string));
            dt3.Columns.Add("DirNumber", typeof(string));
            dt3.Columns.Add("Class", typeof(string));
            dt3.Columns.Add("Model", typeof(string));
            dt3.Columns.Add("Product", typeof(string));

            DataTable Devices = GetDevices();

            Assembly assembly = Assembly.GetExecutingAssembly();
            Stream stream = assembly.GetManifestResourceStream("AXLLibrary.getDeviceIPAddress.xml");
            StreamReader streamReader = new StreamReader(stream);
            string soapRequest = streamReader.ReadToEnd();

            // Set the # of devices items we are going to be searching for
            soapRequest = soapRequest.Replace("{0}", Devices.Rows.Count.ToString());

            StringBuilder TemplateData = new StringBuilder();
            string Template = "<item xsi:type=\"ns1:SelectItem\"><Item xsi:type=\"xsd:string\">{0}</Item></item>";
            foreach (DataRow dr in Devices.Rows)
                TemplateData.AppendFormat(Template, dr[0].ToString());

            // Set the templates
            soapRequest = soapRequest.Replace("{1}", TemplateData.ToString());

            string XML = ExecuteSOAPRequest("#RisPort#SelectCmDevice", soapRequest, AXLServiceType.RisPort);

           
            XmlDocument doc = new XmlDocument();
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
           
            nsmgr.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
            nsmgr.AddNamespace("ns1", "http://schemas.cisco.com/ast/soap/");
            doc.LoadXml(XML);


            XmlNodeList items = doc.SelectNodes("/soapenv:Envelope/soapenv:Body/ns1:SelectCmDeviceResponse/SelectCmDeviceResult/CmNodes/item/CmDevices/item", nsmgr);
            foreach (XmlNode item in items)
            {
                string Name = GetNodeValue(item, "Name");
                string Description = GetNodeValue(item, "Description");
                string IpAddress = GetNodeValue(item,"IpAddress");
                string DirNumber = GetNodeValue(item, "DirNumber");
                string Class = GetNodeValue(item, "Class");
                string Model = GetNodeValue(item, "Model");
                string Product = GetNodeValue(item, "Product");

                DataRow dr = dt2.NewRow();
                dr.ItemArray = new object[] { Name, Description, IpAddress, DirNumber, Class, Model, Product };
                dt2.Rows.Add(dr);
            }
            DataSet ds = new DataSet();
            DataSetHelper dsHelper = new DataSetHelper(ref ds);
            ds.Tables.Add(Devices);
            ds.Tables.Add(dt2);
            ds.Tables.Add(dt3);

            ds.Relations.Add("NameName", ds.Tables[0].Columns[0], ds.Tables[1].Columns[0]);
            foreach(DataRow dr in ds.Tables[0].Rows)
            {
                DataRow newDataRow = dt3.NewRow();
                DataRow[] Children = dr.GetChildRows(ds.Relations[0]);
                if (Children.Length == 0)
                    newDataRow.ItemArray = dr.ItemArray;
                else
                    newDataRow.ItemArray = Children[0].ItemArray;
                dt3.Rows.Add(newDataRow);
            }
            return dt3;            
        }

        private string GetNodeValue(XmlNode item, string Key)
        {
            XmlNode node = item.SelectSingleNode(Key);
            return node.InnerText;
        }

        public string GetDeviceListX()
        {
            DataTable dt = GetDeviceIPAddresses();

            StringWriter sw = new StringWriter();
            XmlTextWriter writer = new XmlTextWriter(sw);
            writer.Formatting = Formatting.Indented;           

            //Write the root element
            writer.WriteRaw("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>");

            //Start an element
            writer.WriteStartElement("DeviceList");

            foreach (DataRow dr in dt.Rows)
            {
                writer.WriteStartElement("Device");
                writer.WriteAttributeString("t", dr["Model"].ToString());
                writer.WriteAttributeString("n", dr["name"].ToString());
                writer.WriteAttributeString("d", dr["description"].ToString());
                writer.WriteAttributeString("c", "");
                writer.WriteAttributeString("p", "");
                writer.WriteAttributeString("i", dr["IPAddress"].ToString());
                writer.WriteAttributeString("s", (dr["IPAddress"].ToString().Length == 0) ? "" : "1");
                writer.WriteEndElement();

            }
            writer.WriteEndElement();
            writer.Flush();
            writer.Close();
            return sw.ToString();
        }      
    }
}

 

The source above loads XML fragments from to embedded resources:

GetDevices.xml

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:ExecuteCCMSQLStatement soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.cisco.com/ast/soap/">
      <ExecuteSQLInputData xsi:type="xsd:string">select name,description from Device where tkclass = 1 order by name;</ExecuteSQLInputData>
      <GetColumns soapenc:arrayType="ns1:ColumnType[2]" xsi:type="soapenc:Array" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
        <item xsi:type="ns1:ColumnType">
          <Name xsi:type="xsd:string">name</Name>
        </item>
        <item xsi:type="ns1:ColumnType">
          <Name xsi:type="xsd:string">description</Name>
        </item>
      </GetColumns>
    </ns1:ExecuteCCMSQLStatement>
  </soapenv:Body>
</soapenv:Envelope>

getDeviceIPAddress.xml
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:SelectCmDevice soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.cisco.com/ast/soap/">
      <StateInfo xsi:type="xsd:string"/>
      <CmSelectionCriteria xsi:type="ns1:CmSelectionCriteria">
        <MaxReturnedDevices xsi:type="xsd:unsignedInt">200</MaxReturnedDevices>
        <Class xsi:type="xsd:string">Phone</Class>
        <Model xsi:type="xsd:unsignedInt">255</Model>
        <Status xsi:type="xsd:string">Registered</Status>
        <NodeName xsi:type="xsd:string"/>
        <SelectBy xsi:type="xsd:string">Name</SelectBy>
        <SelectItems soapenc:arrayType="ns1:SelectItem[{0}]" xsi:type="soapenc:Array" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
          {1}
        </SelectItems>
      </CmSelectionCriteria>
    </ns1:SelectCmDevice>
  </soapenv:Body>
</soapenv:Envelope>

 

Sample Usage

AXLLibrary.AXLClass lib = new AXLLibrary.AXLClass("Username", "password", "10.3.24.22");
string XML = lib.GetDeviceListX();
MessageBox.Show(XML);
The output from the sample would look like this which is in the same XML format as the old devicelistx.asp script returned.
<?xml version="1.0" encoding="iso-8859-1"?>
<DeviceList>
  <Device t="115" n="SEP0018BA14AF7E" d="4330 - Sunnyvale Netlab" c="LONG-INTERNATIONAL-CSS" p="LONG-DP" i="" s="" />
  <Device t="115" n="SEP001E4AA8CC00" d="4305 - Scott Sharp" c="LONG-INTERNATIONAL-CSS" p="LONG-DP" i="10.1.206.160" s="1" />
  <Device t="35" n="SEP000E38502B1D" d="Auto 105139" c="SYSTEM-TAPS-CSS" p="SNVL-TAPS-DP" i="" s="" />
  <Device t="36" n="SEP000BFDB81799" d="Auto 105300" c="SYSTEM-TAPS-CSS" p="SNVL-TAPS-DP" i="" s="" />
</DeviceList>

 

One tip

Connect to the SOAP Monitor service on the call manager which exists at a URL like this and if you leave it overnight running you will see a number of requests which the system generates or if you create your own requests and you get back HTTP 500 errors this monitor may help as well.

https://servername:8443/realtimeservice/SOAPMonitor

image

I hope this source helps someone out there....


October 24, 2008 (Out-of-Band) Microsoft Security Response Center Security Bulletin Release

Microsoft has scheduled to release a security bulletin (out-of-band) to address a vulnerability in all currently supported versions of Windows.

This security update resolves a privately reported vulnerability in the Server service. The vulnerability could allow remote code execution if an affected system received a specially crafted RPC request. On Microsoft Windows 2000, Windows XP, and Windows Server 2003 systems, an attacker could exploit this vulnerability without authentication to run arbitrary code. It is possible that this vulnerability could be used in the crafting of a wormable exploit. Firewall best practices and standard default firewall configurations can help protect network resources from attacks that originate outside the enterprise perimeter.

This security update is rated Critical for all supported editions of Microsoft Windows 2000, Windows XP, Windows Server 2003, and rated Important for all supported editions of Windows Vista and Windows Server 2008.

The security update addresses the vulnerability by correcting the way that the Server service handles RPC requests. For more information about the vulnerability, see the Frequently Asked Questions (FAQ) subsection for the specific vulnerability entry under the next section, Vulnerability Information.

Recommendation. Microsoft recommends that customers apply the update immediately.

This security update will be released outside of the usual monthly security bulletin release cycle in an effort to protect customers. Microsoft recommends customers prepare their systems and networks to apply this security bulletin immediately once released to help ensure that their computers are protected from attempted criminal attacks. The purpose of this notification is to assist customers with resource planning for this security bulletin release.

For more information about security updates, visit http://support.microsoft.com/default.aspx?scid=kb;EN-US;KB958644


IIS MVP 2008 - 2009

I have been rewarded the MVP status for the 12 consecutive year - 1997 through to 2008/2009

1997 1998 1999 2000
2001 2002 2003 2004
mvp2007small mvp2008small
2005 2006 2007 2008

 

 MVP2008
Many thanks....