As a VoIP admin I often have site managers asking me for the names of agents in each of their hunt groups--some of which involve dozens of groups and hundreds of agent phones. Since CUCM doesn't provide any direct way to get names from the hunt group (just DNs) these requests could take a couple of hours. So I worked out this Python script that uses the Selenium module to export a spreadsheet of all hunt groups matching a given search term, with their respective members' names (based on DN "Description" field, as well as a directory of all the retrieved names' DNs. This script requires you to install Firefox, and also the Firefox web driver from: https://github.com/mozilla/geckodriver/releases
The web driver must be added to your system PATH per: https://stackoverflow.com/q/40208051/1893164
It's not the prettiest and I'm a pretty novice coder but it works and has turned an hour+ job into one that just takes a couple of minutes. See comments on the right side for some substitutions you might need to make in the code based on your company's practices. For instance in my company DNs are all 8 digits long, and the first 4 digits are always a common prefix specific to a given location. E.g. one site may have directory numbers 30010000 - 30019999, another site may have 30020000 - 30029999, etc. I have noted below where you would make adjustments based on your standards. The Excel doc saves to whatever folder you have your Python projects in.
Feel free to ask questions or criticize! (edited for readability)
_______________________________________________________________________________________
# HUNT GROUP TOOL 3.0
from selenium import webdriver
import openpyxl
browser = webdriver.Firefox()
browser.get('https://<IP of your CUCM>/ccmadmin') #open cucm
print("In the browser, sign into CUCM using your credentials.")
site = input("Enter site abbreviation: ").upper() # -> or, whatever search term works for your org.
print("Gathering " + site + " Hunt Groups...")
browser.get('https://<IP of your CUCM>/ccmadmin/lineGroupFindList.do') # go to line group page
lgelem = browser.find_element_by_id('searchString0') # locate search field
lgelem.send_keys(site) # enter site abbreviation to search
findbutton = browser.find_element_by_class_name('cuesButton') # find "Find" button and
findbutton.click() # click it
fullhuntdict = {} # dict of hunt groups. keys are LG names
# values are the lists of extensions
finalDict = {} # FINAL RESULT
huntgroupnames = browser.find_elements_by_partial_link_text(site) # list of returned LG names
prefixes = [] # list of DN prefixes
# for searching DNs
finalDNlist = []
namedirectory = []
def getDNs(extprefix): # get list of all DNs
browser.get('https://<IP of your CUCM>/ccmadmin/directoryNumberFindList.do') # go to DN page
dnbuttonclear = browser.find_element_by_name('clearFilterButton') #clear previous search
dnbuttonclear.click()
dnelem = browser.find_element_by_id('searchString0') # locate search field
dnelem.send_keys(extprefix) # enter DN prefix to search
dnbuttonfind = browser.find_element_by_class_name('cuesButton') # find "Find" button and
dnbuttonfind.click() # click it
# below line updates the URL to allow for 500 results per page (change the 500 in URL if more needed):
browser.get(
'https://<IP of your CUCM>/ccmadmin/directoryNumberFindList.do?lookup=false&multiple=true&rowsPerPage=500&pageNumber=1'
)
DNList = browser.find_elements_by_class_name('cuesTableRowEven') # list of even row elements
DNList2 = browser.find_elements_by_class_name('cuesTableRowOdd') # list of odd row elements
DNList += DNList2
fullDNlist = [] # all td elements from rows
siteDNlist = [] # final list just extensions & names
for i in range(len(DNList)): # this loop gets the text of each row
agent = DNList[i].find_elements_by_tag_name('td')
for j in range(len(agent)):
fullDNlist.append(agent[j].text)
for i in fullDNlist: # strips it to just extensions & names
if i not in ['<partition name(s)>', '']: # <-phrase here should be partition name(s) on DN page
siteDNlist.append(i)
return(siteDNlist)
'''For loop to go through links in huntgroupnames'''
for i in range(len(huntgroupnames)):
huntgrouprefreshed = browser.find_elements_by_partial_link_text(site) # re-list LG names each iteration to
# avoid 'stale' error
choosegroup = huntgrouprefreshed[i]
choosegroup.click() # click into selected group
'''now we're in the hunt group for this iteration'''
LGKey = browser.find_element_by_id('NAME') # find LG name field and
LGKey = LGKey.get_attribute("value") # store name for dict keys
huntmemberz = [] # clear agent list for each iteration
extensionlist = browser.find_elements_by_partial_link_text('<phrase>') # list of all DNs in LG
# <phrase> = search term matching DN partition
'''loop through all the values in extensionlist'''
for j in range(len(extensionlist)):
ext = extensionlist[j].text # retrieve link text for this iteration
ext = ext[:8] # your common DN length instead of 8
prefix = ext[:4] # your common DN prefix length instead of 4
huntmemberz.append(ext) # add ext to list
if prefix not in prefixes:
prefixes.append(prefix) # keep running collection of prefixes
fullhuntdict.update({LGKey: huntmemberz}) # add LG name and member list to dict
browser.back()
print("Gathering agent names. This may take a minute or two for larger sites.")
print("Do not click the back button or close your browser.")
for i in prefixes: # loop through collected prefixes
finalDNlist += getDNs(i) # add each group of DNs to final list
for lg in fullhuntdict.keys(): # loop through the stored hunt groups
finalhuntmembers = [] # reset this list before each group
for dn in range(len(fullhuntdict[lg])): # loop through DNs in current group
if fullhuntdict[lg][dn] in finalDNlist: # check if current DN in the DN list
addagent = finalDNlist.index(fullhuntdict[lg][dn]) # get index of current DN in DN list
addagent = finalDNlist[addagent + 1] # find next value in list (agent name)
if addagent not in finalhuntmembers: # check for redundancy and add agent
finalhuntmembers.append(addagent)
if addagent not in namedirectory: # add to cumulative directory
namedirectory.append(addagent)
finalDict.update({lg: finalhuntmembers})
for key in finalDict.keys():
print('')
print('')
print(key)
print('')
for member in finalDict[key]:
print(member)
phonebook = {}
for i in range(len(finalDNlist)): # go through all of DN list
if finalDNlist[i][0] not in '0123456789': # if it's a name
if finalDNlist[i] not in phonebook.keys(): # check if already in phonebook
phonebook.update({finalDNlist[i]: [finalDNlist[i - 1]]}) # if not create dict item (name: list)
else:
phonebook[finalDNlist[i]].append(finalDNlist[i - 1]) # otherwise add extension to existing
# name entry
print('')
print('')
print('DIRECTORY OF EXTENSIONS')
print('')
namedirectory.sort()
for i in range(len(namedirectory)):
name = namedirectory[i]
phonebook[name].sort()
entrylength = len(phonebook[name])
print(name, ' ' * (24 - len(name)), phonebook[name][entrylength - 1]) # sets up left-justified DNs
#-----------------------------------------------------------------------------
# EXPORT TO EXCEL
#-----------------------------------------------------------------------------
myWB = openpyxl.Workbook() # create workbook
sheet = myWB.active
sheet.title = 'Groups' # name active sheet
myWB.create_sheet(title='DN Directory') # create second sheet
colnum = 1
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
columnlist = [] # list of columns needed for all groups
for i in letters:
columnlist.append(i) # add columns A - Z...
for i in letters:
columnlist.append('A' + i) # ...and AA - AZ to list
for key in finalDict.keys(): # loop through the hunt groups
rownum = 3 # start each list of names at row 3
sheet.cell(column=colnum, row=1).value = key # LG name in top row current column
for member in finalDict[key]: # loop through names in current LG
sheet.cell(column=colnum, row=rownum).value = member # add next name in list
rownum += 1 # go to next row
colnum += 1 # go to next column
for i in range(len(finalDict.keys())):
sheet.column_dimensions[columnlist[i]].width = 25 # widen enough columns for all LGs
sheet = myWB['DN Directory'] # switch to second sheet
dnrows = 1
for i in range(len(namedirectory)): # loop through names in directory
name = namedirectory[i]
phonebook[name].sort() # put current agent's DNs in order
entrylength = len(phonebook[name]) # no. of DNs for this agent
sheet.cell(column=1, row=dnrows).value = name # name in col. 1
sheet.cell(column=2, row=dnrows).value = phonebook[name][entrylength - 1] # last (highest) DN for agent in col. 2
dnrows += 1
sheet.column_dimensions['A'].width = 25
sheet.column_dimensions['B'].width = 20
saveit = input('Export to Excel? ')
if saveit.lower() in ['yes', 'y', 'ye']:
filename = input('Enter file name: ')
myWB.save(filename + '.xlsx') #saves in local folder
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: