7

I'm new to powershell and have to fetch users from AD based on a list with names. Is there any way to filter from AD using something similar to an in-statement in SQL? (select * from users where name in ('Joe','Bill)?

As for now I fetch users in a foreach loop and add them to an arraylist, but I don't know if this is good practice:

function GetUsers()
{
$dummydata = @('Bill','Joe','Sam')
$users = New-Object System.Collections.ArrayList($null)

foreach($user in $dummydata)
{
 $aduser = get-aduser -f {GivenName -eq $user} -Properties * | select *
  $users.add($aduser) | Out-Null
}

Return ,$users

}
Shay Levy
  • 121,444
  • 32
  • 184
  • 206
Thomas B
  • 301
  • 2
  • 6
  • 12
  • As an aside: It's best to [avoid the use of script blocks (`{ ... }`) as `-Filter` arguments](https://stackoverflow.com/a/44184818/45375). – mklement0 Nov 07 '18 at 20:30

3 Answers3

5

You'd probably want to put this into a function:

$dummydata = @('Bill','Joe','Sam')

$filter = 
[scriptblock]::create(($dummydata| foreach {"(GivenName -eq '$_')"}) -join ' -or ')
Get-ADUser -f $filter
mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • 1
    I've never seen the foreach be used inside a filter, usually I use it to run a get-aduser for each user. Could you explain how this works? Not sure what the -join and -or are actually doing. – Jessie Jan 18 '18 at 22:15
  • @Jessie: The `foreach[-object]` is merely used to construct an array of transformed strings from the array of input strings (embedding them in a simple filter expression each), and `-join` then joins the simple filters with `-or` to form a compound expression. The resulting single string is passed to `[scriptblock]::Create()`. – mklement0 Nov 07 '18 at 20:47
5

mjolinor's answer is elegant and works, but the use of script blocks is problematic for two reasons:

  • It is unnecessary, because the script block will invariably be converted back to a string when it is passed to Get-ADUser -Filter.

  • More importantly, it perpetuates the widespread misconception that Get-ADUser -Filter accepts PowerShell script blocks that support PowerShell syntax, which is not true; it is a misconception that leads to frustration sooner or later; in short: construct your -Filter arguments as strings to begin with, and know that these filter strings, while resembling PowerShell syntax, use AD-provider-specific syntax, which is not only much more limited, but behaves subtly differently even with operators of the same name as in PowerShell - see this answer for the full story.

Therefore, use string manipulation to construct your filter:

Get-AdUser -Filter ('Bill', 'Joe', 'Sam' -replace 
                      '^.*', 'GivenName -eq "$&"' -join ' -or ')

For information on the regex-based -replace operator, see this answer.

The -Filter argument evaluates to the following string literal, which is what the AD provider ultimately sees:

GivenName -eq "Bill" -or GivenName -eq "Joe" -or GivenName -eq "Sam"
mklement0
  • 382,024
  • 64
  • 607
  • 775
0

while I agree with mklement0 in spirit, scriptblocks have the following two advantages over single quoted strings.

  1. The value can have single quotes (as in D'Sean) or even double quotes without you escaping the quotes.
  2. syntax highlighting.
user242114
  • 29
  • 3