May 6, 2012

Quick Tip – Script to collate Exchange 2010 OAB Generation Logs…

The other day whilst trying to send an e-mail to a new starter in my organisation I discovered that their name did not appear to be on the Global Address List within my Outlook client (Outlook 2010). Now I knew that the user had been created correctly (and had been several days ago), was also not hidden from the GAL, and others folks were quite happily sending her e-mails – so I suspected that as I was using Outlook Cached mode (which normally I don’t) there was a problem with the Offline Address Book.

This problem could of course be local, or on the Exchange Server  – but first I needed to confirm that this was indeed a OAB problem.

I did this by temporarily turning off cached mode and then checking the address book from within Outlook by using direct mode – and I found that the user was present, I further backed up my theory about the oddness with the OAB by checking to see if the user was present from within the OWA address list – she was as well.

To eliminate a local issue  – my first action was to exit Outlook and delete all of the local Offline Address Book cache files on my local machine ~ if you are using Windows 7 with Outlook 2010 these are located in: [ %UserProfile%\AppData\Local\Microsoft\Outlook\Offline Address Books\ ] and are listed as:















Source: Microsoft

Once I had deleted the files, I restarted Outlook and then from the “Send / Receive” ribbon select [ Send / Receive Groups –> Download Address Book ] – see below


I then un-ticked the “Download changes since last Send / Receive” (this will ensure that a full download is instigated) and then clicked on the “OK” button – see below


This did not work, as the user that I was trying to find did not appear in my local address list.

This also indicated that the problem was not with the local copy of the Offline Address List – but was an issue with the generated OAB on the Exchange Servers within my organisation. So I opened up an Exchange Management Console Session and ran the following cmdlet:

Update-OfflineAddressBook –Identity “Address Book Name”

Executing the above does pretty much what you would expect it to – e.g. it starts a refresh of the Offline Address Book which is outside its normal schedule on the designated OAB Generation Server. Generally this can take a little while to complete (depending on the size of the organisation and the number of recipients)

If you would like to get the details of your Offline Address Books and the Generation Servers you can use the following command:

Get-OfflineAddressBook | Select Name,Server

Which will produce output that looks like the following:


Anyhow – I gave it about 30 minutes and tried the OAB download again within Outlook, and unfortunately – no luck, my elusive user was still missing.

When this happens the root cause is * generally * something screwy within the bowels of Active Directory that will need intervention using something like ADSI edit.

Of course the question was what? – What is wrong in AD?

Now the only way that I was going to deduce this was to increase the logging levels on the [ MSExchangeSA\OAL Generator ] on the OAB generation server.

This can be done in two ways:

  • Via the Exchange Management Console

Open the Exchange Management Console navigate to [ Server Configuration ] from the right hand pane – right click on the OAB Generation Server and from the context menu that appears choose “Manage Diagnostic Logging Properties” – see below


From the dialog box that appears – select [ MSExchangeSA –> OAL Generator ] then select the relevant logging level (Lowest, Low, Medium, High, or Expert) and then click on the “Manage” button – see below


  • Via the Exchange Management Shell directly on the Generation Server

You can also set the diagnostic logging level for the OAL Generator from the Exchange Management Shell directly on the Generation Server using the following command line:

Set-EventLogLevel -Identity "MSExchangeSA\OAL Generator" -Level Expert -Confirm:$False

You can also execute this command remotely by using a Powershell remote session (which is the direction that we are heading in for reasons that will become clear very soon) – see below

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI http://servername/powershell
Invoke-Command -Session $Session  {
    Set-EventLogLevel -Identity "MSExchangeSA\OAL Generator" -Level Expert -Confirm:$False

Of course by setting the Logging level to “Expert” on the Generation Server – I was presented with a situation that I personally found a little long winded – as the process that I had to go through to both update the offline address book and gather the logging information involved:

  • Raising the Event Logging of the “MSExchangeSA\OAL Generator” on the designated generation server to “Expert
  • Performing another “Update-OfflineAddressBook” command after I had raised the logging level on the Generation Server
  • Logging onto the OAB Generation Server and review the Application Event Log and filter out all System Attendant Events which are part of the OAL Generator category
  • Put the Event Logging Level back to “Lowest” on the OAB generation server

So I decided to write a Powershell script that would automate all of the above tasks for me that could also be executed from any Exchange Server / Computer that had the Exchange Management tools installed and then compile the results into a HTML based report file.

The Script

The script that I came up with is detailed below (with an associated download should a copy and past from the website not work as it should)

   This script will perform an update of the Offline Address Book Service, but will configure logging levels
   to aid in troubleshooting. These logs will then be collated into a single log file for viewing.
.PARAMETER oAddressBook
   -oAddressBook "Address Book Name" -fHTML "Path and Filename for HTML Report"

   .\updateOABandLog.ps1 -oAddressBook "<Name of Address Book>" -fHTML <Path to HTML file>


    (c) 2012
    Author: Andy Grogan
    v1.0 - First Release


    [parameter(Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Name of the Offline Address Book that you wish to update")]$oAddressBook,
    [parameter(Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Path and Filename to report file")]$fHTML

function checkExchangeSN
    if (! (Get-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction:SilentlyContinue) )
        Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction:Stop

New-Item -ItemType file $fHTML -Force | Out-Null
$ComputerName = $env:COMPUTERNAME
Write-Host "Execution Computer Name is: " $ComputerName -ForegroundColor White

function writeHeader{ 
    Add-Content $fileName "<html>"
    Add-Content $fileName "<head>"
    Add-Content $fileName "<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>"
    Add-Content $fileName '<title>OAB Events Report</title>'
    Add-content $fileName '<STYLE TYPE="text/css">'
    Add-content $fileName  "<!--"
    Add-content $fileName  "td {"
    Add-content $fileName  "font-family: Tahoma;"
    Add-content $fileName  "font-size: 12px;"
    Add-content $fileName  "border-top: 1px solid #999999;"
    Add-content $fileName  "border-right: 1px solid #999999;"
    Add-content $fileName  "border-bottom: 1px solid #999999;"
    Add-content $fileName  "border-left: 1px solid #999999;"
    Add-content $fileName  "padding-top: 0px;"
    Add-content $fileName  "padding-right: 0px;"
    Add-content $fileName  "padding-bottom: 0px;"
    Add-content $fileName  "padding-left: 0px;"
    Add-content $fileName  "}"
    Add-content $fileName    ".Headings {"
    Add-content $fileName  "font-family: Tahoma;"
    Add-content $fileName  "font-size: 14px;"
    Add-content $fileName  "font-weight: bold;"
    Add-content $fileName "}"
    Add-content $fileName  "body {"
    Add-content $fileName  "margin-left: 5px;"
    Add-content $fileName  "margin-top: 5px;"
    Add-content $fileName  "margin-right: 0px;"
    Add-content $fileName  "margin-bottom: 10px;"
    Add-content $fileName  ""
    Add-content $fileName  "table {"
    Add-content $fileName  "border: thin solid #000000;"
    Add-content $fileName  "}"
    Add-content $fileName  "-->"
    Add-content $fileName  "</style>"
    Add-Content $fileName "</head>"
    Add-Content $fileName "<body>"  
    Add-content $fileName  "<table width='100%'>"
    Add-content $fileName  "<tr bgcolor='#3366FF'>"
    Add-content $fileName  "<td colspan='7' height='25' align='left'>"
    Add-content $fileName  "<font face='tahoma' color='#FFFFFF' size='4'><strong>Offline Address Book Processing Log - Executed on: $ComputerName</strong></font>"
    Add-content $fileName  "</td>"
    Add-content $fileName  "</tr>"
    Add-content $fileName  "</table>"  

function WriteFooter(){

    Add-Content $fileName "</body>"
    Add-Content $fileName "</html>"


function script_Logging($logEntry,$Colour){
    Write-Host $logEntry -ForegroundColor $Colour

function get_OABServer{
    $oabGenSrv = Get-OfflineAddressBook $oAddressBook  | Select -ExpandProperty Server
    return $oabGenSrv

function set_Logging($switch){
    script_Logging "Getting OAB Generation Server" "Green"
    $GenerationServer = get_OABServer
    script_Logging "OAB Generation Server is: $GenerationServer" "Yellow"
    $URIString = "http://" +  $GenerationServer + "/Powershell"
    script_Logging $URIString "Green"
    script_Logging "Setting up new PS Session to remote host" "Green"
    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI $URIString     
    script_Logging "Getting Mode" "Green"
    if($switch.ToLower() -eq 'enable'){
        script_Logging "Mode Set to Enable" "Green"
        Invoke-Command -Session $Session  {
            Set-EventLogLevel -Identity "MSExchangeSA\OAL Generator" -Level Expert -Confirm:$False
        script_Logging "Exiting Remote PS Session" "Cyan"
        script_Logging "Mode Set to Disable" "Green"
        Invoke-Command -Session $Session {
            Set-EventLogLevel -Identity "MSExchangeSA\OAL Generator" -Level Lowest -Confirm:$False
        script_Logging "Exiting Remote PS Session" "Cyan"

function update_OAB{
    $PerformUpdate = Update-OfflineAddressBook -Identity $oAddressBook
    script_Logging "Sleeping for 60 Seconds - ZZZZZZzzzzzzzzzz" "Green"
    Sleep 60
    $GenerationServer = get_OABServer
    script_Logging "Getting Event Logs from System Attendant on OAB Server" "Green"
    $oabEVENTS = Get-EventLog -ComputerName $GenerationServer -LogName "Application" -Source "MSExchangeSA" | where {$_.Category -eq 'OAL Generator'}
    Add-Content $fileName "<p class=headings>OAB Generation Event Logs from OAB Generation Server: $GenerationServer</p>"
    Add-Content $fileName "<table>"
    Add-Content $fileName "<tr>"
    Add-Content $fileName "<td><strong>Event ID</strong></td>"
    Add-Content $fileName "<td><strong>Time Generated</strong></td>"
    Add-Content $fileName "<td><strong>Machine Name</strong></td>"
    Add-Content $fileName "<td><strong>Category</strong></td>"
    Add-Content $fileName "<td><strong>Entry Type</strong></td>"
    Add-Content $fileName "<td><strong>Message</strong></td>"
    Add-Content $fileName "</tr>"
    foreach($evt in $oabEVENTS){
        $evtID = $evt.EventID
        $evtTime = $evt.TimeGenerated
        $evtMachine = $evt.MachineName
        $evtCat = $evt.Category
        $evtType = $evt.EntryType
        $evtMessage = $evt.Message
        if($evtType -eq 'Error'){
            Add-Content $fileName "<tr bgcolor=""#FF0000"">"
            Add-Content $fileName "<td>$evtID</td>"
            Add-Content $fileName "<td>$evtTime</td>"
            Add-Content $fileName "<td>$evtMachine</td>"
            Add-Content $fileName "<td>$evtCat</td>"
            Add-Content $fileName "<td>$evtType</td>"
            Add-Content $fileName "<td>$evtMessage</td>"
            Add-Content $fileName "</tr>"
        }elseif($evtType -eq 'Warning'){
            Add-Content $fileName "<tr bgcolor=""FBDA05"">"
            Add-Content $fileName "<td>$evtID</td>"
            Add-Content $fileName "<td>$evtTime</td>"
            Add-Content $fileName "<td>$evtMachine</td>"
            Add-Content $fileName "<td>$evtCat</td>"
            Add-Content $fileName "<td>$evtType</td>"
            Add-Content $fileName "<td>$evtMessage</td>"
            Add-Content $fileName "</tr>"
            Add-Content $fileName "<tr>"
            Add-Content $fileName "<td>$evtID</td>"
            Add-Content $fileName "<td>$evtTime</td>"
            Add-Content $fileName "<td>$evtMachine</td>"
            Add-Content $fileName "<td>$evtCat</td>"
            Add-Content $fileName "<td>$evtType</td>"
            Add-Content $fileName "<td>$evtMessage</td>"
            Add-Content $fileName "</tr>"
    Add-Content $fileName "</table>"
    writeHeader $fHTML
    set_logging "enable" "Green"
    update_OAB $fHTML
    set_logging "disable" "Green"
    writeFooter $fHTML
    script_Logging "Script Completed" "Yellow"
    Invoke-Item $fHTML


[ UpdateOABandLog.ps1 – 8KB ]

Script Usage

Should you wish to use the script download it to a location on one of your Exchange Servers (or a computer with the Exchange 2010 management tools installed), open a Powershell session and type in the following command:

.\UpdateOABandLog.ps1 -oAddressBook "PrepAD Offline Address List" -fHTML x:\scripts\OAB-Report.html

If execution fails you might need to follow some of the steps that are detailed in the article that I detailed here.

Sample Script Output

When the script is executed you will see output similar to the following screenshot


When the script has finished you should be presented with report within your default web browser that details all events that occurred during the execution of the “Update-OfflineAddressBook” cmdlet. The script is designed to highlight Warnings in Yellow and Errors in Red – see below


So what was my problem?

I suppose that the above is a bit of a leading question really – those who know me will say that I have loads of problems, but in the context of this post the reason why my user was not appearing in the Offline Address List was down to a previously deleted OAB entry which was still the default OAB within Active Directory (don’t know who did this as I inherited this Exchange installation) – after a bit of reconfiguration using ADSI edit all was back to normal – but using this script helped me identify the problem from a single workstation, and I hope that it will be of some use to someone out there.

Exchange 2010 Articles, Powershell 0 Replies to “Quick Tip – Script to collate Exchange 2010 OAB Generation Logs…”