Recently, I faced a common IT administrative task: extracting email addresses from Active Directory for a list of users but in the format of "Firstname Surname" this task which seemed like a straightforward quickly revealed some interesting challenges where the data was not samAccount name or any valid computer based data, but human derived data.
I started with a simple text file containing a list of users in the format:
John Smith
Jane Doe
Robert-J Johnson
Sarah-MB Williams
Michael Brown
Sam Taylor
My goal was clear: look up each user in Active Directory and extract their SMTP email address that ends with "@bythepowerofgreyskull.com". I also needed to make sure I was only retrieving information for enabled accounts.
I started with a basic PowerShell script that would:
- Read the list of users from a text file
- Split each line into first name and last name
- Query AD for matching users
- Extract their email addresses
Here's what my initial approach looked like:
# Read the list of users
$users = Get-Content -Path "UserList.txt"
$results = @()
foreach ($user in $users) {
# Split into first name and last name
$nameParts = $user -split " ", 2
$firstName = $nameParts[0]
$lastName = $nameParts[1]
# Search AD
$adUser = Get-ADUser -Filter "GivenName -like '$firstName*' -and Surname
-eq '$lastName'" -Properties EmailAddress
# Extract email
$results += [PSCustomObject]@{
FullName = $user
FirstName = $firstName
LastName = $lastName
Email = $adUser.EmailAddress
}
}
# Export to CSV
$results | Export-Csv -Path "C:\Path\To\UserEmails.csv" -NoTypeInformation
I quickly realized that some of the names in my list had hyphens in the first name, like "Adam-J" or "Adam-PR". This was causing issues with AD lookups because these naming conventions don't always match exactly with what's stored in Active Directory.
I added some logic to handle hyphenated first names:
# Handle first names with hyphens
if ($firstName -match "-") {
$firstNameParts = $firstName -split "-"
$firstName = $firstNameParts[0] # Use only the first part for searching
}
This modification would allow "Adam-J" to match with "Adam" in Active Directory.
When I ran the script and checked the output, I noticed another issue. Some results showed:
"FullName","FirstName","LastName","Email"
"John Smith","John","Smith","System.Object[]"
"Jayne Doe","Jayne","Doe","System.Object[]"
The "System.Object[]" indicated that the script was returning multiple AD user objects for a single name lookup. This happens when there are several accounts with similar names in AD.
I needed to handle this situation by properly selecting one account from multiple matches:
if ($adUsers -is [array]) {
# Try to find exact match first
$exactMatch = $adUsers | Where-Object { $_.GivenName -eq $firstName -and
$_.Surname -eq $lastName } | Select-Object -First 1
if ($exactMatch) {
$email = $exactMatch.EmailAddress
}
else {
# If no exact match, take the first result
$email = $adUsers[0].EmailAddress
}
}
else {
# Single user found
$email = $adUsers.EmailAddress
}
My next discovery came when examining the log file. I needed to specifically look for email addresses in the "@bythepowerofgreyskull.com" domain, not just any email address. In Active Directory, users can have multiple email attributes, and I needed to ensure I was getting the correct one.
This required me to look at both the primary email address and the proxyAddresses attribute:
function Get-SeverntrentEmail {
param ($User)
# First check if the main EmailAddress is a severntrent.co.uk address
if ($User.EmailAddress -like "*@bythepowerofgreyskull.com") {
return $User.EmailAddress
}
# If not, check proxyAddresses for severntrent.co.uk addresses
if ($User.proxyAddresses) {
# Look for primary SMTP address first that matches severntrent.co.uk
$primarySmtp = $User.proxyAddresses | Where-Object {
$_ -like "SMTP:*@bythepowerofgreyskull"
} | Select-Object -First 1
if ($primarySmtp) {
# Remove the "SMTP:" prefix
return ($primarySmtp -replace "SMTP:", "")
}
# If no primary, look for any secondary smtp addresses
$secondarySmtp = $User.proxyAddresses | Where-Object {
$_ -like "smtp:*@severntrent.co.uk"
} | Select-Object -First 1
if ($secondarySmtp) {
# Remove the "smtp:" prefix
return ($secondarySmtp -replace "smtp:", "")
}
}
# If no severntrent.co.uk email found, return null
return $null
}
The last requirement was to only include enabled accounts in the results. The logs were showing instances where multiple users were found, but some were disabled. I needed to modify the AD query to filter for enabled accounts only:
# Search only for enabled accounts
$adUsers = Get-ADUser -Filter "GivenName -like '$firstName*' -and Surname
-eq '$lastName' -and Enabled -eq `$true" -Properties EmailAddress, proxyAddresses
And then only include results in the output if they had a valid email:
# Only add to results if we found an email
if ($email) {
$results += [PSCustomObject]@{
FullName = $user
FirstName = $firstName
LastName = $lastName
Email = $email
}
}
The Final Solution
After addressing all these challenges, I ended up with a comprehensive PowerShell script that:
- Reads a list of users from a text file
- Properly handles hyphenated first names
- Queries only enabled AD accounts
- Handles multiple matching users appropriately
- Extracts only @severntrent.co.uk email addresses
- Logs all operations for troubleshooting
- Creates a clean CSV output with only valid results
Here's the core part of the final script:
# Process each user in the list
foreach ($user in $users) {
# Split into first name and last name
$nameParts = $user -split " ", 2
if ($nameParts.Count -eq 2) {
$firstName = $nameParts[0]
$lastName = $nameParts[1]
# Handle hyphenated first names
if ($firstName -match "-") {
$firstNameParts = $firstName -split "-"
$firstName = $firstNameParts[0]
}
# Search AD for enabled users only
$adUsers = Get-ADUser -Filter "GivenName -like '$firstName*' -and Surname
-eq '$lastName' -and Enabled -eq `$true" -Properties EmailAddress, proxyAddresses
# Process results
if ($adUsers) {
$email = $null
# Extract email using the custom function
if ($adUsers -is [array]) {
$exactMatch = $adUsers | Where-Object { $_.GivenName -eq $firstName
-and $_.Surname -eq $lastName } | Select-Object -First 1
if ($exactMatch) {
$email = Get-SeverntrentEmail -User $exactMatch
}
else {
foreach ($adUser in $adUsers) {
$potentialEmail = Get-SeverntrentEmail -User $adUser
if ($potentialEmail) {
$email = $potentialEmail
break
}
}
}
}
else {
# Single user found
$email = Get-SeverntrentEmail -User $adUsers
}
# Only add to results if a valid email was found
if ($email) {
$results += [PSCustomObject]@{
FullName = $user
FirstName = $firstName
LastName = $lastName
Email = $email
}
}
}
}
}
Lessons Learned
This project reminded me of several important lessons when working with Active Directory automation:
- Names are messy - People's names can be formatted in various ways, and your scripts need to be flexible enough to handle these variations.
- Multiple accounts exist - In large organizations, it's common to have multiple accounts for similar names (duplicates, test accounts, etc.). Always have a strategy for handling this.
- Check account status - Not all accounts in AD are active. Remember to filter for enabled accounts when appropriate.
- Email attributes are complex - AD stores email information in multiple attributes (EmailAddress, proxyAddresses, etc.). Make sure you're looking in the right places.
- Logging is essential - Detailed logging saved me countless hours of troubleshooting and helped track down edge cases.
The final script now runs smoothly against our user list, producing a clean CSV file containing only enabled users with their @bythepowerofgreyskull.com email addresses. What started as a seemingly simple task turned into an interesting journey through the nuances of Active Directory automation.