2

I'm trying to create a new Active Directory user, but first I verify that the user doesn't exist already with Get-ADUser. I import the user data from our HR department and build custom properties:

$newUsers = Import-Csv $csvFile |
            Select-Object -Property @{n='EmpNum';e={$_.'Employee Number'}},
                @{n='UPN';e={$_.'Email Address'}},
                @{n='Alias';e={$_.'Email Address'.Split("@")[0]}} #### etc

When I loop through the objects from the CSV file, I use the UPN property to search for the user in Active Directory:

foreach ($newUser in $newUsers) {
    $exists = Get-ADUser -Filter {UserPrincipalName -eq $newUser.UPN} -Properties * -Server $adServer -Credential $adCred 
    ...
}

The filter causes an error:

Get-ADUser : Property: 'UPN' not found in object of type:
'System.Management.Automation.PSCustomObject'. At
C:\Users\bphillips.NEWHOPEOFIN\Dropbox\Powershell\NewHire\AddNewDSP.ps1:50
char:15
+     $exists = Get-ADUser -Filter {UserPrincipalName -eq $newUser.UPN} -Propertie ...

I've tried doing this: -Filter {UserPrincipalName -eq $("$newUser.UPN") but that doesn't help; I get another error

Get-ADUser : Cannot process argument because the value of argument
"path" is not valid. Change the value of the "path" argument and run
the operation again. At
C:\Users\bphillips.NEWHOPEOFIN\Dropbox\Powershell\NewHire\AddNewDSP.ps1:50
char:15
+     $exists = Get-ADUser -Filter {UserPrincipalName -eq $("$newUser.UPN")} -Prop ...

$newUser is a string, so I don't understand why it causes a problem. Hard-coding a UserPrincipalName like, "test@ourcompany.com" works, but the $newUser.UPN won't work.**

PS C:\> $newUser.UPN.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

and

PS C:\> $newUser.UPN | gm

   TypeName: System.String

$newUser.UPN contains a valid string value

PS C:\> $newUser.UPN
ypope@ourcompany.net

What do I have to do to get $newUser.UPN to be recognized as a string for the filter parameter? What's going on that I don't understand?

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
user18349
  • 21
  • 1
  • 1
  • 3
  • Try Get-aduser * -Filter {UserPrincipalName -eq $newUser.UPN} -Properties * -Server $adServer -Credential $adCred – EBGreen Dec 01 '15 at 19:26
  • $exists = Get-aduser * -Filter {UserPrincipalName -eq $newUser.UPN} -Properties * -Server $adServer -Credential $adCred => $exists -eq $null => True (for a UPN value that shouldn't return null) – user18349 Dec 01 '15 at 19:30
  • Sorry I wasn't clear. It didn't work. _Get-ADUser : A positional parameter cannot be found that accepts argument '*'._ – user18349 Dec 01 '15 at 19:45
  • 2
    try `$UPN = $newUser.UPN` then: `-Filter {UserPrincipalName -eq $UPN}` – Avshalom Dec 01 '15 at 19:46
  • Yes that works. I had resorted to that already. What bothers me is that I don't know why the other way won't work... I suspect it has something to do with $newUser being a pscustomobject (hash table?), but the UPN property should evaluate to a string. Maybe I'm way off base... dunno. – user18349 Dec 01 '15 at 19:56

3 Answers3

3

The BNF for filter query strings does not allow expressions as the second operand in a comparison, only values (emphasis mine):

Syntax:
The following syntax uses Backus-Naur form to show how to use the PowerShell Expression Language for this parameter.

<filter> ::= "{" <FilterComponentList> "}"
<FilterComponentList> ::= <FilterComponent> | <FilterComponent> <JoinOperator> <FilterComponent> | <NotOperator> <FilterComponent>
<FilterComponent> ::= <attr> <FilterOperator> <value> | "(" <FilterComponent> ")"
<FilterOperator> ::= "-eq" | "-le" | "-ge" | "-ne" | "-lt" | "-gt"| "-approx" | "-bor" | "-band" | "-recursivematch" | "-like" | "-notlike"
<JoinOperator> ::= "-and" | "-or"
<NotOperator> ::= "-not"
<attr> ::= <PropertyName> | <LDAPDisplayName of the attribute>
<value>::= <compare this value with an <attr> by using the specified <FilterOperator>>

Put the value of the property you want to compare against in a variable and use that variable in the comparison. You may also want to define the filter as an actual string, if only for clarity (despite what it looks like the filter is not a scriptblock).

$upn = $newUser.UPN
$exists = Get-ADUser -Filter "UserPrincipalName -eq '$upn'" ...
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • Hi Ansgar, can you explain a bit more on this please? Or even go to my post I just created which is basically the same issue http://stackoverflow.com/questions/39522042/powershell-how-to-pass-a-variable-to-filter – Mucker Sep 16 '16 at 00:20
  • I already quoted the [BNF](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form) from the documentation. What more explanation do you need? – Ansgar Wiechers Sep 16 '16 at 00:31
  • The filter query can use an expression as the second operand, but your solution of sticking the expression in an variable first is also a valid workaround. – BenH Jan 26 '17 at 14:41
  • @BenH I've seen filter queries using expressions fail *way* too many times to consider anything but a plain value a viable option. – Ansgar Wiechers Jan 26 '17 at 14:43
  • This doesn't work if the string value has a `'` in it. Instead a syntax error is generated. – Appleoddity Apr 25 '20 at 18:31
1

Expressions can inside the filter block of a Get-ADUser but they need to be properly wrapped with quotes.

Get-ADUser -Filter "UserPrincipalName -eq '$($newUser.UPN)'"
BenH
  • 9,766
  • 1
  • 22
  • 35
0
  • Never use a script block ({ ... }) as the -Filter argument - the -Filter parameter's type is [string] - construct your filter as a string.

  • While seemingly convenient, using a script block only works in very limited scenarios and causes confusion when it doesn't work - such as when involving property access, as in this case.

For more information, see this answer of mine.

mklement0
  • 382,024
  • 64
  • 607
  • 775