Replacing a string with a variable in Get-ADGroup - powershell

I'm trying to use PowerShell to search AD for Group Names.
Why don't either of these work, the param or the Read-Host? Both are passing strings, but the results are empty. However, if I replace the variable $ADGroup in the command with an actual Group Name (a string) and run the command Get-ADGroup... results are provided as expected. I tried to replace the double quotes with single quotes and I get the same results, the command works alone but neither Read-Host or param provide information. I can't figure out why the string isn't being passed when it's a variable ($ADGroup). Thanks.
param(
[Parameter(Mandatory=$true)]
[string]$ADGroup
)
# One or the other param or Read-Host
$ADGroup = Read-Host "Enter Group Name"
PS \> Get-ADGroup -Filter {name -like "*$ADGroup*"} -Properties * | Select-Object -Property Name
Get-ADGroup -Filter {name -like '*GroupName*'} -Properties * | Select-Object -Property Name
Name
----
Results
Results
Results
Results
Results

This is one of the reasons why using a script block based filter (-Filter {...}) on the cmdlets of the ActiveDirectory Module is not recommended.
The -Filter on the Parameter section of the Get-* cmdlets from ActiveDirectory Module states the following:
-Filter
Specifies a query string that retrieves Active Directory objects. This string uses the PowerShell Expression Language syntax. The PowerShell Expression Language syntax provides rich type-conversion support for value types received by the Filter parameter. The syntax uses an in-order representation, which means that the operator is placed between the operand and the value.
Query String:
Get-ADGroup -Filter "name -like '*$ADGroup*'"
LDAP Query String:
Get-ADGroup -LDAPFilter "(name=*$ADGroup*)"
Recommended Documentations for efficient Filtering:
about_ActiveDirectory_Filter
Active Directory: LDAP Syntax Filters
Note: Worth mentioning, when querying Active Directory you will want to retrieve only the needed attributes from the AD Objects, specially when querying big Domains / Forests. Using -Properties * is a bad practice and also very inefficient, this will slow down your query as it is retrieving all available attributes of the objects being queried.

maybe it doesn't recognize it as a string or the filter is not correct.
param(
[Parameter(Mandatory=$true)]
[string]$ADGroup
)
#one or the other param or read-host
$ADGroup = Read-Host "enter group name"
$ADGroup = $ADGroup.ToString()
Get-ADGroup -Filter {name -like "*$ADGroup*"} -Properties * | select -Property Name
or this should do it..
$ADGroup = $ADGroup.ToString()
Get-ADGroup -Filter {name -like "*$ADGroup*"} -Properties * | Select-Object -expandProperty Name

Related

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

Filter result from Get-ADUser using sAMAccountname

I would like to extract a username from AD using Get-ADUser. The issue I'm having is when using sAMAaccount name as filter, I get multiple results if the value is found in multiple entries. To illustrate, if my samaccountname is 'a123b', and my coworker's is 'c1234d', I get both our names when I run this:
get-aduser -ldapFilter "(samaccountname=*123*)"| select Name
I would like to return only my information based on '123' and not '1234'
I've already tried the following as well to no avail:
get-aduser -Filter "samaccountname -like '*123*'" | select Name
You can narrow it down with a regular expression:
$filter = "[a-zA-Z]123[a-zA-Z]"
Get-ADUser -Filter "samaccountname -like '*123*'" | where { $_.samaccountname -match $filter} | select name
$filter is a simple regex pattern looking for 123 surrounded by letters (uppercase or lowercase)
-match is the operator that allows a regex comparison
When using a partial SamAccountName in a Filter or LDAPFilter, it is more than likely to get multiple results.
To test and return a specific user account, you need the filter to be more specific if possible (depends on what policies your environment uses for accountnames), like
Get-ADUser -Filter "SamAccountName -like 'a123*'" | Select-Object Name
or use an extra Where-Object clause to narrow down the results by some other user property like the firstname for instance:
Get-ADUser -Filter "SamAccountName -like '*123*'" | Where-Object { $_.GivenName -eq 'John' } | Select-Object Name
Mind you, the above examples can still return multiple user objects..
If you have it, the absolute sure way of retrieving a single user object is by using the DistinghuishedName of that user and get the object by using the -Identity parameter. See Get-ADUSer
P.S.:
When using the -like operator or an LDAPFilter, use wildcard characters on the parts of the name that can vary.
Since you can't use regex in the LDAP query, you could use a query like this to tell it to find user accounts that contain 123 but not with a fourth digit:
(&(objectClass=user)(samaccountname=*123*)(!samaccountname=*1231*)(!samaccountname=*1232*)(!samaccountname=*1233*)(!samaccountname=*1234*)(!samaccountname=*1235*)(!samaccountname=*1236*)(!samaccountname=*1237*)(!samaccountname=*1238*)(!samaccountname=*1239*)(!samaccountname=*1230*))
It's ugly, but it works.
Note that, if you have a filter that starts with a wildcard, the index for that attribute cannot be used, so it will have to look at every account to find a match. I added a filter for objectClass, since that is indexed and it will ensure it only looks at user objects.

Get-ADComputer to return a different property than queried?

I am using Get-ADComputer to search through my domain for a specific string in the Location property. However, when I find it, I want to return the Name property the string was found in.
My company is using Powershell version 5.1 if that makes a difference.
I've already tried piping Name after "select-string -Pattern 'example'" but it simply returns nothing, I assume it thinks I'm looking for the property within Location rather than the Get-ADComputer result. The answer will probably be someone telling me to store the whole Get-ADComputer as a variable, but I'm not sure what the data limit on Powershell variables are, and it seems I would be parsing through quite a lot of data.
Get-ADComputer -properties Location -SearchBase "OU=E, DC=M" -filter 'Name -like "*"' | select Location | select-string -pattern "example"
My current result is the entire Location property, but my desired result is the Name property while searching for the location. It would be even better if I could return both.
If you are looking for the string example within location, you can filter on location and then output the name.
Get-ADComputer -SearchBase "OU=E, DC=M" -Filter "location -like '*example*'" | Select-Object Name
If you are looking for the string example within Name, you can filter on Name and still output the name.
Get-ADComputer -SearchBase "OU=E, DC=M" -Filter "Name -like '*example*'" | Select-Object Name
If you want to output more properties including location and Name, you will need to add the -properties switch to handle location.
Get-ADComputer -Properties location -SearchBase "OU=E, DC=M" -Filter "Name -like '*example*'" | Select-Object Name,location
If you are looking to find string example within any property that outputs by default from the Get-ADComputer command, then you will need something like the following:
Get-ADComputer -Properties location -SearchBase "OU=E, DC=M" -Filter * | Where-Object { $_ | Out-String | Select-String -pattern "example"}
Explanation:
Select-Object will output a custom object with the properties that you have selected. The -Filter on the AD commands has limited operators available. If you are looking for a simple string, know what property contains the string, but don't know where the string exists within the string, use the -like operator. The * characters are for wildcards. -Filter is almost always faster than piping into something else, so you should use it if you can.
The Where-Object { $_ } processes the current object ($_) in the pipeline, which includes all of the properties piped into the command. If you only want to compare a single property, then $_ should become $_.propertyname.

get-adgroup -filter "SID -like '*-512'"

I have been wanting to figure out how to use -filter to get what I want. What I am trying to do is find the Domain Admins group by a -like statement of *-512 against the SID property using the following:
get-adgroup -filter "SID -like '*-512'"
It works if I put the actual SID
get-adgroup -filter "SID -eq 'S-1-5-21domain-512'"
I know doing it this way will work
get-adgroup -filter * | ? {$_.SID -like '*-512'}
https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems
As BenH comments, you cannot partially filter on SIDs in LDAP queries, because of the way SID values are stored in the directory. The SID string you see is an SDDL representation of an underlying byte array.
I assume your motivation for attempting wildcard matching against a well-known RID is that you don't know the domain SID in advance. You can easily obtain that with the Get-ADDomain cmdlet:
$DomainSID = (Get-ADDomain).DomainSID
$DomainAdminsSid = New-Object System.Security.Principal.SecurityIdentifier ([System.Security.Principal.WellKnownSidType]::AccountDomainAdminsSid,$DomainSID)
Get-ADGroup -Filter {SID -eq $DomainAdminsSid}