Powershell to fix phone number formats (part 1)

Peter sent me a mail last week suggesting a blog post.

"You mentioned in https://blogs.technet.com/jamesone/archive/2007/02/21/the-campaign-for-real-numbers.aspx that a transport rule would be cool. Whislt I'm not yet a E2K7 user, wouldn't it be good if you could knock up a powershell script to create the rule and publish it on your blog?

you get treble value - powershell, exchange, and crappy phone number layout"

I thought I'd try to do three things.

  1. Fix entries which have built up in my Outlook contacts over time which aren't in E.164 format so everything I have can be dialed.
  2. Apply the same fixes to Active directory user and contact objects
  3. [The bit Peter suggest, and I don't know how to do yet] Create an Exchange 2007 transport rule which fires the does the same thing as my Outlook rule to advise people of broken numbers I might need to pull in some help from Eileen , Brett or Ewan for that one.

This post just deals with the fist of these.

I wanted two powershell functions. The first takes a String which holds the phone number and re-formats it.

 function Format-Number-as-E164 ([string]$Number)
{if ($number.length -gt 5) 
 {if ($number.substring(0,2) -ne '08')
   {if ($number.substring(0,2) -eq '00') {$number='+' + $number.substring(2) }
    if ($number.substring(0,1) -eq '0')  {$number='+44 '+ $number.substring(1) }
    $number = $number.replace("+440", "+44")
    $number = $number.replace("+44 0", "+44")
    $number = $number.replace("+44(0)", "+44")
    $number = $number.replace("+44 (0)", "+44")
    $number = $number.replace("+44(0", "+44(")    
    $number = $number.replace("+44 (0", "+44 (")}
 }
$number
} 

The logic is pretty simple:

  • ignore anything to short to be a phone number and special codes like 0800, 0870, 0845 which (mostly) can't be dialed from outside the UK.
  • Fix anything where I have entered the local code for international. 001 (234) 555-1234  becomes +1 (234) 555-1234 and UK formatted numbers O118 909 3080 becomes +44 118 909 3080.
  • Finally get rid of 0 in +44 0118, +44 (0) 118 and +44 (0118)  

The second function takes an outlook contact object and calls the first for each of the 13 different phone numbers - here I'm just showing one.

 function Format-contact-as-e164 ($contact) 
{   if($contact.CompanyMainTelephoneNumber) 
    {$temp = Format-Number-as-E164($contact.CompanyMainTelephoneNumber)
      if ($temp -ne $contact.CompanyMainTelephoneNumber) 
        {$contact.CompanyMainTelephoneNumber=$temp
        $changed=$TRUE}
    }
    if ($changed) 
    {write-host $contact.fileAs changed
    $contact.save() }
} 

So now I need to feed my outlook contacts into this function converting code I've been using for years gives me this - Get Default folder can get your inbox, calendar, contacts and so on. 10 is the code for the contacts folder.

 $Outlook= New-Object -comobject "outlook.application"
$namespace=$outlook.GetNamespace("MAPI")
$myContacts=$namespace.GetDefaultFolder(10).name

Of course this can be squeezed into one line.

 $myContacts=(new-object -comobject "Outlook.Application").getnamespace("mapi").getDefaultFolder(10)

I haven't tried it by I guess you could dispense with the variable altogether and  update my address book with

 foreach ($item in(new-object -comobject "Outlook.Application").getnamespace("mapi").getDefaultFolder(10).items) {Format-contact-as-e164($item) }

Since I didn't trust my code to work first time (nor should you) I did two things to check it worked properly. The first was to do a global replace of {$contact. with {write-host  so I could see what it was doing  - Powershell syntax is that write-host CompanyMainTelephoneNumber=$temp  will treat CompanyMainTelephoneNumber= as a literal string and expand the variable $temp. There are cases where this is infuriating (at least for new converts) but here it's exactly what I want.

When I was satisfied that it was  working correctly, I changed the code back and tested a contact which I knew I could fix so I just invoked Format-contact-as-e164( $myContacts.Items.item(1)) when that worked, it was time to go for it and update all the affected contacts with

foreach ($item in $myContacts.Items) {Format-contact-as-e164($item) }

It worked. (Phew). I've attached the .ps1 file with the code in it. As with all code posted to this blog it is provided as an example. It doesn't necessarily represent "best practice" and comes with no warranty or support (so if you want to use it against real data of your own, take suitable precautions).

Technorati tags: Microsoft, Powershell, Exchange, Outlook, e.164, telephony