Using Get-AdUser with an imported CSV

This topic contains 7 replies, has 5 voices, and was last updated by  Joel Sallow 3 months, 3 weeks ago.

  • Author
    Posts
  • #97355

    Darren Shinkins
    Participant

    Hi all,

    Wonder if someone could point out where I'm going wrong with this one – I'm sure this should be much simpler than I'm making it! I've got a list of people's names (which should match the DisplayName field in Active Directory), for whom I want to the ADUsers (ultimately, I'd look to grab the SAMAccountNames and export them out to another csv).

    So, I put the list of names into a csv and tried this:

    Import-CSV .\listofnames.csv | %{ Get-ADUser -Filter {DisplayName -eq $_.PersonName}}
    

    ...where personname is the column header in the csv file.

    When I run this I get an error

    Get-ADUser : Property: 'PersonName' not found in object of type 'System.Management.Automation.PSCustomObject'
    

    When I do a Get-Member on the imported CSV, I see PersonName listed, but it is a NoteProperty, rather than a property as you'd normally see it. Not sure if that's significant? Having said that, referencing the property works just fine when I so something slightly simpler like:

    Import-CSV .\listofnames.csv | %{ Write-Output $_.PersonName}
    

    Any ideas at all?

    Thanks

  • #97361

    Olaf Soyk
    Participant

    Hmmm ... a little bit strange but I can reproduce this error. I tried a little bit and this seems to work somehow ...

    Import-Csv -Path .\listofnames.csv  | 
        ForEach-Object {
            $DisplayName = $_.PersonName
            Get-ADUser -Filter {Displayname -eq $DisplayName} 
        }

    But please do not ask me to explain why it does not work the other and why it does work this way. 😉

  • #97386

    postanote
    Participant

    Olaf, yours works becasue you are explicitly sending the raw string value.

    They way the Darren is calling this, there is no default property called DisplayName in the result set, nor is he calling it before he uses the pipe.

        Import-CSV '.\listofnames.csv' | %{ $_.PersonName}
        Import-CSV .\listofnames.csv | %{ Get-ADUser -Filter {DisplayName -eq $_.PersonName}}
    

    We can see this by calling the Get-ADUser cmdlet without the pipeline for the file with Get-Member.

        Get-ADUser -Filter * | Select -First 1 | Get-Member -MemberType Properties | Select Name
    
        Name
        ---- 
        DistinguishedName
        Enabled
        GivenName
        Name
        ObjectClass
        ObjectGUID
        SamAccountName
        SID
        Surname
        UserPrincipalName 
    

    It's still odd that it is not matching by value though, which is odd.
    Yet, what appears to be happening, is that header name – PersonName, for whatever reason is getting read in and Get-ADUser is barfing on it.

    So, like your example, the following work as well.

        Import-CSV '.\listofnames.csv' | %{ Get-ADUser -Filter * -Properties DisplayName | Where DisplayName -eq $_.PersonName}
        (Import-CSV '.\listofnames.csv').PersonName | %{ Get-ADUser -Filter * | Where Name -EQ $_}
        Import-CSV '.\listofnames.csv' | %{ Get-ADUser -Filter * | Where Name -eq $_.PersonName}
    
        DistinguishedName : CN=5Admin ServiceAc...
        Enabled           : True
        GivenName         : 5Admin
        Name              : 5Admin ServiceAccount
        ObjectClass       : user
        ObjectGUID        : c8b5e...
        SamAccountName    : 5admin
        SID               : S-1-5-21-...
        Surname           : ServiceAccount
        UserPrincipalName : 5admin@contoso.com
        ....
    
  • #97424

    Olaf Soyk
    Participant

    As always – a great and comprehensive explanation. Thank you very much.

  • #97442

    Ron
    Participant

    The Filter parameter on Get-ADUser does not work directly, it converts it to an ldapFilter behind the scenes. As such, I'm never sure if it's going to do it correctly, so I avoid it for all but the simplest of searches. Try this:

    Import-CSV .\listofnames.csv | %{ Get-ADUser -ldapFilter "(DisplayName=$($_.PersonName))"}
  • #97452

    Joel Sallow
    Participant

    The alternative, which would work pretty well with OP's original attempt albeit with some extra $( ) around his variable property accessor, is to use double quotes for the filter.

    Yes, all the documentation on -Filter tells you to use braces. Just... don't. It is a [string] parameter in the documentation (and implementation), so what can often happen is that PS converts the contents of what is actually a [scriptblock] to [string] directly. When this is done, it can completely skip the part where PS usually expands variables in strings.

    Save yourselves the time and hassle, and just do:

    Import-CSV .\listofnames.csv | % { Get-ADUser -Filter "DisplayName -eq $($_.PersonName)"}
    

    It'll insert the variable just as it ought to.

  • #97496

    Darren Shinkins
    Participant

    Thank you all for your help and advice! Those all worked for me!

    See, I'd wondered if it didn't want to play nicely with my pair of braces on the filter argument – I think I tried with quotes, but I think I was missing the second $()! One small change I needed to make to Joel's solution was to put the comparison part in single quotes to give:

     Import-CSV .\listofnames.csv | % { Get-ADUser -Filter "DisplayName -eq '$($_.PersonName)'"}
    

    I'm also going to spend a bit more time playing with the -ldapFilter parameter; that looks like it will come in handy.

    One more quick follow-up question on this – re the use of -filter *

    My assumption was/is that I should probably avoid using this where possible to prevent unnecessary load on the domain controller. Is that right? Not sure exactly how many active users are in my AD, but rough guess is it's in the region of 5,000.

    Thanks again everyone!

  • #97509

    Joel Sallow
    Participant

    Oop, nice catch! I tend to forget that you still have to quote the second part because... AD cmdlets are silly, really there's no explanation for requiring such odd behaviour!

    And yes, where possible have some limiting aspect of your user search. If you try to get all users in the domain it'll cause a good bit of time lag, and probably bog down the network a little bit.

    So, either use a filter, or search only in a single OU, or something of that sort to limit the amount of objects the command will return from the DC.

    In general, with PS (and I guess with most programming languages!), you should attempt to adhere to the maxim: Filter left, format right.

    Basically, that means do all filtering as early as possible to limit the amount of unnecessary memory usage and objects being passed around. Then, do any formatting absolutely last so you retain data in its most useful form as much as possible and save you lots of trouble. 🙂

You must be logged in to reply to this topic.