Search code examples
powershellvalidationoopactive-directorypowershell-3.0

Powershell: Checking for duplicate email in AD


Background: I'm trying to make a script that will see if a new users email ($email) is the same as one already existing (which would cause an error). I have a very remedial understanding of objects so this is what I have so far (yes it is ugly):

$email = "[email protected]"   
$mailcheck = Get-ADUser -filter * -Properties * | ForEach-Object {$_.mail}
$mailcheck | ForEach-Object {if ($email -eq $_.mail){"$email = $($_.mail) - Matching email"}else{"$email = $($_.mail) - No duplicate email"}}

Problem 1: The script doesn't match emails. When I have a matching email in AD it doesn't recognize it.

Problem 2: When executing just the 2nd line, indexing doesn't work properly. While it looks like a consecutive list of emails, if a user doesn't have an email at all (blank) really it could be something like this:

[email protected]

[email protected]


[email protected]
[email protected]

So $mailcheck[0] returns [email protected] while $mailcheck[1] returns blank despite the list actually looking like this:

[email protected]    
[email protected]             
[email protected]
[email protected]

Conclusion: I really just need problem 1 solved but problem 2 peaked my curiosity. Thanks.


Solution

  • The way you are doing it above is really inefficient. -Properties * will return every property on the user, some properties are expensive in terms of processing power to return. Only use the properties you need. The properties returned by default without specifying that parameters do not need to be specified with -Properties, only additional nondefault properties. -Filter * will also match on literally any value for any field, effectively returning every ADUser, further increasing the resources required for your script to execute as you will now have to process every user to find any accounts matching that email.

    Now that that's out of the way, here is a more efficient method to implement what you're asking:

    # Set the email address to search for
    $emailAddress = '[email protected]'
    
    # Get all users where the email address matches what is set above
    # Force it as an array so you can treat it like one even if only
    # one or zero users are returned
    $adUsers = @( Get-ADUser -Filter "EmailAddress -eq '${emailAddress}'" )
    
    # Make sure no accounts were returned
    # If there are, throw an error with the number of users and who they are
    if( $adUsers ) {
      throw "Found $($adUsers.Count) users matching EmailAddress ${emailAddress}: $($adUsers.SamAccountName -join ', ')"
    }
    

    By using the filter to only match the specific email address, Powershell does not need to collect every single AD user in the system, or iterate over all of them to find a specific email address. This will take a long time to check, especially in larger environments, whereas filtering the returned objects based on email address (or on any other property) results in a faster operation and less data to sift through.

    You can then check whether $adUsers contains anything (an array count of anything but 0 evaluates to $True, you could also use if( $adUsers.Count -gt 0 ) as the condition), and if so, throw an error with more information as I do above.

    Update for comment question:

    To answer your other question in the comment, "I didn't know what object to compare $email to", EmailAddress and Mail both look to be valid properties, but I don't know the difference between them. In my environment, both Mail and EmailAddress are populated with my email address, but have always used EmailAddress and haven't run into issues using that. Maybe one is deprecated and the other is new or something, but I'm not really sure.

    There is also yet another property called proxyAddresses as well, which preliminary research shows that both EmailAddress and Mail are related to it, but I don't know much about it. It's not populated on my ADUser objects, so I can't poke around with it.