How to find UPN that contains digit? - powershell

i would like to know how to find UPN that constain digit with -filter?
Get-ADUser -filter {(UserPrincipalName -contains "I dont know what i should add here #contoso.com")} -properties userprincipalname | select userprincipalname

The -Filter argument of AD cmdlets, which accepts a string, uses PowerShell-like syntax, but with only a limited subset of supported operators, some of which work in subtly different ways than in PowerShell.
The filter language is not sophisticated enough to do the matching you want: the only pattern matching supported is via wildcards, which are limited to use of *, using the -like operator.[1]
Therefore, use -Filter for pre-filtering with -like, then use a Where-Object call to let PowerShell filter the results down, using its regex capabilities:
Get-ADUser -Filter 'UserPrincipalName -like "*#contoso.com"' -Properties UserPrincipalName |
Where-Object UserPrincipalName -match '\d'
Select-Object UserPrincipalName
Note:
-match '\d' matches if at least one digit (\d) is present in the input.
I've used a string rather than a script block ({ ... }) to specify the -Filter argument, because that's what -Filter expects. While seductively convenient, the use of script blocks is conceptually problematic and can lead to misconceptions - see this answer.
[1] By contrast, PowerShell's -like operator supports PowerShell's more fully-featured wildcard expressions. Also, the AD -Filter's language at least situationally interprets * to mean: at least one character, whereas PowerShell's wildcard expression interpret it as zero or more.

Related

Searching partial names with Powershell [duplicate]

I'd like to check if a user account already exists in the system.
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter {sAMAccountName -eq "$SamAc"}
I'm not sure why, but $User will always return null even if {sAMAccountName -eq "$SamAc"} is supposed to be true.
What am I missing here?
Edit:
This is what was missing:
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Editor's note: The script block ({ ... }) was replaced with a string.
There is valuable information in the existing answers, but I think a more focused summary is helpful. Note that the original form of this answer advocated strict avoidance of script blocks ({...}) and AD-provider variable evaluation, but this has been replaced with more nuanced recommendations.
Option A: Letting the AD provider resolve - stand-alone only - variable references:
Get-ADUser -Filter 'sAMAccountName -eq $SamAc' # note the '...' quoting
Note the use of '...', i.e. a verbatim (single-quoted) string, because the string's value is to be passed as-is to the AD provider (cmdlet).
While use of a script block ({ ... }), Get-ADUser -Filter { sAMAccountName -eq $SamAc }, technically works too (its verbatim content, sans { and }, is converted to a string), it is conceptually problematic - see bottom section.
Do not quote the variable reference ("$SamAc").
Use only stand-alone variable references (e.g, $SamAc); expressions are not supported (e.g., $user.SamAccountName or "$name*" or $("admin_" + $SamAc)); if necessary, use an intermediate, auxiliary variable; e.g.:
$name = "admin_" + $SamAc; Get-ADUser -Filter 'sAMAccountName -eq $name'
Generally, only a subset of PowerShell's operators are supported, and even those that are do not always behave the same way - see bottom section.
Caveat: If you use Get-ADUser via an implicitly remoting module - whether self-created via Import-PSSession or, in PowerShell v7+, via the Windows Compatibility feature - neither '...' nor { ... } works, because the variable references are then evaluated on the remote machine, looking for the variables there (in vain); if (Get-Command Get-ADUser).CommandType returns Function, you're using an implicitly remoting module.
If implicit remoting is involved, you MUST use string interpolation, as shown next.
Option B: Using PowerShell's string interpolation (expandable strings), up front:
Get-ADUser -Filter "sAMAccountName -eq `"$SamAc`"" # note the "..." quoting
Using "...", i.e. an expandable (double-quoted) string makes PowerShell interpolate (expand) all variable references and subexpression up front, in which case the AD provider sees only the (variable-free) result.
As shown above, for string operands embedded quoting then is necessary.
For embedded quoting, '...' is a simpler alternative to `"...`" (`" is an _escaped "), but note that this assumes that an expanded value doesn't itself contain ', which is a distinct possibility with last names, for instance.
Also, be sure to `-escape constants such as $true, $false, and $null inside the "..." string, which are always recognized by the AD provider; i.e., use `$true, `$false and `$null, so that PowerShell doesn't expand them up front.
Caveat: Using an expandable string does not work with all data types, at least not directly: for instance, the default stringification of a [datetime] instance (e.g., 01/15/2018 16:00:00 is not recognized by the AD provider; in this case, embedding the result of a call to the instance's .ToFileTime() (or .ToFileTimeUtc()?) method into the string may be necessary (as suggested in the comments on this post); I'm unclear on whether there are other data types that require similar workarounds.
On the plus side, string interpolation allows you to embed entire expressions and even commands in a "..." string, using $(...), the subexpression operator; e.g.:
# Property access.
Get-ADUser -Filter "sAMAccountName -eq `"$($user.SamAccountName)`""
# String concatenation
Get-ADUser -Filter "sAMAccountName -eq `"$('admin_' + $SamAc)`""
Background
Any argument you pass to -Filter is coerced to a string first, before it is passed to the Get-ADUser cmdlet, because the -Filter parameter is of type [string] - as it is for all provider cmdlets that support this parameter; verify with Get-ADUser -?
With -Filter in general, it is up to the cmdlet (the underlying PowerShell provider) to interpret that string, using a domain-specific (query) language that often has little in common with PowerShell.
In the case of Get-ADUser, that domain-specific language (query language) is documented in Get-Help about_ActiveDirectory_Filter.
Note: As of this writing, no newer version of this legacy topic exists; this GitHub issue requests one.
With Get-AdUser, the language supported by -Filter is certainly modeled on PowerShell, but it has many limitations and some behavioral differences that one must be aware of, notably:
As Santiago Squarzon points out, these limitations and difference stem from the fact that the language is translated into an LDAP filter behind the scenes, it is therefore constrained by its features and behaviors. (Note that you can use the -LDAPFilter parameter in lieu of -Filter to directly pass an LDAP filter).
Only a limited subset of PowerShell operators are supported, and some exhibit different behavior; here's a non-exhaustive list:
-like / -notlike only support * in wildcard expressions (not also ? and character sets/ranges ([...])
'*' by itself represents any nonempty value (unlike in PowerShell's wildcard expressions, where it also matches an empty one).
Instead of -eq "" or -eq $null to test fields for being empty, use
-notlike '*'.
Certain AD fields, e.g., DistinguishedName, only support '*' by itself, not as part of a larger pattern; that is, they only support an emptiness test.
There is no support for regex matching.
-lt / -le and -gt / -ge only perform lexical comparison.
Referencing a nonexistent / misspelled property name causes the Get-ADUser command to quietly return $null.
As stated, only stand-alone variable references are supported (e.g, $SamAc), not also expressions (e.g., $SamAc.Name or $("admin_" + $SamAc))
While you can use a script block ({ ... }) to pass what becomes a string to -Filter, and while this syntax can be convenient for embedding quotes, it is problematic for two reasons:
It may mislead you to think that you're passing a piece of PowerShell code; notably, you may be tempted to use unsupported operators and expressions rather than simple variable references.
It creates unnecessary work (though that is unlikely to matter in practice), because you're forcing PowerShell to parse the filter as PowerShell code first, only to have the result converted back to a string when the argument is bound to -Filter.
This one bit me when I first started to work with the ActiveDirectory module, and it was a pain to figure out.
The -Filter parameter for the ActiveDirectory module cmdlets is actually looking for a string. When you do {sAMAccountName -eq "$SamAc"} as the value, it is actually looking for "sAMAccountName -eq ""`$SamAc"""
Basically, Powershell parses the parameter and turns its value into a string, and will not interpolate the variable. Try building the string before hand, and it should work.
Something like this:
$SamAc = Read-Host 'What is your username?'
$filter = "sAmAccountname -eq ""$SamAc"""
$User = Get-ADUser -Filter $filter
I have to comment on this because it really aggravated me to sort this out.
Joseph Alcorn has the right idea. The filter parameter takes a string and then evaluates that in order to process the filter. What trips people up with this is that you are given the option to use curly brackets instead {}, and this doesn't work as you'd expect if you were using Where... it still has to be treated like a string.
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
I recommend sticking to quotes to make it more clear/readable for yourself and others and to avoid potential syntax errors, or stick to Where{} in the pipeline. When doing so, I find it best to use double-quotes on the outside & single-quotes on the inside so you still get intellisense detection on the variable.
Simply remove the quotes around your variable:
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter {sAMAccountName -eq $SamAc}
This should work just fine.
if (($ADUser = Get-ADUser -filter "SamAccountName -eq '$(Read-Host Username)'") -ne $null) {$ADUser.SamAccountName} else {"Not Found"}
Little addendum if anyone like me got here and was still tearing their hair out:
-properties *
Would be quite a common this to have in this query. Doesn't work, I'm sure someone smarter than me can figure it out
-properties mail,cn,wtf
etc does work as expected
It took me quite a bit to just use
Do not quote the variable reference ("$SamAc").
TXH so much
Okay, I got mine to finally work using the following syntax and using the following example from up above:
Previously:
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Working Version:
$user = Get-aduser -Filter "sAMAccountName -eq '$($SamAc)'"
I had to add $($ ) to $SamAc before PowerShell could access the variable string value.

How to query the Active Directory using a list of users in a text file for a specific attribute with PowerShell

I'm somewhat basic to Powershell and use one-liner commands only to keep it short and basic.
I would like to do the following: I have a list of users in a text file in the form of UserPrincipalName. I'd like to query this list of users if their accounts are still active/enabled or not. To do so, I'm trying to run the following command, which just reveals nothing in the end (blank output):
gc .\users.txt | foreach {get-aduser -server "corp.xxx.com"
-f 'name -like "$_"' -properties *}| select displayname,enabled
As mentioned, the output is blank with no errors or whatsoever.
I read that aduser doesn't work with pipelines, but I need to find a solution.
Kindly request your support :)
Thanks
Your use of single quotes in your filter is not allowing the expansion of the variable. Double-quotes should be wrapping the filter expression so as to allow the interpolation of the automatic variable $_:
Get-ADUser -Filter "name -like '$_'" ...
Single-quoted strings:
A string enclosed in single quotation marks is a verbatim string. The string is passed to the command exactly as you type it. No substitution is performed.
Also note, you mention in your question that the file has the user's UserPrincipalName attribute, yet you're querying the Name attribute, if that's the case, the filter should be:
Get-ADUser -Filter "UserPrincipalName -eq '$_'" ...
Note the use of -eq instead of -like, for exact matches you should always use this operator, see about_ActiveDirectory_Filter for usage details and examples of each operator.
If you're only interested in DisplayName and Enabled for your output, there is no reason in querying all the user's attributes, -Properties * should be just -Properties DisplayName since Enabled is already part of the default attributes returned by Get-ADUser.
Finally, the -Identity parameter can be bound from pipeline, and this parameter accepts a UserPrincipalName as argument, hence ForEach-Object is not needed in this case:
Get-Content .\users.txt |
Get-ADUser -server "corp.xxx.com" -Properties DisplayName |
Select-Object DisplayName, Enabled

Filtering Get-ADGroups with question mark wildcard doesn't seem to work

I'm trying to get a list of AD groups that have a name that starts with "Users-####-" (# is a number 0-9).
I've tried using Get-ADGroup -Filter {name -like "Users-[0-9][0-9][0-9][0-9]-*"} and Get-ADGroup -Filter {name -like "Users-????-*"}, but got no results.
I can of course use Get-ADGroup -Filter {name -like "Users-*"}, but this will also include all the groups that have something else than four characters after Users-.
I then decided to try using Where-Object and the this code returned the expected groups
Get-ADGroup -Filter * | Where-Object {$_.Name -like "Users-[0-9][0-9][0-9][0-9]-*"}
According to Microsoft documentation about wildcards, both ways I tried should work, but they actually don't.
Anybody have an idea what I'm doing wrong or is this just a bug in how ADGroup filtering works?
According to Microsoft documentation about wildcards, both ways I tried should work, but they actually don't.
That's a reasonable assumption, but the -Filter parameter exposed by some cmdlets in the ActiveDirectory module is a deceptive construct - it's designed to look like PowerShell's native operator syntax, but "underneath the hood" the cmdlet translates the filter expression to a valid LDAP query filter:
name -like "Users-*"
# is translated to
(name=Users-*)
$_.Name -like "Users-[0-9][0-9][0-9][0-9]-*"
# is translated to
(Name=Users-[0-9][0-9][0-9][0-9]-*)
Since LDAP doesn't recognize the wildcard range construct [0-9], it ends up querying the directory store for objects where the name literally starts with Users-[0-9][0-9][0-9][0-9]- - same goes for ?.
Since * is the only wildcard accepted by LDAP, the closest you can get is:
Get-ADGroup -Filter {name -like "Users-*-*"}
And then filter the results further on the client with Where-Object (in which case we're back to PowerShell performing the comparison and we can use all the wildcards again):
Get-ADGroup -Filter {name -like "Users-*-*"} | Where-Object Name -like 'Users-[0-9][0-9][0-9][0-9]-*'
As stated in about_ActiveDirectory_Filter:
Note: PowerShell wildcards, other than "*", such as "?" are not
supported by the -Filter parameter syntax.
In this case, you can combine -LDAPFilter with Where-Object to keep your query compatible and efficient:
Get-ADGroup -LDAPFilter "(name=Users-*-*)" | Where-Object {
$_.Name -like "Users-[0-9][0-9][0-9][0-9]-*"
}
You can use -Filter in this case as pre-filter, so at least you will get only groups with names starting with Users-.
Then in a further Where-Object clause you can specify further and in this case I would use regex -match there like:
Get-ADGroup -Filter "Name -like 'Users-*'" | Where-Object { $_.Name -match '^Users-\d{4}-.*' }
P.S. -Filter should be a string, not a scriptblock
The filters in the Powershell Active Directory module have odd behaviors.
Filter or Where Clause
There are two ways to restrict the output of an AD cmdlet like
Get-ADUser. First, you can use the -LDAPFilter or -Filter parameters
to filter the output. Second, you can pipe the results to the
Where-Object cmdlet. Where possible, the first method is more
efficient for two reasons.
Filtering is done on the domain controller instead of the local
client. The domain controller is more likely to be a server class
computer optimized for queries. Filtering results in a smaller
resultset sent over the network from the domain controller to the
client. In contrast, the Where-Object cmdlet only filters on the local
client after the resultset has been sent from the remote computer. For
example, you could retrieve all users with a department that starts
with "IT" using the Where-Object cmdlet as follows:
Get-ADUser -Filter * -Properties department | Where-Object {$_.department -Like "it*"} | Select sAMAccountName, department The
resultset from the Get-ADUser statement includes all users in the
domain. A more efficient method to get the same results would use a
filter, similar to below:
Get-ADUser -Filter {department -Like "it*"} -Properties department | Select sAMAccountName, department Now only the users needed are
included in the resultset from Get-ADUser. In a test domain with 2,150
users (7 of which have "IT" departments) the first command above took
4 times as long as the second (average of 10 trials each with 16
minutes between trials). The difference could be substantial in a
domain with ten's of thousands of users.
Also, note that the statements above use the -Properties parameter to
specify only the properties needed. The default properties exposed by
the cmdlet are always included, like sAMAccountName in this case. If
you request all properties, with -Properties *, the resultset will
include many properties for each user. The resultset will be much
smaller if you only specify the extended properties needed, like
department in this case. Repeating the last command above in the test
domain with 2,150 users, but requesting all properties (with
-Properties *) required 75% more time on average to complete. The default and extended properties exposed by the Get-ADUser cmdlet are
documented in Active Directory: Get-ADUser Default and Extended
Properties.
PowerShell Filter Syntax
The PowerShell Active Directory module cmdlets support an extended
form of the PowerShell Expression Language. PowerShell documentation
indicates that PowerShell syntax filters should be enclosed in braces.
But there are many examples where single quotes or double quotes are
used instead. As you might expect, this affects how the filter is
interpreted.
Using String Attributes The following table shows some example
PowerShell syntax filters using string properties, like Department.
Some filters result in error, others do not raise an error but never
produce results. The variable $Dept is defined as previously.
Filter Result
-Filter {department -eq "IT Department"} Works
-Filter {department -eq $Dept} Works
-Filter {department -eq "$Dept"} No Results
-Filter {department -eq '$Dept'} No Results
-Filter "department -eq $Dept" Error
-Filter 'department -eq $Dept' Works
-Filter {department -eq "it*"} No Results
-Filter {department -Like "it*"} Works
-Filter "department -Like ""it*""" Works
-Filter "department -Like 'it*'" Works
-Filter 'department -Like "it*"' Works
-Filter 'department -Like ''it*''' Works
-Filter {department -ge "IT"} Works
Some of these results may not be expected.
For example, you might expect enclosing a variable in a quoted string
to work. The best policy might be to always enclose PowerShell syntax
filters in braces, and to refrain from quoting variables.
The last example using the "-ge" operator is only useful in rare
situations. The filter will result in any departments that are
lexicographically greater than or equal to "IT". For example, it will
return "Test Department", because "T" is greater than "I".

Why doesn't $PSItem behave as expected when using a bracket-based -Filter argument?

I was assisting a user with this question, linked to my answer here: Powershell script to add users to A/D group from .csv using email address only?
Initially I wrote the script as follows, using a bracket-based filter for Get-AdUser like follows:
Import-CSV "C:\users\Balbahagw\desktop\test1.csv" |
Foreach-Object {
# Here, $_.EmailAddress refused to resolve
$aduser = Get-ADUser -Filter { EmailAddress -eq $_.EmailAddress }
if( $aduser ) {
Write-Output "Adding user $($aduser.SamAccountName) to groupname"
Add-ADGroupMember -Identity groupname -Members $aduser
} else {
Write-Warning "Could not find user in AD with email address $($_.EmailAddress)"
}
}
However, $_.EmailAddress failed to populate a value. However, changing the Get-ADUser filter to a string-based filter worked as intended:
$aduser = Get-ADUser -Filter "EmailAddress -eq '$($_.EmailAddress)'"
What is the strangeness I'm experiencing, and why? Is it because when I'm using brackets, it's treated as a new scope and the $PSItem won't follow?
-Filter parameters are generally string parameters (verify with
Get-Help Get-AdUser -Parameter Filter)
They generally do not accept PowerShell code - filters are provider-specific and often have their own syntax, although it happens to be PowerShell-like in the case of the AD cmdlets.
Also, they generally have no knowledge of PowerShell variables (see below).
Thus, when a script block ({ ... }) is passed, it is converted to a string, which evaluates to its literal contents (everything between the opening { and the closing }):
{ EmailAddress -eq $_.EmailAddress }.ToString() yields the literal string EmailAddress -eq $_.EmailAddress - without any evaluation - and that's what Get-AdUser sees - no evaluation takes place.
In a presumably well-meaning but misguided effort to support the widespread, but ill-advised practice of passing script blocks to the -Filter parameter of AD cmdlets, it seems that these cmdlets actually explicitly expand simple variable references such as $_ in the string literal they receive, but that doesn't work with expressions, such as accessing a property of a variable ($_.EmailAddress)
Therefore, -Filter arguments should generally be passed as expandable strings ("..."); in the case at hand:
-Filter "EmailAddress -eq '$($_.EmailAddress)'"
That is, the only robust solution is to use strings with the variable parts baked in, up front, via string expansion, as shown above.
For values that are neither numbers nor strings, such as dates, you may have to use a literal string ('...') and rely on the AD provider's ability to evaluate simple references to PowerShell variables (e.g., $date) - see this answer of mine for details.
As stated, the syntax of AD filters is only PowerShell-like: it supports only a subset of the operators that PowerShell supports and those that are supported differ subtly in behavior - see Get-Help about_ActiveDirectory_Filter.
It is tempting to use script blocks, because the code inside requires no escaping of embedded quotes / no alternating of quote chars and no use of subexpression operator $(...). However, aside from using script blocks as strings being inefficient in general, the problem here is that the script block is making a promise that it cannot keep: it looks like you're passing a piece of PowerShell code, but you're not - and it works only in simple cases (and then only due to the misguided accommodation mentioned above); generally, it's hard to remember under what circumstances it doesn't work and how to make it work if it fails.
It is therefore really unfortunate that the official documentation uses script blocks in its examples.
For a more comprehensive discussion, see this answer of mine.
You're not wrong, it's the module's fault
The type of payload you have to use with the -Filter parameter differs depending on which provider you're working with, a design decision which can be pretty confusing!
The output of Get-Help Get-ADUser -Parameter Filter gives you some pretty detailed examples of the different syntax options you can use with the Active Directory Provider's implementation of Filter syntax.
Here's an example:
#To get all user objects that have an e-mail message attribute, use one of the following commands:
Get-ADUser -Filter {EmailAddress -like "*"}
It looks like the ActiveDirectory provider places the specific restriction that you must wrap the input in quotes. Here's what happens when I look for my account without putting quotes around my e-mail.
Get-ADUser -Filter {EmailAddress -eq stephen#foxdeploy.com}
Get-ADUser : Error parsing query: 'EmailAddress -eq stephen#foxdeploy.com'
Error Message: 'syntax error' at position: '18'.
But adding quotes? It works!
Get-ADUser -Filter {EmailAddress -eq "stephen#foxdeploy.com"}
DistinguishedName : CN=Stephen,CN=Users,DC=FoxDeploy,DC=local
Enabled : True
GivenName : Stephen
Name : Stephen
ObjectClass : user
ObjectGUID : 6428ac3f-8d17-45d6-b615-9965acd9675b
SamAccountName : Stephen
SID : S-1-5-21-3818945699-900446794-3716848007-1103
Surname :
UserPrincipalName : Stephen#FoxDeploy.local
How to make yours work
Now, because of this confusing filter implementation, you will need to change your user lookup on line 5 to the following:
$aduser = Get-ADUser -Filter "EmailAddress -eq `"$($_.EmailAddress)`""
We are providing the -Filter payload as a String. Next we want to use String Expansion to pull out the .EmailAddress property, so we wrap the string in $( ) to signal string expansion. Finally, the provider wants our filter comparison wrapped in quotes, so we put double quotes around it, and then escape the quotes using the backtick character.
And now it should work.
TLDR - blame the provider and blame the module, there are so many inconsistencies with the Active Directory module.

Get-Aduser -Filter will not accept a variable

I'd like to check if a user account already exists in the system.
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter {sAMAccountName -eq "$SamAc"}
I'm not sure why, but $User will always return null even if {sAMAccountName -eq "$SamAc"} is supposed to be true.
What am I missing here?
Edit:
This is what was missing:
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Editor's note: The script block ({ ... }) was replaced with a string.
There is valuable information in the existing answers, but I think a more focused summary is helpful. Note that the original form of this answer advocated strict avoidance of script blocks ({...}) and AD-provider variable evaluation, but this has been replaced with more nuanced recommendations.
Option A: Letting the AD provider resolve - stand-alone only - variable references:
Get-ADUser -Filter 'sAMAccountName -eq $SamAc' # note the '...' quoting
Note the use of '...', i.e. a verbatim (single-quoted) string, because the string's value is to be passed as-is to the AD provider (cmdlet).
While use of a script block ({ ... }), Get-ADUser -Filter { sAMAccountName -eq $SamAc }, technically works too (its verbatim content, sans { and }, is converted to a string), it is conceptually problematic - see bottom section.
Do not quote the variable reference ("$SamAc").
Use only stand-alone variable references (e.g, $SamAc); expressions are not supported (e.g., $user.SamAccountName or "$name*" or $("admin_" + $SamAc)); if necessary, use an intermediate, auxiliary variable; e.g.:
$name = "admin_" + $SamAc; Get-ADUser -Filter 'sAMAccountName -eq $name'
Generally, only a subset of PowerShell's operators are supported, and even those that are do not always behave the same way - see bottom section.
Caveat: If you use Get-ADUser via an implicitly remoting module - whether self-created via Import-PSSession or, in PowerShell v7+, via the Windows Compatibility feature - neither '...' nor { ... } works, because the variable references are then evaluated on the remote machine, looking for the variables there (in vain); if (Get-Command Get-ADUser).CommandType returns Function, you're using an implicitly remoting module.
If implicit remoting is involved, you MUST use string interpolation, as shown next.
Option B: Using PowerShell's string interpolation (expandable strings), up front:
Get-ADUser -Filter "sAMAccountName -eq `"$SamAc`"" # note the "..." quoting
Using "...", i.e. an expandable (double-quoted) string makes PowerShell interpolate (expand) all variable references and subexpression up front, in which case the AD provider sees only the (variable-free) result.
As shown above, for string operands embedded quoting then is necessary.
For embedded quoting, '...' is a simpler alternative to `"...`" (`" is an _escaped "), but note that this assumes that an expanded value doesn't itself contain ', which is a distinct possibility with last names, for instance.
Also, be sure to `-escape constants such as $true, $false, and $null inside the "..." string, which are always recognized by the AD provider; i.e., use `$true, `$false and `$null, so that PowerShell doesn't expand them up front.
Caveat: Using an expandable string does not work with all data types, at least not directly: for instance, the default stringification of a [datetime] instance (e.g., 01/15/2018 16:00:00 is not recognized by the AD provider; in this case, embedding the result of a call to the instance's .ToFileTime() (or .ToFileTimeUtc()?) method into the string may be necessary (as suggested in the comments on this post); I'm unclear on whether there are other data types that require similar workarounds.
On the plus side, string interpolation allows you to embed entire expressions and even commands in a "..." string, using $(...), the subexpression operator; e.g.:
# Property access.
Get-ADUser -Filter "sAMAccountName -eq `"$($user.SamAccountName)`""
# String concatenation
Get-ADUser -Filter "sAMAccountName -eq `"$('admin_' + $SamAc)`""
Background
Any argument you pass to -Filter is coerced to a string first, before it is passed to the Get-ADUser cmdlet, because the -Filter parameter is of type [string] - as it is for all provider cmdlets that support this parameter; verify with Get-ADUser -?
With -Filter in general, it is up to the cmdlet (the underlying PowerShell provider) to interpret that string, using a domain-specific (query) language that often has little in common with PowerShell.
In the case of Get-ADUser, that domain-specific language (query language) is documented in Get-Help about_ActiveDirectory_Filter.
Note: As of this writing, no newer version of this legacy topic exists; this GitHub issue requests one.
With Get-AdUser, the language supported by -Filter is certainly modeled on PowerShell, but it has many limitations and some behavioral differences that one must be aware of, notably:
As Santiago Squarzon points out, these limitations and difference stem from the fact that the language is translated into an LDAP filter behind the scenes, it is therefore constrained by its features and behaviors. (Note that you can use the -LDAPFilter parameter in lieu of -Filter to directly pass an LDAP filter).
Only a limited subset of PowerShell operators are supported, and some exhibit different behavior; here's a non-exhaustive list:
-like / -notlike only support * in wildcard expressions (not also ? and character sets/ranges ([...])
'*' by itself represents any nonempty value (unlike in PowerShell's wildcard expressions, where it also matches an empty one).
Instead of -eq "" or -eq $null to test fields for being empty, use
-notlike '*'.
Certain AD fields, e.g., DistinguishedName, only support '*' by itself, not as part of a larger pattern; that is, they only support an emptiness test.
There is no support for regex matching.
-lt / -le and -gt / -ge only perform lexical comparison.
Referencing a nonexistent / misspelled property name causes the Get-ADUser command to quietly return $null.
As stated, only stand-alone variable references are supported (e.g, $SamAc), not also expressions (e.g., $SamAc.Name or $("admin_" + $SamAc))
While you can use a script block ({ ... }) to pass what becomes a string to -Filter, and while this syntax can be convenient for embedding quotes, it is problematic for two reasons:
It may mislead you to think that you're passing a piece of PowerShell code; notably, you may be tempted to use unsupported operators and expressions rather than simple variable references.
It creates unnecessary work (though that is unlikely to matter in practice), because you're forcing PowerShell to parse the filter as PowerShell code first, only to have the result converted back to a string when the argument is bound to -Filter.
This one bit me when I first started to work with the ActiveDirectory module, and it was a pain to figure out.
The -Filter parameter for the ActiveDirectory module cmdlets is actually looking for a string. When you do {sAMAccountName -eq "$SamAc"} as the value, it is actually looking for "sAMAccountName -eq ""`$SamAc"""
Basically, Powershell parses the parameter and turns its value into a string, and will not interpolate the variable. Try building the string before hand, and it should work.
Something like this:
$SamAc = Read-Host 'What is your username?'
$filter = "sAmAccountname -eq ""$SamAc"""
$User = Get-ADUser -Filter $filter
I have to comment on this because it really aggravated me to sort this out.
Joseph Alcorn has the right idea. The filter parameter takes a string and then evaluates that in order to process the filter. What trips people up with this is that you are given the option to use curly brackets instead {}, and this doesn't work as you'd expect if you were using Where... it still has to be treated like a string.
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
I recommend sticking to quotes to make it more clear/readable for yourself and others and to avoid potential syntax errors, or stick to Where{} in the pipeline. When doing so, I find it best to use double-quotes on the outside & single-quotes on the inside so you still get intellisense detection on the variable.
Simply remove the quotes around your variable:
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter {sAMAccountName -eq $SamAc}
This should work just fine.
if (($ADUser = Get-ADUser -filter "SamAccountName -eq '$(Read-Host Username)'") -ne $null) {$ADUser.SamAccountName} else {"Not Found"}
Little addendum if anyone like me got here and was still tearing their hair out:
-properties *
Would be quite a common this to have in this query. Doesn't work, I'm sure someone smarter than me can figure it out
-properties mail,cn,wtf
etc does work as expected
It took me quite a bit to just use
Do not quote the variable reference ("$SamAc").
TXH so much
Okay, I got mine to finally work using the following syntax and using the following example from up above:
Previously:
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Working Version:
$user = Get-aduser -Filter "sAMAccountName -eq '$($SamAc)'"
I had to add $($ ) to $SamAc before PowerShell could access the variable string value.