Find Un-Migrated Phone Numbers in Cisco Call Manager to Port to Skype for Business / Teams

Find Un-Migrated Phone Numbers in Cisco Call Manager to Port to Skype for Business / Teams

Currently I am doing a Skype for Business migration for a large enterprise. The current phone system is Cisco Call Manager and I am migrating everything to Skype for Business / Microsoft Teams in Office 365. I am at a point where I have migrated a majority of my local users but I want to make sure I grab all available phone numbers I can. These phone numbers could be left from old users, systems, etc.

ImportExcel PowerShell Module

To make this work easier, I am going to be using the ImportExcel PowerShell module. I could use Export-CSV but then I will end up with several CSV data files to work with, and it can get confusing quick. Installing the module is easy as it is available on the PSGallery.

Gathering the Phone Data

Export Phone Numbers in Skype for Business Portal

By logging into Skype for Business Online via PowerShell I can grab all migrated / available numbers in a single line:

By using the -WorkSheetName parameter I can specify the data to be dumped to a specific worksheet in a workbook. I will be using this workbook throughout the process which I have named “Master.xlsx” located at C:\Export.

Export Phone Numbers from CUCM

Export Local Users with Phones

My local users have phones with assigned numbers. In CUCM I can export my existing phones / numbers by going to:

  1. Bulk Administration
  2. Phones
  3. Export Phone
  4. All Details

Once the job has ran (which you can monitor in Job Scheduler) I can download the files in Bulk Administration > Upload/Download files. The file is a .txt file but I can save it as a .csv file by using Windows Notepad.

I save this list as exportphones.csv. I then went into it and copied its data and pasted it into my Master.xslx workbook under a new worksheet named, “LocalUsers”.

Export Remote Users with Phones

My remote users do not have phones, so they will not be in the above list. Instead they are set up as CTI Route Points which designates a virtual device that can receive multiple, simultaneous calls for application-controlled redirection. By using a CTI Route Point I can set up forwarding from their work number to their cell phone.

I can export a list of my CTI Route Points in CUCM by going to:

  1. Bulk Administration
  2. Import/Export
  3. Export

I first want to give my exported file a valid name

The ONLY thing I want to run is CTI Route Point, so I check that and then select the “Run Immediately” radio button and then click Submit.

You may get a warning because some dependencies are missing, we can ignore this because we will not use this export as a configuration import at any time.

You can monitor the status of your job in the Job Scheduler. Once it is complete you can download the results by going to Bulk Administration > Upload/Download Files

Once you locate your file, select it and the press “Download Selected”

This file is a TAR file which will open in Notepad and then I just save it as a CSV file.

I then copied the CSV file data and created the worksheet, “RemoteUsers” in my master workbook.

WorkBook Formatting

Once you have your LocalUsers and RemoteUsers worksheets completed, I would format the “Forward All Destination 1” row to Number with 0 decimal places. This should have your external forwarding value and if you include the typical “9” and “1” before the area code it will not format properly.

Data Parsing and Manipulation

The next few sections will walk you through each step of the process, from how I figure out what the Direct Inward Dialing number is, checking if the number has been migrated or not, to figuring out if my user is local or remote. If you are familiar enough with PowerShell and can understand the final script, please feel free to jump down to the bottom where I post the source script. However, I highly recommend reading through the guide.

String Manipulation and Concatenation

So now my goal now is to parse the LocalUsers and RemoteUsers worksheets, combine the external mask (which will be a value like 618203XXXX) value and the extension  (which will be a value like 6438) to get the full Direct Inward Dialing (DID) number (618-203-6438). This number will be the number that I will need to port if not ported already.

By using the -split method and splitting the string at the first “X”, selecting the first object, and then concatenating of both strings (external phone mask without the trailing XXXX and the extension), I can create the entire DID number that I need to migrate and store it in a variable.

I can also figure out if my already migrated users are set up properly by querying the “Forward All Destination 1” value and making sure it is not NULL. Once users are migrated from Cisco Call Manager to Skype for Business / Teams, forwarding should be set up so Cisco Call Manager knows to route the calls from users not migrated yet back out and to Office 365.

False Positive Prevention

In my Cisco dumps I noticed that I have quite a few entries with no EXTERNAL PHONE NUMBER MASK 1 value. This value has the first half of our DID that we need to migrate, if this value is not present then there is no DID to migrate. To prevent getting a bunch of garbage data, I will only parse data that has an EXTERNAL PHONE NUMBER MASK 1 value.

Splitting the Results

My two data ‘buckets’ that I will be iterating through are my local users and my remote users worksheets, but I want to split my results into two more items of “Migrated” and “Not Migrated” users / DID’s. To do this I will check the $Phone variable (where I created the full DID by adding the External Mask and the Extension) and doing a lookup against the Skype Numbers worksheet.


As I parse through the data I will be storing the results in a generic list which will then become my new excel worksheets at the end. I create properties and then supply the value based on the original data. Below we can see the ExternalForwarding property will have a value found in the ‘Forward All Destination 1’ header.

At the end, we will export our entire list object into a new worksheet. The one above will contain the items for my local users who have already been migrated to Office 365.


Below is the entire script put together. In the end I will have 4 more worksheets, LocalUsers_AlreadyMigrated, LocalUsers_NotMigrated, RemoteUsers_AlreadyMigrated, and RemoteUsers_NotMigrated.

LastLogonTimeStamp Lookup

Luckily for me, the DESCRIPTION field in the Cisco Call Manager was set as the users first name and last name. So I would like to leverage the ActiveDirectory module to do a lookup on the user, query the last logon timestamp, do DateMath to figure out how many days ago that was, and then add that to the worksheet.

DisplayName Formatting

The DisplayName in my organization is following a Lastname, FirstName format. Since the Description field in Cisco Call Manager was set up as FirstName LastName I will need to do some string manipulation to change the format.

LastLogonTimeStamp Script

And now we will have a LastLogon column

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: