Wednesday, September 18, 2019

Cisco CP-8800-A-KEM

Running sip88xx.12-5-1SR3-74 on 8851 phones and installing 28 button CP-8800-A-KEM.

NOTES:

  • You must enable One Column Display on the device it's connected to or the CP-8800-A-KEM will light but will not register.
  • If the Line Mode is set to the default Session Line Mode the KEM button configuration actually begins on button 6, even though the device Add on Module(s) numbering starts at 11.
  • If the device Line Mode is set to Enhanced Line Mode, the KEM button configuration begins on button 11 as indicated in the Add on Module field.
  • Custom wallpaper normally deployed on the phones gets mangled on the KEM.

Sunday, September 01, 2019

Cisco Unity Connection add delete contacts via CUPI example

This is a sample of how to add and / or delete contacts in the Unity Connection database using the CUPI interface.
This was created using Python 3.6.2 and Cisco Unity Connection 12.5.

This script was created after finding Extension was a required field in the Unity Connection BAT process and needs to be unique, creating challenges in environments where single DNs may need multiple names associated with them.

Ultimately I found the Extension field in the BAT file can simply be left blank.

With that, I would suggest using the built in Unity Connection BAT process to manage contacts when possible.  
Unity Connection provides the ability to add contacts manually and via the Bulk Administration tool GUI but there are some limitations.
When adding Unity Connection contacts manually, only the Alias (unique) and the DisplayName is required. When adding Unity Connection contacts via Bulk Administration, an Alias (unique) and Extension (unique) is required. A problem arises when you only want to leverage Unity Connection contacts as additional directory entries, and where you might have multiple names or spellings for the same transfer destination.
Manually, you can add as many contacts as you require with variations of DisplayNames, all using the same TransferNumber, as the TransferNumber does not need to be unique. If you are managing thousands of DisplayName variations though (full names vs. acronyms vs. friendly names, etc.), manual entry is likely not acceptable.
Since BAT requires a unique Extension, if you enter it accurately you are required to still enter a TransferNumber, but now need to leverage multiple AlternateNames per contact to deal with name variations. This is undesireable as contact AlternateNames are not easily searchable via the GUI, and additionally User and Contact names can't be managed seperately if the extensions are the same.
For example, you may want need to manage directory entries for the President of the United Sates. Several years ago, the user BObama may have had extension 1111. This year, user DTrump may have the extension 1111. You might have historically had a directory entry (contact) with DisplayName POTUS with extension 1111. You might want a second directory entry (contact) with DisplayName P O T U S with extension 1111. You cannot add either contact with BAT, as a user already has that extension number. You can use AlternateNames in the User but when you delete and add a new user every four years, you need to remember to re-add all the asociated alternate names, which aren't searchable. If you choose to manage those more permanant AlternateNames in a contact and via BAT, you now need to create a bogus unique Extension for the contact and again manage unsearchable AlternateNames. If you want to be able to search for the AlternateNames, you need to BAT multiple contacts with multiple bogus Extesnsions and use the DisplayName in each instead.
None of this is perfect.
The CUC CUPI interface allows for bulk contact additions and deletions where Extension is not required.
This sample assumes your BAT file columns will be Alias, DisplayName, FirstName, LastName, TransferEnabled, TransferExtension and saved in UTF-8 format without BOM.

You can find my Github repository here: https://github.com/raymaslanka/Cisco-UCXN-CUPI-add-delete-contacts, or gist here:

import getpass
import csv
import requests
from requests import Session
from requests.auth import HTTPBasicAuth
import xml.etree.ElementTree as ET
import sys
def get_CUC_version(CUC, session):
# Using CUC version query to simply test user authentication. We don't really need the version info for anything.
request_data = session.get('https://' + CUC +'/vmrest/version/', timeout=2, stream=True)
return(request_data.status_code)
def insert_contact(CUC, template, row, session, rowNum):
if rowNum == 0:
# Basic check to see if CSV columns are likely accurate
if (row[0],row[1],row[2],row[3],row[4],row[5]) != ('Alias', 'DisplayName', 'FirstName', 'LastName', 'TransferEnabled', 'TransferExtension'):
print('There may be a problem with your column order:')
print('Correct names and order: [\'Alias\', \'DisplayName\', \'FirstName\', \'LastName\', \'TransferEnabled\', \'TransferExtension\']')
print('Your names and order: ', row)
sys.exit(0)
else:
print ('CSV required columns look accurate.')
print ('')
else:
print('Inserting CSV file row number:',rowNum + 1)
xml = make_XML(row)
headers = {'Content-Type':'application/xml'}
try:
request_data = session.post('https://' + CUC +'/vmrest/contacts?templateAlias=' + template + '', headers=headers, data=xml, timeout=2)
print ('Insert response:',request_data)
print ('')
except requests.exceptions.RequestException as e:
print('Something bad happened inserting:')
print(e)
return
def delete_contact(CUC, template, alias, session,rowNum):
headers = {'Content-Type':'application/xml'}
try:
print('Getting CUC ObjectId using CSV Alias ' + alias + ' in row number:',rowNum + 1)
request_data = session.get('https://' + CUC +'/vmrest/contacts?query=(alias%20is%20' + alias + ')', headers=headers, timeout=2, stream=True)
tree = ET.fromstring(request_data.text)
count = tree.findall('Contact')
if len(count) > 0:
print ('Found ' + str(len(count)) + ' contact with that alias.')
for contact in tree.findall('Contact'):
aliastext = contact.find('Alias').text
objectidtext = contact.find('ObjectId').text
print('Deleting CUC contact ' + aliastext + ' with ObjectId ' + objectidtext)
objectid = contact.find('ObjectId').text
request_data = session.delete('https://' + CUC +'/vmrest/contacts/' + objectid + '', headers=headers, timeout=2, stream=True)
print ('Delete response:',request_data)
print ('')
else:
print ('Found ' + str(len(count)) + ' contacts with that alias. Skipping...')
print('')
except requests.exceptions.RequestException as e:
print('Something bad happened deleting')
print(e)
return
def make_XML(row):
print('Creating XML from:',row)
xml = '<Contact>'
xml = xml + '<Alias>' + row[0] + '</Alias>'
xml = xml + '<DisplayName>' + row[1] + '</DisplayName>'
xml = xml + '<FirstName>' + row[2] + '</FirstName>'
xml = xml + '<LastName>' + row[3] + '</LastName>'
xml = xml + '<TransferEnabled>' + row[4] + '</TransferEnabled>'
xml = xml + '<TransferExtension>' + row[5] + '</TransferExtension>'
xml = xml + '</Contact>'
return(xml)
def main():
csvFile = 'YOUR BAT FILENAME HERE'
CUC = 'YOUR UNITY CONNECTION SERVER FQDN / IP ADDRESS HERE'
template = 'YOUR CONTACT BAT TEMPLATE ALIAS HERE'
username = input('UCxN username: ')
password = getpass.getpass('UCxN password:')
adddelete = input('[A]dd / [D]elete: ')
print ('')
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(username, password)
if get_CUC_version(CUC,session) != 200:
print ('Authentication Failed.')
sys.exit(0)
if adddelete == 'A':
csvData = csv.reader(open(csvFile))
rowNum = 0
for row in csvData:
insert_contact(CUC, template, row, session, rowNum)
rowNum +=1
elif adddelete == 'D':
csvData = csv.reader(open(csvFile))
rowNum = 0
for row in csvData:
if rowNum == 0:
print('Skipping column header row 1.')
print('')
else:
delete_contact(CUC, template, row[0], session, rowNum)
rowNum +=1
else:
print('Invalid Entry')
print('')
sys.exit(0)
if __name__ == '__main__':
main()