Sunday, March 30, 2008

Cisco Attendant Console - Transferring Calls

In many of our offices (and probably soon to be all of them) we use Cisco Call Manager for our call processing. In each of our offices a receptionist is used to field the incoming calls. Included with Cisco's telephone system is a Java-based application named the Attendant Console (AC). This application allows the receptionist (in our case) to see the incoming call information, answer the call, put the call on hold, transfer the call to a number (either internal or external), as well as some other cool things.

Often, especially with executive-level management, the receptionist needs different options for transferring calls depending on the situation. The AC offers a few different ways to accomplish this often overlooked, yet necessary and important task and that is what will be examined in this post.

Types of transfers available in the AC:
  1. Transfer - This type of transfer does not inform the receiver of the call prior to transferring the call. When the call is transferred from the receptionist, it just rings the number (internal or external) that it is transferred to. To do this, left-click on the call and drag it over to the entry in the directory or speed dial
  2. Consult Transfer - A consult transfer allows the receptionist to consult the receiver of the call prior to transferring. For a consult transfer, click the call, then right-click the speed dial or directory entry and choose Consult Transfer. Once the receiver agrees to accept the call, click on the call in the hold window and click transfer. If the receiver doesn't want to take the call, the call can be picked up as with any other hold call and a sent to VM or whatever.
  3. Direct Transfer - Although not often used, this is a very cool feature of the Cisco system. A direct transfer will merge two calls into the same call. Simply select both calls in the call window (using the Ctrl key), right-click one of the selected calls and choose direct transfer. When the receiver picks up the phone, both calls will be on their line.
As demonstrated here, although transferring a call seems like a simple and easy task, there are additional possibilities and requirements for transferring calls. Often, those of us in the IT field don't take this into consideration because we are not receptionists and don't think in this way. However, it is important to know the features of the systems that we support and how to instruct our users to use these features when they need them.

Thursday, March 27, 2008

Exchange 2007 Address Management

While I was upgrading our Recipient Address Policies from Exchange 2003 to Exchange 2007, I inadvertently applied each of the policies to all of our user accounts (and contacts!). I searched and searched for a cmdlet that would allow me to easily remove a proxy address, aka: alias. To accomplish this I had to put together many different elements, but in the end it turned out to be an elegant, yet simple solution. In all fairness, our recipient policies were pretty messed up and needed to be overhauled anyway. We recently removed some of the domains protected by our spam filter company (http://www.securence.com). This means that anyone with those addresses would be vulnerable to all spam. So, removing these policies was on my to-do list anyway.

First, I pulled in the EmailAddresses property using the get-mailbox cmdlet. This allowed me to specify which mailboxes I wanted based on which ones had the proxy address listed.

get-mailbox -resultsize unlimited | where-object {$_.EmailAddresses -like "*domain2.com"}


Next, I put all of those addresses into an array named $mailboxes.

$mailboxes = @(get-mailbox -resultsize unlimited | where-object {$_.EmailAddresses -like "*domain2.com"})


Now that my array is populated with all of the mailboxes that have an alias with domain2.com, I can loop through and remove the proxy address. This is a variation of a really neat command that I found on the Exchangepedia Blog. The "-" removes the property from the object. So, the $mailbox variable stores the mailbox object, and then the $mailbox.emailAddresses line specifies that property that I want to change and then I append the alias (first.last in our case) to the "@domain2.com" to tell it which address to remove.

foreach ($mailbox in $mailboxes){$mailbox.emailAddresses -= $mailbox.alias + "@domain2.com"}


Finally, I loop back through the array to commit the changes using the set-mailbox command.

foreach ($mailbox in $mailboxes) {$mailbox | set-mailbox}


That's it. As usual, I am sure that there is a more efficient way to write this script, and if I wanted to spend an extra 30 minutes to an hour refining the script, I could, but really why? At this point I've already run the script. One day when my work load has lightened up a bit and I'm looking for a pet project, maybe I will revisit this. The entire script is below:

$mailboxes = @(get-mailbox -resultsize unlimited | where-object {$_.EmailAddresses -like "*domain2.com"})
foreach ($mailbox in $mailboxes){$mailbox.emailAddresses -= $mailbox.alias + "@domain2.com"}
foreach ($mailbox in $mailboxes) {$mailbox | set-mailbox}



Monday, March 24, 2008

PowerShell - Sorting Text

Over time I will be posting little uses I find for the Windows PowerShell. The PowerShell can be downloaded from Microsoft's website. I downloaded it the first time to try and solve some VBScript woes that I was having. Later, I found that I needed it to manage Exchange 2007 during my training at Global Knowledge (love this place!). Finally, I downloaded an awesome tutorial from Frank Koch. This tutorial is a must for anyone new to the PowerShell. I have been through the Microsoft documentation and user guides, and they are nice but, Frank has put it together in such a way that he steps through the concepts and relates them so that they are much more intuitive and easy to remember.

We have many servers (about 65) in our enterprise that I use Microsoft's Remote Desktops Console to access. As new servers are added and old ones are removed, the list quickly becomes difficult to navigate because the servers are soon in no order at all. The console doesn't allow for the moving up/down in the list or any other easy way to change them. It is possible to go through and rename each connection with what would be the next server in order, but this too is tedious and difficult. Finally, some sort of XML configuration file - but no, I couldn't find that either. I have found it much easier to just add the connections back in.

The PowerShell comes into play here. In the MMC it is possible to export the list of servers to a text file. Once exported, I use the Get-Content cmdlet to read the text file in. I then pipe the results into the sort-object cmdlet and it spits out a beautifully sorted list by connection name. Here is the command that I use to accomplish this:

get-content 'Remote Desktops.txt' | sort-object


Now I can just go down the list adding the connections back to the console and I have a nicely sorted list of servers.

Unity Express Backup

In many of our locations, we use a Cisco Unity Express (CUE) router for voice mail processing. This device is a nice piece, both for features and price. The caveat of this is the backup process. Although, I have heard that there is a way to automate the backup of the system, I have not been able to figure this out for myself. So, I must continue to log into the device each month, take it offline, and back it up to an FTP server.

I set the FTP server with a folder for each of the CUE devices. The server uses a standard account that I have designated specifically for this purpose. To configure the device for the initial backup, go to Administration->Backup/Restore->Configuration. Enter the server URL to the FTP server, the User ID and password to be used. The Maximum Revisions field is the number of backups that should be kept on the FTP server.


Once the system is configured for the backup destination, user name, password, and maximum revisions, a backup can be run. When running the backup, the system knows how many backups it has run and automatically assigns a number to the backup. A description is optional, and the categories determine what information is to be backed up. We choose to backup both the configuration (system and application settings) and the data (application data and voice mail messages).


I have realized that although we pay for the 4 hour response of SmartNet with these systems, if you don't have the configuration and voice mail greetings backed up, you can still endure many, many hours of heartache when trying to restore the system to full functionality.

Fortunately, we have not yet had to restore from one of these backups, so I can't give any indication as to how well the restoration works and if all data is successfully restored back to its original glory. Hopefully, I will never need to find out!

Sunday, March 23, 2008

Import Contacts from CSV Into Exchange 2007

A vendor submitted a list of their employees whose contact information needed to be made available through the Exchange 2007 Global Address List (GAL). I found a very elegant solution for this from the MSExchange.org website. Although the solution is a great starting point, I needed to modify it. The way it is written makes this a very easy thing to do.

The Excel sheet sent to me this time (next time it will probably be different) had additional columns and attributes that were not included in the posted script. The original script assumes that their is not "display name" or full name. So it concatenates the first and last fields to create this to later be used at import. I find it easier to concatenate the strings (if needed) using Excel's concatenate() function. Speaking of the Excel sheet, there needs to be column headers in the sheet. These column headers will be used during the import process. The fields available bring up the point of how Exchange 2007 and Active Directory store and access the properties of a contact object. The mail-enabled contact must be created through Exchange. Then, the Active Directory-specific attributes can be changed.

All of these objects are created using the Windows Powershell (more info about the Powershell can be found here: http://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx) with the Exchange Snap-in. The following are the commands used:
  • Import-csv
  • ForEach-object
  • New-mailcontact
  • Set-contact
  • Set-mailcontact
The format of the new-mailcontact command points to a domain controller, and then the attributes/properties of the object are manipulated using a hyphen (-) followed by the name of the property, while the name of the column is designated with a variable.

new-mailcontact -domaincontroller dc.domain.com -Name $_."Name Column" -Firstname $_."First Name" -Lastname $_."Last Name"


The set-contact command works the same way, it just offers different attributes to manipulate.

set-contact -domaincontroller dc.domain.com -City $_."Business City" -Company $_."Company"


The entire script is below:

Add-Content c:\debug.txt "::Starting Import: ";

$err = "";

Import-Csv Import-CSV-Contacts.csv | ForEach-Object{

New-MailContact -DomainController dc.domain.com -Name $_."displayName" -Firstname $_."FirstName" -Lastname $_."LastName" -ExternalEmailAddress $_."E-mail Address" -OrganizationalUnit "harrynorman.com/Offices/Contacts/Dickenson Gilroy Law Firm" -ErrorAction SilentlyContinue -ErrorVariable +err | Set-Contact -DomainController dc.domain.com -City $_."Business City" -Company $_."Company" -Office $_."Office" -DisplayName $_."displayName" -Fax $_."Business Fax" -Name $_."displayName" -Phone $_."Business Phone" -PostalCode $_."Business Postal Code" -StateOrProvince $_."Business State" -StreetAddress $_."Business Street" -Title $_."Title" -ErrorAction SilentlyContinue -ErrorVariable +err;

Set-MailContact -Identity $_."displayName" -DomainController dc.domain.com -ErrorAction SilentlyContinue -ErrorVariable +err;
}
Add-Content c:\debug.txt $err;


Finally, I created a new custom address list in Exchange to aggregate these addresses. Much like the "query-based distribution groups" in Active Directory, a query of the company can be used to create the custom address list. As new contacts are added/removed the address list should be updated accordingly.

Side Note: A very nice feature in Exchange 2007 Outlook Web Access is the way the system automatically senses an address field for a contact. It provides a "Map this address..." link that then takes the user to Microsoft's map engine displaying the map for the user in a new window.