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

Time:04-23

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?

CodePudding user response:

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]-*'

CodePudding user response:

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

CodePudding user response:

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]-*"
}

CodePudding user response:

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".

  • Related