Skip to content

Instantly share code, notes, and snippets.

@HurtzDonut
Last active February 7, 2019 17:21
Show Gist options
  • Save HurtzDonut/a16ba1c9b5e6a03d627bb1b62f8b3747 to your computer and use it in GitHub Desktop.
Save HurtzDonut/a16ba1c9b5e6a03d627bb1b62f8b3747 to your computer and use it in GitHub Desktop.
Get-ADUser CmdLet help - Markdown file


Introduction

Some of the most common issues I see posted are regarding the Active Directory CmdLets, specifically, Get-ADUser, and I would like to take some time to help clarify some things.


Get-ADUser

Filter Syntax

From the Get-ADUser Microsoft Doc:

Specifies a query string that retrieves Active Directory objects.

The following syntax uses Backus-Naur form to show how to use the PowerShell Expression Language for this parameter.

<filter> ::= "{" <FilterComponentList> "}"

<FilterComponentList> ::= <FilterComponent> | <FilterComponent> <JoinOperator> <FilterComponent> | <NotOperator> <FilterComponent>

<FilterComponent> ::= <attr> <FilterOperator> <value> | "(" <FilterComponent> ")"

<FilterOperator> ::= "-eq" | "-le" | "-ge" | "-ne" | "-lt" | "-gt"| "-approx" | "-bor" | "-band" | "-recursivematch" | "-like" | "-notlike"

<JoinOperator> ::= "-and" | "-or"

<NotOperator> ::= "-not"

<attr> ::= <PropertyName> | <LDAPDisplayName of the attribute>

<value>::= <compare this value with an <attr> by using the specified <FilterOperator>

Now, all this may seem rather complex to a someone new with PowerShell, so let me try to break it down.

While it may not be intuitive at first, Filter expects a STRING value.

Filter Examples

Simple String

PS C:\> Get-ADUser -Filter 'Name -like "Lau*"'

DistinguishedName : CN=Lau Gan-Lan,OU=Users,DC=cabbage,DC=corp
Enabled           : True
GivenName         : Lau
Name              : Lau Gan-Lan
ObjectClass       : user
ObjectGUID        : 1b78014f-206d-40c1-b74c-11469d6071fd
SamAccountName    : lganlan
SID               : S-1-5-21-8401565-2470669646-3058293501-71676
Surname           : Gan-Lan
UserPrincipalName : lganlan@cabbage.corp

Simple Variable

PS C:\> $Name = "Lau"
PS C:\> Get-ADUser -Filter 'Name -like "$Name*"'

DistinguishedName : CN=Lau Gan-Lan,OU=Users,DC=cabbage,DC=corp
Enabled           : True
GivenName         : Lau
Name              : Lau Gan-Lan
ObjectClass       : user
ObjectGUID        : 1b78014f-206d-40c1-b74c-11469d6071fd
SamAccountName    : lganlan
SID               : S-1-5-21-8401565-2470669646-3058293501-71676
Surname           : Gan-Lan
UserPrincipalName : lganlan@cabbage.corp

In both examples above, we are passing a string to the Filter parameter, and returning the exact results we want.


Now, lets take a look at what happens if we pass a script block (i.e. {<property> -like <val>}):

Simple Script Block

PS C:\> Get-ADUser -Filter {Name -like "Lau*"}

DistinguishedName : CN=Lau Gan-Lan,OU=Users,DC=cabbage,DC=corp
Enabled           : True
GivenName         : Lau
Name              : Lau Gan-Lan
ObjectClass       : user
ObjectGUID        : 1b78014f-206d-40c1-b74c-11469d6071fd
SamAccountName    : lganlan
SID               : S-1-5-21-8401565-2470669646-3058293501-71676
Surname           : Gan-Lan
UserPrincipalName : lganlan@cabbage.corp

This still returns the results we want, as Get-ADUser converted the script block into a filter string.


But, /u/_Cabbage_Corp_, all the examples so far have done the same thing. So why do we need to pass a string?

Well, I'm glad you asked. Let's take a look at an exmaple that is slightly more complex:


Script Block & Variables with Properties

<# 
C:\Temp\Users.csv Contents
    First,Last,EmployeeID,Email
    Lau,Gan-Lan,2,Lau@CabbageCorp.org
#>

PS C:\> $Users = Import-CSV C:\Temp\Users.csv
PS C:\> Get-ADUser -Filter {SurName -eq $Users.Last}
Get-ADUser : Property: 'Last' not found in object of type: 'System.Management.Automation.PSCustomObject'.
At line:1 char:1
+ Get-ADUser -Filter {SurName -eq $Users.Last}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-ADUser], ArgumentException
    + FullyQualifiedErrorId : Property: 'Last' not found in object of type: 'System.Management.Automation.PSCustomObject'.,Microsoft.ActiveDirectory.Management.Commands.GetADUser

As you can see, in this example, we have a CSV with some employee data. If we were to run $Users.Last we would see the correct info: Gan-Lan is returned.

So why doesn't Get-ADUser work when we know the data is correct??

Simple. As we stated earlier -Filter is expecting a string. By passing a script block to -Filter, we are forcing Get-ADUser to convert this to a string for us. So in effect we are running:

PS C:\> Get-ADUser -Filter "SurName -eq $Users.Last"

And, as we know, in order to access the properties of a variable inside of a string we need to use a method similar to one of the following:

"$($Variable.Property)"
"{0}" -F $Variable.Property

Script Block & Variables with Properties (cont'd)

With that in mind, we could change our previous example to this:

PS C:\> Get-ADUser -Filter {SurName -eq $($User.Last)}

However, when we run this we receive a rather cryptic error message:

Get-ADUser : Cannot process argument because the value of argument "path" is not valid. Change the value of the "path" argument and run the operation again.
At line:1 char:1
+ Get-ADUser -Filter {SurName -eq $($Users.Last)}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-ADUser], PSArgumentException
    + FullyQualifiedErrorId : Cannot process argument because the value of argument "path" is not valid. Change the value of the "path" argument and run the operation again.
,Microsoft.ActiveDirectory.Management.Commands.GetADUser

Path?? What path??

We changed the syntax of our variable to allow for expansion inside strings, so why didn't this work?!

Well, I can't explain it any better than this Stack Overflow explanation

Stack Overflow - mklement0

If you specify a script block - which you should avoid:

A script block, when converted to a string, results in the literal contents between { and } - no variable expansion (interpolation) takes place

Therefore, it is literal sAMAccountName -eq "$SamAc" that is passed to Get-ADUser.

Get-ADUser, perhaps in an effort to support the script-block syntax / be more PowerShell-like, does support referencing a variable unquoted...

However, this emulation of a regular PowerShell script block is not only confusing - because users still think they need enclosing quotes - but also half-baked, and therefore brittle


Bringing it all together

Finally, we've reached the end of our journey together. Hopefully, this has helped you in some way/shape/form. Below you will find a quick TL;DR of our conversation together. Thanks for reading, and keep on being awesome!!

TL;DR

# Get-ADUser with simple string
PS C:\> Get-ADUser -Filter 'Name -like 'Lau*'"
# Returns all AD User Objects with their Name property starting with [Lau]


# Get-ADUser with simple variable
PS C:\> $LastName = 'Gan-Lan'
PS C:\> Get-ADUser -Filter 'SurName -eq "$LastName"'
# Returns all AD User Objects with their SurName property equal to the value of the variable $LastName


# Get-ADUser with variable properties
<#
C:\Temp\Users.csv Contents
    First,Last,EmployeeID,Email
    Lau,Gan-Lan,2,Lau@CabbageCorp.org
#>
PS C:\> $Users = Import-CSV -Path C:\Temp\Users.csv
PS C:\> Get-ADUser -Filter 'GivenName -like "$($Users.First)*"'
# Returns all AD User Objects with their GivenName property starting with the value found in $Users.First, which is populated from C:\Temp\Users.csv


# Advanced Example
<#
C:\Temp\Users.csv Contents
    First,Last,UserName,EmployeeID,Email,Dept
    Lau,Gan-Lan,lganlan,002,Lau@CabbageCorp.org,Executive
    Hari,Ritorra,hritorra,100,Hari.Ritorra@CabbageCorp.org,Marketing
    Vilram,Rongeng,vrongeng,200,Vilram.Rongeng@CabbageCorp.org,HR
    Talris,Gotsal,tgotsal,201,Talris.Gotsal@CabbageCorp.org,Marketing
    Tila,Wilan,twilan,300,Tila.Wilan@CabbageCorp.com,Accounting
#>
PS C:\> $Users = Import-CSV -Path C:\Temp\Users.csv
PS C:\> $Users | 
    ForEach-Object {
        $Dept = Switch ($PSItem.Dept) {
            'Accounting'{'Accounting_TeamMembers'}
            'Executive' {'Executive_Staff'}
            'HR'        {'HumanResources_Team'}
            'Marketing' {'Marketing_Dept'}
            Default     {'General_Staff'}
        }
    
        Get-ADUser -Filter 'Enabled -eq "$True" -and SamAccountName -eq "$($PSItem.UserName)"' |
            ForEach-Object {
                Add-ADGroupMember -Identity $Dept -Members $PSItem
            }
    }
# 1. Imports a list of users from C:\Temp\Users.csv
# 2. Loops through each entry, and does the following:
#   i. Sets the variable $Dept based on the value of the 'Dept' property of the current user
#   ii. Gets the AD User Object for the current user, using the 'UserName' property
#   iii. Adds the AD User Object to the pre-determined $Dept group
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment