Powershell - querying and updating users based on column data match

I'm having trouble trying to figure out a way to first query AD (entire forest) for users based on attribute matching of data in column in a CSV, and then for each of those users' returned, updating a different attribute using data from a different column in the same CSV.

Here's what I've come up with so far...

$csv = Import-csv test.csv

foreach ($user in $csv)

{
    $surname = $user.surname
    $employeeNumber= $user.employeenumber
    $otherAddresses = $user.otheraddresses

try {

$filter = [scriptblock]::Create("employeenumber -eq '$employeeNumber'")
get-aduser -filter $filter -server dc02:3268

	}
 
 catch {
	    Write-Warning -Message ('Unable to find {0}: {1}' -f $surname,$_.exception.message)
        continue
	}
	
}
		

Open in new window


I haven't added the Set-Aduser part yet, the problem I'm currently trying to fix before adding that, is figuring out why the "catch {}" for the try/catch in the script isn't working.

If I put an invalid row in the csv, as in, a user who doesn't exist with last name and/or employeeNumber, there's no error reported in Powershell output.
garryshapeAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

footechCommented:
Add -errorAction Stop to your Get-ADUser command.  Otherwise the error is non-terminating.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
garryshapeAuthor Commented:
I'm trying to figure out now what would cause an error for me to test it....lol
Because if it doesn't find anyone that meets the filter, it just simply doesn't output anything, right? At least according to this code?
footechCommented:
Ah crap, I made a mistake while testing.  Setting the errorAction only works when using the -Identity parameter, not -filter (I was a little surprised with my test result, should have looked closer).  So, what you'll have to do is something like
$result = get-aduser -filter $filter -server dc02:3268
If ($result -eq $null)
{
    Write-Warning -Message ('Unable to find {0}' -f $surname)
}
Else
{
    # do something with $result
}

Open in new window


If you really wanted to use try/catch with that, then you could add in a throw statement (like at line 4) to generate the terminating error.
Making Bulk Changes to Active Directory

Watch this video to see how easy it is to make mass changes to Active Directory from an external text file without using complicated scripts.

garryshapeAuthor Commented:
That's pretty cool I appreciate it.
Now I have to figure out how to update custom attribute of the user if there's a match.
So if there's a match, would I add this to the else? I think I'd just add in one more command like

set-aduser Add @{otherAddresses=$otherAddresses}
But I have to make sure the data from $user.otheraddresses doesn't already exist.

The custom attribute is mult-value so an array I guess, I'm not sure how to check through each of the values in the custom attribute otherAddresses before "adding" what's from the respective column from the csv.
I am trying but not figuring it out.

I guess it were one value and not multi, it'd be like this?:

$result = get-aduser -filter $filter -server dc02:3268
If ($result -eq $null)
{
    Write-Warning -Message ('Unable to find {0}' -f $surname)
}
Else
{
$userOtherAddresses = get-aduser -property otherAddresses
if ($userOtherAddress -NotContains $user.OtherAddresses)
    set-aduser $user -Add @{otherAddresses=$otherAddresses}
}

Open in new window

footechCommented:
No need to do the query again, it'll just slow things down.  Instead use the first query to get all the info you need and store it in a variable.

Depending on how much efficiency is a concern, you can either always set the attribute, or just set it when it needs to be changed.  If you're comparing arrays, you can either use Compare-Object, or sometimes you just have to loop through an array checking each element for a condition one at a time.  When it comes to setting the attribute, you can either call Set-ADUser and add each non-match separately, or you can build up an array of all the non-matches for a user and then call Set-ADUser once.
$result | Set-ADUser -Add @{otherAddresses=$builtArray}

Open in new window


If you need more specifics, provide some sample data to work with.
garryshapeAuthor Commented:
Oh yeah in otherAddresses its essentially going to be their personal email address like bob@microsoft.com.
If its in the CSV for bob but not in AD for bob (based on matching of the employee number, then ideally it add the email to his otherAddresses field
footechCommented:
Did you understand and/or try to apply what I described in my last post?

For sample data, I mean actually provide a file that has the correct format.  When trying to work through a process, that can be one of the most helpful steps in accomplishing your goal.
garryshapeAuthor Commented:
Sorry yes itd be a CSV file being imported, don't think I can attach it here but here's a copy/paste:

otherAddresses,givenname,surname,employeeNumber
Bob@microsoft.com,Bob,Douglas,677812
footechCommented:
You didn't really answer my question...

Here's an option that should work (not fully tested).  Not sure what you mean by the "otherAddresses" attribute since that's not a standard AD attribute.
$csv = Import-csv test.csv

foreach ($user in $csv)
{
    $surname = $user.surname
    $employeeNumber= $user.employeenumber
    $otherAddresses = $user.otheraddresses
    $filter = [scriptblock]::Create("employeenumber -eq '$employeeNumber'")

    $result = get-aduser -filter $filter -server dc02 -Properties otherAddresses
    If ($result -eq $null)
    {
        Write-Warning -Message ('Unable to find {0}' -f $surname)
    }
    Else
    {
        $builtArray = @()
        foreach ($address in $otherAddresses)
        {
            if ( $result.otherAddresses -notcontains $address )
            {
                $builtArray += $address
            }
        }
        if ( $builtArray.count -gt 0 )
        {
            $result | Set-ADUser -Add @{otherAddresses=$builtArray}
        }
    }
}

Open in new window

garryshapeAuthor Commented:
wow thank you I can definitely try to work from that.
yes it's custom attribute in AD added to schema
garryshapeAuthor Commented:
Thought I would follow-up I changed the Else statement in the end just a little, to accommodate my multiple domain environment.
If you or anyone reads this and thinks they can advise of an alternative, that would be great.
Since what I found, was that I couldn't set-aduser the property I wanted when using set-aduser against the global catalog. I had to specify a domain controller, and the domain controller for each user would depend on which domain (same forest) they were in when the match of the employeeNumber was found.

   
 Else
    {
        $builtArray = @()
        foreach ($address in $otherAddresses)
        {
            if ( $result.otherAddresses -notcontains $address )
            {
                $builtArray += $address
            }
        }
        if ( $builtArray.count -gt 0 )
        {

#### begin added
        if (result.CanonicalName -like "*child.domain.com*")
{
            $result | Set-ADUser -server "child.domain.com" -Add @{otherAddresses=$builtArray}
}
else {
            $result | Set-ADUser -Add @{otherAddresses=$builtArray}
}
#### end added
        }
    }

Open in new window


I'm not sure how else to determine the domain they're in, at least without modifying the filter / scriptblock to work properly with the builtarray set-aduser part.

Perhaps this is a bad way to go about it and may slow down the network, I hope not!
footechCommented:
I think that'll work fine.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.