Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 

Looking Up Email Addresses with PowerShell

A week or so ago Aaron Nelson (Blog|Twitter) put out a call for help on Twitter looking for anyone that could help with adding autocomplete for looking up an email address to a PowerShell forms application. The original request was to look up the user in the Global Address List (GAL) via Outlook but after some thought we decided to switch to looking up the recipients via Active Directory (AD), allowing the search to work on machines that do not have Outlook installed…like servers. I will walk through both functions then provide a quick and dirty test application so you can try out the code for yourself.

The first function I want to show is the one to look up a recipient via Outlook. Despite its limited application this is the more interesting code block to me. I love that I only had to pass a partial name to get back the closest match from the GAL. I chose to include the instantiation of the $outlook object in this function because it made for a more clear example. If I were writing production code I would likely declare $outlook as a global variable then just instantiate it in this function if it had not been already. A great source for more information on calling into Outlook from PowerShell is this article.

1
2
3
4
5
6
7
8
9
[void] [System.Reflection.Assembly]::LoadWithPartialname("Microsoft.Office.Interop.Outlook")

Function get-emailOutlook{
    param([System.String] $searchString)
    [Microsoft.Office.Interop.Outlook.Application] $outlook = New-Object -ComObject Outlook.Application
    $item = $outlook.Session.GetGlobalAddressList().AddressEntries.Item($searchString)
    $name.Text = $item.Name
    $email.Text = $item.GetExchangeUser().PrimarySmtpAddress
}

The other way to get after this information is via Active Directory. My feeling is that this is going to be the preferred method for most people to look up email addresses. The exception would be those people that want to be able to look up contacts from outside their organization in their local address book. Going the AD route took a few more lines of code, but was still quite easy. The big difference here is that we had to define a search filter by applying the wildcard symbol, “*”, to the portion of the recipient name that had been typed so far. The other big thing to notice is that checks to make sure the results are not null had to be added because unlike the Outlook this search may not return any results. I found this article incredibly helpful in putting this function together.

1
2
3
4
5
6
7
8
9
10
11
12
13
Function get-emailAD{
    param([System.String] $searchString)
    [System.DirectoryServices.DirectorySearcher] $searcher = New-Object System.DirectoryServices.DirectorySearcher
    $searcher.Filter = "(&(objectCategory=User)(Name=$searchString*))"
    $path = $searcher.FindOne()
    if($path){
        $user = $path.GetDirectoryEntry()
    }
    if($name){
            $name.Text = $user.name
            $email.Text = $user.mail
    }
}

That does it for the functions. Now for the test harness. This code is not terribly pretty and could probably be made more robust but it seems to work well enough for me to demonstrate the calls. The one thing that I had thought I would need to add is multi-threading to work like AJAX, but since the code runs so much faster than the HTTP calls you would see with AJAX it seems unnecessary. If the lookups run slowly in your environment then it would make sense to add some threading logic. With that, here is the code for the test harness:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialname("Microsoft.Office.Interop.Outlook")

Function get-emailAD{
    param([System.String] $searchString)
    [System.DirectoryServices.DirectorySearcher] $searcher = New-Object System.DirectoryServices.DirectorySearcher
    $searcher.Filter = "(&(objectCategory=User)(Name=$searchString*))"
    $path = $searcher.FindOne()
    if($path){
        $user = $path.GetDirectoryEntry()
    }
    if($name){
        $name.Text = $user.name
        $email.Text = $user.mail
    }
}

Function get-emailOutlook{
    param([System.String] $searchString)
    [Microsoft.Office.Interop.Outlook.Application] $outlook = New-Object -ComObject Outlook.Application
    $item = $outlook.Session.GetGlobalAddressList().AddressEntries.Item($searchString)
    $name.Text = $item.Name
    $email.Text = $item.GetExchangeUser().PrimarySmtpAddress
}

Function get-email{
    [System.Int32] $location = $name.SelectionStart
    if($location -eq 0){
        $name.Text = ""
        $email.Text = ""
        return;
    }
    if ($useOutlook.Checked -eq $true){
        get-emailOutlook -searchString $name.Text.Substring(0,$location)
    }
    else{
        get-emailAD -searchString $name.Text.Substring(0,$location)
    }
    $name.SelectionStart = $location
}

[System.Windows.Forms.Form] $form = New-Object System.Windows.Forms.Form
$form.Text = 'Autocomplete Tester'
$form.Size = New-Object System.Drawing.Size(400, 200)
$form.StartPosition = 'CenterScreen'
$form.KeyPreview = $true
$form.Add_KeyDown({if ($_.KeyCode -eq 'Enter'){$name.SelectionStart = $name.TextLength;$email.Visible = $true;}})
$form.Add_KeyDown({if ($_.KeyCode -eq 'Escape'){$form.Close()}})

[System.Windows.Forms.Label] $nameLabel = New-Object System.Windows.Forms.Label
$nameLabel.Text = "Name to Search for:"
$nameLabel.Width = 110
$nameLabel.Location = New-Object System.Drawing.Size(20, 50)
$form.Controls.Add($nameLabel)

[System.Windows.Forms.TextBox] $name = New-Object System.Windows.Forms.TextBox
$name.Text = ''
$name.Width = 200
$name.Location = New-Object System.Drawing.Size(140, 50)
$name.AutoSize = $true
$name.Add_KeyUp({get-email})
$form.Controls.Add($name)

[System.Windows.Forms.Label] $emailLabel = New-Object System.Windows.Forms.Label
$emailLabel.Text = "Email Address:"
$emailLabel.Width = 110
$emailLabel.Location = New-Object System.Drawing.Size(20, 80)
$form.Controls.Add($emailLabel)

[System.Windows.Forms.TextBox] $email = New-Object System.Windows.Forms.TextBox
$email.Text = ''
$email.Location = New-Object System.Drawing.Size(140, 80)
$email.Width = 200
$email.AutoSize = $true
$email.Visible = $false
$form.Controls.Add($email)

[System.Windows.Forms.CheckBox] $useOutlook = New-Object System.Windows.Forms.CheckBox
$useOutlook.Checked = $false
$useOutlook.Text = "Use Outlook"
$useOutlook.Location = New-Object System.Drawing.Size(20, 20)
$form.Controls.Add($useOutlook)

$form.Topmost = $True
$form.Add_Shown({$form.Activate()})
[void] $form.ShowDialog()

I hope you find these functions helpful. Please let me know if you run into any issues with them or know of a better way to do the same thing. Please keep in mind that scripts from the internet are like Halloween candy, inspect before consumption. I offer no warranty beyond a sympathetic ear if you should run into any issues.

Comments

No comments.

Leave a Comment

Please register or log in to leave a comment.