Reputation: 23
I need to filter out only the AD groups from the Net User command in powershell. All the AD groups begin with an * so i would like to filter out the string by displaying everything that's preceeded by an *
I get an error since '*' is a special character and cannot be used. How do i get powershell to ignore it as a special character?
I cannot use any other commands to get AD groups, so Get-AD is not an option. i only have Net user to work with.
My base script,
Net User USER /domain | Select-String '*'
I cannot use any other script than Net user to accomplish this task, even though Get-AD would be simpler, i do not have the option.
Upvotes: 1
Views: 254
Reputation: 437953
Santiago's helpful answer shows a more robust, OO solution that is much more in the spirit of PowerShell.
To answer your question as asked:
Select-String
by default interprets its (positionally implied) -Pattern
argument as a regex (regular expression), where *
is a metacharacter.
While \
-escaping regex metacharacters is possible (and is necessary in the event that you need more sophisticated matching that requires a regex), the direct solution is to add the -SimpleMatch
switch, which causes the -Pattern
argument to be interpreted as a literal (verbatim) string:
net user $someuser /domain | Select-String * -SimpleMatch
Also note that what Select-String
outputs by default aren't just the matching input lines as-is, but Microsoft.PowerShell.Commands.MatchInfo
objects that provide metadata for each match, with the matching line text stored in the .Line
property.
While that distinction doesn't matter much for displaying results, it may for programmatic processing, so if you only want to output the text of the matching lines, add -Raw
in PowerShell (Core) 7+, or pipe to | ForEach-Object Line
in Windows PowerShell.
The above will show those net user
output lines that contain a literal *
, and therefore all group memberships, which is good enough for the human observer.
You indeed need regex matching and operations if you want to extract the group names individually, for later programmatic processing:
# Use an ordered hashtable to collect the group names in,
# with keys 'Local' and 'Global', targeting the *current* user in this example.
$groupMemberships = [ordered] @{}
(((net user $env:USERNAME) -join "`n") -split "`n`n")[-1] -split '\n' -match ' \*' |
ForEach-Object {
$tokens = $_ -split ' \*'
if ($tokens[0] -notmatch '^ ') {
$key = if ($groupMemberships.Count -eq 0) { 'Local' } else { 'Global' }
}
$groupMemberships[$key] += @($tokens[1..($tokens.Count-1)].Trim())
}
$groupMemberships # display result.
Sample output:
Name Value
---- -----
Local { Administrators }
Global { Department1, Region1 }
That is $groupMemberships.Local
$groupMemberships.Global
then contains the name(s) of the local / global (AD) groups the user is a member of, respectively, as an array.
Note:
The solution above is complex, because it tries to be as robust as possible.
Notably, it is possible - albeit not likely in practice - that output lines that are unrelated to group names contain *
as well, notably the Comment
and User's comment
fields.
Therefore, only the last paragraph of net user
's output is considered, which is known to contain the group names - note that matching lines by field-name parts such as Local
and Global
is explicitly avoided, as the field names are localized based on your system's display language.
The last paragraph is known to list the local group memberships first, followed by the global (AD) ones. Each line in the last paragraph can contain multiple (*
-prefixed) group names and there can be overflow lines for additional groups that don't fit on the first line for the given scope. Such overflow flow lines can be detected by starting with whitespace.
Upvotes: 1
Reputation: 13631
You can use a backslash to escape regex special characters and use ^
to specify start of string:
> @("a", "*b", "c*", "*d", "e**") | Select-String -Pattern '^\*'
*b
*d
So, to display the groups you could use, for example:
Net User USER /domain | % { $_ -split "\s+" -match "^\*" }
As per the comment, if the group names may contain spaces then obviously splitting on space characters would be inappropiate.
An alternative:
Net User USER /domain | % { $_ -split '^[^*]+\*?' -match '.+' }
Or, if we only want to look at the lines beginning "Local Group Memberships" or "Global Group Memberships" we could use, for example:
Net User USER /domain |
? { $_ -match '^(?:Local|Global) Group Memberships +\*(.+)' } | % { $matches[1] }
Upvotes: -1
Reputation: 60045
Instead of trying to parse the output from net user USER /domain
I would use what's already available in powershell. You can get the current logged on user's Active Directory Group Membership using adsi
and adsisearcher
.
Here are 2 different ways of accomplishing it.
memberof
attribute:$searcher = [adsisearcher]::new(
[adsi] "LDAP://$env:USERDNSDOMAIN",
[string] "(cn=$env:USERNAME)",
[string[]] ("memberOf", "cn")
)
$searcher.FindOne().Properties['memberof'] | ForEach-Object {
$searcher.Filter = "(distinguishedName=$_)"
$searcher.FindOne().Properties['cn'][0]
}
member
:$searcher = [adsisearcher]::new(
[adsi] "LDAP://$env:USERDNSDOMAIN",
[string] "(cn=$env:USERNAME)",
[string[]] ("distinguishedName", "cn")
)
$userDn = $searcher.FindOne().Properties['distinguishedName'][0]
$searcher.Filter = "(&(objectCategory=group)(member=$userDn))"
$searcher.FindAll() | ForEach-Object {
$_.Properties['cn'][0]
}
Upvotes: 1