Get-ADUser -Filter "SamAccountName -like

I would like to find Active Directory User Accounts so that when I input something like
Joe Jones,
there will be a match on User Accounts where the SamAccountName looks something like this:
AA.Joe.Jones
AA.joe.ones
aa.Joe.Jones
xx.Joe.Jones
XX.Joe.Jones

So from the Gui Input, Joe Jones,
$NewFirst = joe
$NewLast = jones

And
SamAccountName (of the AD Record) = AA.Joe.Jones

this match works:

$GoodSam = Get-ADUser -Filter "SamAccountName -like '*$NewLast*' -and SamAccountName -like '*$NewFirst*'" -prop $Properties   | 
 Where-Object { $_.SamAccountName -match "^[A-Za-z]{2}(\.[A-Za-z]*){0,1}\.$NewFirst\.$NewLast$" } | 
 Select-Object $Properties  

But it takes several seconds to run.
I want something to execute like lightning.

So I am trying this:

$GoodSam = Get-ADUser -Filter "SamAccountName -like '[A-Za-z][A-Za-z].*$NewFirst*.$NewLast' "  -Properties $properties | Select-Object $properties 

But there is no match found.

And since I know the pattern works by testing this:

 # Define the NewFirst and NewLast values
$NewFirst = "Joe"
$NewLast = "Jones"

# Example SamAccountNames to test
$SamAccountNames = @(
    "io.joe.jones",
    "ab.joe.jones",
    "xy.joe.jones",
    "joe.jones",
    "jones.joe",
    "jjones",
    "joe.smith",
    "joe.jones"
)

# Test each SamAccountName
foreach ($SamAccountName in $SamAccountNames) {
    if ($SamAccountName -like "[A-Za-z][A-Za-z].*$NewFirst*.$NewLast") {
        Write-Host "Match found for SamAccountName: $SamAccountName"
    } else {
        Write-Host "No match for SamAccountName: $SamAccountName"
    }
} 

I do not know why this does not find a match:

$GoodSam = Get-ADUser -Filter "SamAccountName -like '[A-Za-z][A-Za-z].*$NewFirst*.$NewLast' "  -Properties $properties | Select-Object $properties 

Thank you in advance for your help on this.

Hmmm … what’s in $Properties? … and you should use a -SearchBase to limit your query to a specific OU. This might speed up your query already.

Why do you use the sAMAccountName to search for first name and last name? I’d use the properties GivenName and Surname for that purpose.

The -Filter parameter does not undestand complex regex. You may try an LDAP-filter with more complex patterns to get faster results.

Olaf, thank you for your reply.
There are many attributes in $Properties. SamAccountName, Name, SN, mail -and many others. I use all these to display on the console when there is a match.
$Properties is just a way to make it look nice and modular.

I must use SamAccountName to search for firstName and lastName… because for these records I am looking for, the other attributes are not reliable because there are no good standards for uniformity. The other attributes cannot be trusted.

I will try an LDAP-filter. Thank you for the reference.

The less you specify for the parameter -Properties the faster you get your results. :wink:
… and BTW: just to have it at least mentioned once - SamAccountName, Name and SurName will be returned by default. You don’t have to specify them explicitly.

And again … using a -SearchBase could speed up your query as well.

So just because I’m curious - you use the full first name and the full last name for your sAMAccountNames but you do not fill in the attributes GivenName and Surname? May I ask why?

Olaf, thank you for your reply,
I use all these attributes in $Properties for many other Get-AdUser examples and they all run as fast as lightning in other applications. But for this application, The only one that works is the one I showed earlier; it slows down for as much as 10 or 15 seconds.

And I must search in all the OU’s. Searching in all the OU’s does not seem like a problem in the other Get-AdUser examples.

I am glad to explain for your curiosity; In this application for users’ records that are preceded by two alpha characters followed by a period, I must look at the SamAccountName because it is the only attribute that can be counted on to also have the firstName and LastName. These are special records, indeed. And in my workplace, these are user accounts that have Administrative privliges.

So the idea is: Let’s look to see if Joe Jones or Mary Smith has an Administrative Account! And if they do, what is it ? and what are the two alpha characters that precede their name? The two alpha characters are various and are coded to mean what OU they are in and other things as well.

And I am not having any luck with an LDAP filter. I tried this:

# Construct the LDAP filter
$LDAPFilter = "(&(objectCategory=person)(objectClass=user)(SamAccountName=[A-Za-z][A-Za-z].*$NewFirst*.$NewLast))" 

 $GoodSam = Get-ADUser -LDAPFilter $LDAPFilter  -Properties $properties | Select-Object $properties  

I also tried this:

$GoodSam = Get-ADUser -LDAPFilter "SamAccountName -like '[A-Za-z][A-Za-z].*$NewFirst*.$NewLast'" -Properties $properties | Select-Object $properties  

There were no errors, but it did not find the record that I know is there.
That was a very hasty try. I must study LDAP filters more.

It is just after 3:00 P.M. here in central United States; my quitting time for the day.

I’m far away from understanding LDAP filters but I’m afraid they don’t work with regex syntax as well. But shouldn’t that return some meaningful results?

$LDAPFilter = '(&(objectCategory=person)(objectClass=user)(SamAccountName=*.*{0}*.{1}))' -f $NewFirst, $NewLast

Another idea could be to query all possible users in advance, save them in a variable and run queries with advanced filter patterns against this variable.

3 Likes

Olaf, thank you for your reply. Yes, that works, but there is still a big 5 second delay, Ha!

I am studying your pattern. It does not stipulate preceding alpha characters. But after careful consideration, I will adapt your version because they may start using numbers too!

I thought the Where-Object part of my original pattern was slowing it down. But your pattern does not use Where-Object, and there is still a big pause.

So I guess it takes a long time, (5 seconds), to run the pattern through all the AD User Accounts.

But then, on this query below there is no time lag, so I wish I knew why there is no time lag on this one:

$GoodSam = Get-Aduser -Filter "(Surname -like '$InputUser*')" -Prop $Properties   | Where-Object { ($_.Surname -or ($_.SamAccountName) -match "^$([regex]::Escape($InputUser))(?:\d.*$)")}  | Select-Object $Properties

And why there is a big (5 second), time lag on yours:

$LDAPFilter = '(&(objectCategory=person)(objectClass=user)(SamAccountName=*.*{0}*.{1}))' -f $NewFirst, $NewLast 

$GoodSam = Get-ADUser -LDAPFilter $LDAPFilter  -Properties $properties | Select-Object $properties  

I’m coming in late here, but one other option that might be worth exploring if speed is an absolute must would be the .NET ADSI Searcher:

$Domain = "contoso.local"
$SearchBase = "DC=contoso,DC=local"
$Searcher = [adsisearcher]::new([adsi]"LDAP://$Domain/$SearchBase", "(objectCategory=user)")

[void]$Searcher.PropertiesToLoad.Add("SAMAccountName")
[void]$Searcher.PropertiesToLoad.Add("city")
[void]$Searcher.PropertiesToLoad.Add("department")
[void]$Searcher.PropertiesToLoad.Add("description")
[void]$Searcher.PropertiesToLoad.Add("displayname")
[void]$Searcher.PropertiesToLoad.Add("employeetype")
[void]$Searcher.PropertiesToLoad.Add("extensionAttribute6")
[void]$Searcher.PropertiesToLoad.Add("extensionAttribute7")
[void]$Searcher.PropertiesToLoad.Add("extensionAttribute8")
[void]$Searcher.PropertiesToLoad.Add("extensionAttribute9")

$Searcher.PageSize = 1000
$Searcher.Filter = '(SamAccountName=*.*{0}*.{1})' -f $NewFirst, $NewLast
$Searcher.FindAll()

This is just example text. The final method invocation of FindAll will just spit out objects. You could then pipe those to Foreach-Object or Select-Object or something.
You can also very quickly get all of the users in the domain using ADSI searcher, then filter through those results in memory if you’re going to be doing a lot of searches.

Nice, but why not

$Domain = "contoso.local"
$SearchBase = "DC=contoso,DC=local"
$Searcher = [adsisearcher]::new([adsi]"LDAP://$Domain/$SearchBase", "(objectCategory=user)")

$Properties = "SAMAccountName", "city", "department", "description", "displayname", "employeetype", "extensionAttribute6", "extensionAttribute7", "extensionAttribute8", "extensionAttribute9"

[void]$Searcher.PropertiesToLoad.AddRange($Properties)

$Searcher.PageSize = 1000
$Searcher.Filter = '(SamAccountName=*.*{0}*.{1})' -f $NewFirst, $NewLast
$Searcher.FindAll()
1 Like

“why not” indeed. That was my first time ever using ADSISearcher and I just made a slight improvement on found-code from an internet search. I appreciate the extra tuning.

2 Likes

KrzyDoug and GreyOut, thank you for your input, I will study this. I am not familiar with ADSISearcher. I will see how fast it is and how it compares. Five or fifteen seconds is not much time, I know, but because this was my absolute slowest Get-AdUser, it does make me think that something is wrong. And I want to make sure I am using the best, fastest PowerShell Code…

!! … that does not have to be the same!!! :point_up:t3: :smirk: … the fastest code might not be the best. There are other qualities you may think of … for example reliability or error tolerance. :man_shrugging:t3: