I said when I posted about fixing the phone numbers in your Outlook Contacts that I'd come back and do the same thing for Active Directory. Richard told people to look out for that, so no pressure to get it done then...

Using the Active Directory Services interface (ADSI) from Powershell seems to fill some people with fear. One of the books I picked up said "don't bother" use VB. I found the Mastering PowerShell in your lunch-break pages quite helpful on ADSI; and there are a bunch of tools worth investigating. I wanted to do this without creating a dependency on those, if I could.

So here are a few bits that might be useful before I dive into the code.

  1. [ADSI]LDAP://{path} will fetch an ADSI object. the LDAP part is case sensitive. You can specify LDAP://serverName:port/name to go to a specific server - if you leave the port out :389 is assumed, and you can specify the search should go against a Global Catalog server with GC://. Leaving the path empty - calling [ADSI]"", you'll return the default naming context for the current domain.
  2. The LDAP bit is required, but when AD gives you a path it usually omits the LDAP:// , causing an error when you try to get the object. The exception to this is the "Searcher" object
  3. ADSI objects aren't saved back to the server until you call their setInfo method
  4. ADSI objects have properties and children. To get the Children use $ADSIobject.psbase.children. Properties can be addressed as $ADSIobject.property.name. However this will return something if the AD property wasn't set. A better way to check properties is with $ADSIObject.psbase.propertyName
  5. The DirectoryServices.DirectorySearcher object is a very useful way to get a collection of objects

I've kept the same structure as I used in the Outlook Contacts version. I've kept the same function Format-number-as-E164 and I have another function which takes a user or contact object, checks to see if phone numbers are present and if they are, it calls Format-number-as-E164.  This follows the same pattern as the outlook one, but is named function Format-ADPerson-as-e164 and takes an LDAP path as a parameter. The AD fields it looks at are facsimileTelephoneNumber, homePhone, ipPhone, mobile, pager, PrimaryInternationalISDNNumber , TelephoneAssistant  and TelephoneNumber

Rather than show identical code for all these attributes, I've just shown one below.

function Format-ADPerson-as-e164 ($LDAPpath) 

{
    $changed=$false
    $Contact=[ADSI]($LDAPPath)
    if($contact.psbase.properties.facsimileTelephoneNumber)
    {$temp = Format-Number-as-E164($contact.facsimileTelephoneNumber)
      if ($temp -ne $contact.facsimileTelephoneNumber)
        {$contact.facsimileTelephoneNumber=$temp
        $changed=$TRUE}
    }   

     if ($changed) {
    write-host $contact.name changed
    $contact.setInfo()
    }
}

I  tested the code with the path to a single user e.g. Format-ADPerson-as-e164 ('LDAP://CN=James O'Neill,CN=Users,DC=Contoso,DC=com')

Then it needs to be called for many AD users, By using [ADSI]"", and filtering to the "Person" objectClass, I selected every user and contact in my domain but you could specify a single OU or a more restrictive filter.

    $searcher= New-Object directoryServices.DirectorySearcher([Adsi]"") 

$searcher.filter="(objectclass=person)"

$searcher.findall() | forEach-Object {$_.path}

The last line is there to show which objects are going to be processed. When I'm happy that I've go the right objects and the right code

    $searcher.findall() | foreach-object {Format-ADPerson-as-e164($_.path)}

Does the processing.

The code is attached for you to play with, but as I've said before, and will say in the future; any code I provide here is for example purposes. No Warranty or support is provided. You should take steps to validate any such code or yourself before running it.

 

Technorati tags: , , , ,