Check if an AD user exists with Get-ADUser

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

In this article I describe how to check if an Active Directory user exists or not with the PowerShell cmdlet Get-ADUser, and show how to handle the quirks, such as the one that -ErrorAction Stop does not work, nor does setting $ErrorActionPreference = 'Stop', and using try {} catch {}.

The AD cmdlets are inconsistent with PowerShell standards in some ways. Missing -WhatIf support on critical cmdlets, "-Properties" instead of "-Property" (you're supposed to use the singular form; this is seen on other parameters as well here and there) , -ErrorAction doesn't behave as many expect, and possibly things I don't know about, to mention a few.

This information is valid as per 2016-01-28, with 2008 R2 and 2012 R2 servers using the built-in Get-ADUser cmdlet. PowerShell versions 2, 3, 4, and 5.

I revisited this problem now on 2017-03-12 and, to my surprise, now the try/catch block works on 2012 R2 on a fresh install against a Server 2016 AD controller. The screenshot below, showing the failures, is from 2012 R2, but against a 2016 AD in the new lab, still on 2012 R2 (fresh install), it works. I'm not sure if the AD cmdlets have somehow been updated (I didn't think that was possible, but can it happen via Windows Update now??) or if it's because the AD controller itself is Server 2016. Click here to jump directly to that part.

tl;dr:

[bool] (Get-ADUser -Filter { SamAccountName -eq $SomeSamAccountName }) 




Screenshot example

This demonstrates that -ErrorAction SilentlyContinue doesn't seem to work with Get-ADUser -Identity when a user doesn't exist.

It also demonstrates one of the successful verification methods I document more extensively below in this article.

Get-ADUser-check-user-exists-example.png

Verifying an AD user exists - failed attempt one

You might find out about "-ErrorAction Stop" and try {} catch {} blocks, and expect something like this to work:

Import-Module ActiveDirectory
$SamAccountName = 'doesNotExist'
try {
    $User = Get-ADUser -Filter { SamAccountName -eq $SamAccountName } -ErrorAction Stop
}
catch {
    Write-Warning -Message "User does not exist."
} 

Except it does not print the warning. Setting $ErrorActionPreference = 'Stop' does not work either. This is a bug/flaw with at least this AD cmdlet. I suppose the reason would be that it doesn't fail to execute the query, it just doesn't find the user.

These tests were performed on a 2012 R2 computer with PSv5 in January 2016. Now that it's March 2017, also see the new behavior

Verifying an AD user exists - successful attempt one

You could force the output to be an array using the @() notation, and checking if the .Count property is 0 for non-existence, or greater than 0 for existence (.Count -gt 0 or .Count -eq 1), like this:

if (@(Get-ADUser -Filter { SamAccountName -eq $SamAccountName }).Count -eq 0) {
    Write-Warning -Message "User $SamAccountName does not exist."
}

This works.

Verifying an AD user exists - successful attempt two

You can also simply cast what's returned to a [bool] type; that's a so-called boolean value that can either be true or false (respectively traditionally represented by the numbers 1 and 0).

$SamAccountName = 'doesnotexist'
[bool] (Get-ADUser -Filter { SamAccountName -eq $SamAccountName }) # returns false

$SamAccountName = 'joakimbs'
[bool] (Get-ADUser -Filter { SamAccountName -eq $SamAccountName }) # returns true

So you can check in an if statement (I also tossed in a foreach loop) like you see below. Remove the "-not" to invert the logic and check if a user exists.

foreach ($SamAccountName in 'doesNotExist', 'joakimbs') {
    if (-not [bool] (Get-ADUser -Filter { SamAccountName -eq $SamAccountName })) {
        Write-Warning -Message "User ${SamAccountName} does not exist."
    }
}

Another example (PSv3 on Server 2008 R2):

PS C:\> $users = 'joakimbs', "blabla"

PS C:\> $users | foreach { [bool] (Get-ADUser -Filter { SamAccountName -eq $_ } ) }
True
False

New behavior

As I talk about in the beginning of this article, the behavior has changed as of March 2017 with a Windows Server 2016 AD controller. Here's an example of how you can now do it. You don't actually even need the "-ErrorAction Stop" part - it'll work even with -ErrorAction SilentlyContinue now (which is weird?). Trying to document this new behavior now.

Image example of how you can now do it:

Check-if-an-ad-user-exists-example-updates-2017-server-2016-ad.png

As text:

PS C:\temp> $UserList = @("DoesNotExist", "TestUser0001")
foreach ($u in $UserList) {
    try {
        $ADUser = Get-ADUser -Identity $u -ErrorAction Stop
    }
    catch {
        if ($_ -like "*Cannot find an object with identity: '$u'*") {
            "User '$u' does not exist."
        }
        else {
            "An error occurred: $_"
        }
        continue
    }
    "User '$($ADUser.SamAccountName)' exists."
    # Do stuff with $Result
}

User 'DoesNotExist' does not exist.
User 'testuser0001' exists.

PS C:\temp>


Verifying an AD user exists using ADSISearcher

For the sake of the completeness of this article, I'll mention a few things about also using ADSI, which can be used in PowerShell version 1 as well.

I base my example on what I found here and have amended a few things based on the query to target only users that I looked up in my own wiki article here.

First I tried what Richard Mueller mentions, and did this:

PS D:\> $SamAccountName = 'test'

PS D:\> $Searcher = [adsisearcher] "(sAMAccountName=$SamAccountName)"

PS D:\> if (@($Searcher.FindOne()).Count -eq 1) { "$SamAccountName exists" } else { "$SamAccountName does not exist" }
test exists

PS D:\> get-aduser test
get-aduser : Cannot find an object with identity: 'test' under: 'DC=ad,DC=example,DC=org'.

So "test" is found as a SAM account name, but is not an actual AD user object (another type of object, see below). Since the SAM account name is unique per AD, I suppose the distinction is not always needed between a user or other type of object, but if it is, here's how to verify it really is a user:

# I was wondering what kind of object "test" is.
PS D:\> (Get-ADObject -Filter { SamAccountName -eq 'test' }).ObjectClass
group

PS D:\> $SamAccountName = "test"
PS D:\> $Searcher = [adsisearcher] "(&(objectCategory=Person)(objectClass=User)(sAMAccountName=$SamAccountName))"
PS D:\> if (@($Searcher.FindOne()).Count -eq 1) { "$SamAccountName exists" } else { "$SamAccountName does not exist" }
test does not exist

The only difference is in the LDAP query, where I added "(objectClass=user)", which targets users, and "(objectCategory=Person)", which filters out "contact" type AD objects that would otherwise be part of the results.