I'm currently working on some PowerShell to update Active Directory User Attributes. The script will read the updated attributes from a CSV.
What I would like to achieve is to iterate through users and compare each user attribute against the value stored in the CSV. If the CSV attribute value doesn’t match the user's Active Directory attribute I would like to update the value in Active Directory
At present I can select a user and display the all the properties using the following:
Get-ADUser -Filter "UserPrincipalName -eq '$($upn)'" -Properties * -SearchBase 'DC=core,DC=com'
What I'm struggling on is the ability to loop through all the properties for each user and compare them against the CSV values for that user.
Here is the snippet I'm working from:
# Import CSV into variable $users
$users = Import-Csv -Path 'C:\PowerShell\AD\UserUpdates.csv'
# Loop through each user
foreach ($user in $users) {
#Search in specified OU and Update existing attributes
$userproperties = Get-ADUser -Filter "UserPrincipalName -eq '$($user.UserPrincpalName)'" -Properties * -SearchBase 'DC=core,DC=com'
}
Does anyone know a way of looping through all the user profile attributes for a user?
Any help or guidance would be greatly appreciated?
UPDATE
Ok working on this a bit further, I have made progress but I don't think it's the cleanest way of accomplishing this.
$userproperties = Get-ADUser -Filter "UserPrincipalName -eq '$($upn)'" -Properties * -SearchBase 'DC=core,DC=com' | Select-Object Name,Created, LastLogon,GivenName,SurName,DisplayName,DistinguishedName,UserPrincipleName
This allows me to select items such as the following:
$userproperties.DisplayName
But with this approach I need to list out every attribute I wish to work with. I would prefer to be able to loop across all properties. Maybe I can put all the properties I wish to utulise into an array and loop through that?
this is a way to cycle into the properties of an object (an AD user in this case):
$user = Get-ADUser -Filter "UserPrincipalName -eq '$($user.UserPrincpalName)'" -Properties * -SearchBase 'DC=core,DC=com'
$user | gm | ? membertype -eq property | select -expa name | % { $user.$_ }
in the foreach-object (%) you can add the logic you need to update some proeprty
It's not too hard to loop through all the properties of one entry in the CSV file. The trick is to transform the hashtable you get from looping through the imported
csv data into a PS object, as follows:
# Import CSV into variable $users
$users = Import-Csv -Path 'C:\PowerShell\AD\UserUpdates.csv'
# Loop through each user
foreach ($user in $users) {
#Obtain attributes from corresponding ADuser.
$userproperties = Get-ADUser -Filter '
"UserPrincipalName -eq '$($user.UserPrincpalName)'" `
-Properties * -SearchBase 'DC=core,DC=com'
#Search in specified OU and Update existing attributes
foreach ($prop in $user.psobject.properties) {
Set-variable -name $prop.name -value $prop.value
# Instead of doing a set-variable, you could set the corresponding attribute
# in the appropriate AD.
}
}
Set-ADUser has a -Replace parameter that accepts a hash table of properties and values that you can use to update multiple properties at once. Rather than looping through each property for each user, you can just build that hash table and then do a single update operation. You can make it a little more efficient by just returning the AD User properties you're checking from your CSV. That list of properties can be had by simply getting a property list from the first object in the collection created from your imported CSV file.
# Import CSV into variable $users
$CSVusers = Import-Csv -Path 'C:\PowerShell\AD\UserUpdates.csv'
#Get the list of properties to check
$Properties = $CSVusers[0].psobject.properties.name
# Loop through each user
foreach ($CSVuser in $CSVusers) {
$UpdateProperties = #{}
#Search in specified OU and Update existing attributes
$ADUser = Get-ADUser -Filter "UserPrincipalName -eq '$($CSVuser.UserPrincpalName)'" -Properties $Properties -SearchBase 'DC=core,DC=com'
#Create a hash table of properties that need updated
Foreach ($Property in $Properties)
{
if ($CSVUser.$Property -ne $ADUser.$Property)
{ $UpdateProperties[$Property] = $CSVuser.$Property }
}
#Update user
if ( $UpdateProperties.Count -gt 0 )
{ Set-ADUser $ADUser.DistinguishedName -Replace $UpdateProperties }
}
Related
Recently completed an Azure AD provisioning integration between SuccessFactors and On-Prem AD.
In order for some of our existing users to get 'scoped in' to the Update provisioning, they first need to match on employee id (we currently do not use the Create functionality).
There are about 400 users that we've identified need to be matched, and our HR team has provided us with a csv with the following attributes (Full Name, EmployeeID). I need to somehow compare this file with all users in AD who have no employee id, and if not, update EmployeeId with the contents from the HR provided file.
I'm a bit stuck on how to attack this. Need a Big Brain :)
#import HR file with required attributes "Formal Name, EmployeeId"
#returns ~6500 entries
$SFUsers = Import-Csv Z:\ExportsFromProd\Global_ActiveHeadcountReport_08292022.csv
#returns ~1400 entries
#some accounts never get an employee id
$users = Get-ADUser -Filter "*" -Properties EmployeeID | Where-Object {$_.employeeID -eq $null}
foreach ($account in $users) {
$accountName = $account.name
get-aduser -Filter {Name -eq $accountName} -Properties * | Select-Object samaccountname, displayName
#this is where i need help:
<#
try {
Lookup $SFUser.'Formal Name' in $SFUsers array???
Get $SFUser.'EmployeeID' | set-aduser $account -employeeId $SFUser.'EmployeeId'
}
catch {
}
finally {
}
#>
}
'''
You can use the faster -Filter or LDAPFilter parameters of Get-ADUser to find only users where the EmployeeID property is unset.
Also, your code could be done by using Get-ADUser only once:
#import HR file with required attributes "Formal Name, EmployeeId"
#returns ~6500 entries
$SFUsers = Import-Csv -Path 'Z:\ExportsFromProd\Global_ActiveHeadcountReport_08292022.csv'
#returns ~1400 entries
#some accounts never get an employee id
$users = Get-ADUser -Filter "employeeid -notlike '*'" -Properties DisplayName, EmployeeID
# or use LDAPFilter
# $users = Get-ADUser -LDAPFilter "(!employeeID=*)" -Properties DisplayName, EmployeeID
foreach ($account in $users) {
# try and find this user in the csv file either by .Name or .DisplayName property
$HRUser = $SFUsers | Where-Object { $_.'Formal Name' -eq $account.Name -or
$_.'Formal Name' -eq $account.DisplayName}
if ($HRUser) {
$account | Set-ADUser -EmployeeID $HRUser.EmployeeId
}
else {
Write-Warning "AD user $($account.Name) not found in the CSV file.."
}
}
I'm hit and miss when it comes to writing PowerShell these days. I currently have a CSV with the following headers - Name, UserName, EXT, UserPrincipleName. I need to add the column data for OtherTelephone into each user's AD profile. I have a basic script going but I wanted to see if I was missing anything or if something needed to be corrected. I've added data to non-array attributes but wasnt sure if it was the same.
$users = Import-csv -path ".\extensions.csv"
foreach ($ext in $users {
Get-ADUser -Fi * -prop othertelephone -searchbase "MyOU" | select name,#{n="othertelephone";e={$_.othertelephone -join ";"}} | Set-aduser $_.userName -add #{othertelephone = $ext}
Thanks. And as always, I appreciate the help.
Since LDAP attribute otherTelephone is a multivalued (string array) property, I would first check to see if perhaps the new extension from the csv is already set for that user.
Then, if it is not, add it to the existing array.
Try
$searchBase = "OU=MyOU, ...."
$users = Import-csv -Path ".\extensions.csv"
foreach ($user in $users) {
# first check, is csv field EXT populated?
if ([string]::IsNullOrWhiteSpace($user.EXT) {
Write-Warning "Empty extension value for user $($user.Name) in the CSV.."
continue # skip this one and proceed with the next
}
# try and find the user using its UserPrincipalName
$adUser = Get-ADUser -Filter "UserPrincipalName -eq '$($user.UserPrincipalName)'" -Properties otherTelephone -Searchbase $searchBase
if ($adUser) {
# test if the new extension has already been set (otherTelephone is an array)
if ($adUser.otherTelephone -contains $user.EXT) {
Write-Host "Extension $($user.EXT) is already set for user $($user.Name).."
}
else {
Write-Host "Adding extension $($user.EXT) to user $($user.Name)"
# add the new extension to whatever is already set
# using -Add or -Replace usually wants strongly typed object arrays
# therefore the cast to [string[]]
[string[]]$extensions = #($user.EXT) + $adUser.otherTelephone
$adUser | Set-ADUser -Replace #{otherTelephone = $extensions}
}
}
else {
Write-Host "User $($user.Name) not found.."
}
}
Please note the property is called UserPrincipalName, not as stated in the question UserPrincipleName.
I've got a list of valid users provided by HR. The formatting was not cool, so I managed to get a new file like I wanted: one column, on each line the samaccountname (1st letter of firstname and name).
My file looks like this:
bgates
sjobs
bmarley
epresley
etc.
I'd like to disable users who are NOT in this list. I guess I have to deal with some if stuff, but I don't know how to.
#HariHaran, i have tried this:
#this part works fine
$list = Import-Csv .\listadnames2.csv -Delimiter ";"
$lol =
ForEach ($user in $list)
{
$user.prenom[0] + $user.nom
}
$lol | Out-File .\samaccountnames.csv
$validusers = Import-Csv .\samaccountnames.csv
$fullusers = Get-ADUser -Filter * -SearchBase "OU=USERS,DC=domain,DC=com" -ResultPageSize 0 -Prop samaccountname | Select samaccountname
foreach ($u in $validusers)
if ($u -match $fullusers) {continue} else
{
Set-ADUser -Identity $($._) -Enabled $false -whatif
}
The users list (samaccountnames.csv) you create in $lol is not a CSV file, but simply a text file with all constructed usernames each on a separate line.
Therefore you should read the file using
$validusers = Get-Content .\samaccountnames.csv instead of $validusers = Import-Csv .\samaccountnames.csv.
Then you'll have an array of samaccountnames to work with.
Next, I wonder why you use -ResultPageSize 0.. The default setting is 256 objects per page, so I can only imaging you could need this value to be higher than this default, not less.
(see the docs)
Taken from the part where you read the samaccountnames file, I think this will do the job:
$validusers = Get-Content .\samaccountnames.csv
# property 'SamAccountName' is returned by default as are
# 'DistinguishedName', 'Enabled', 'GivenName', 'Name', 'ObjectClass', 'ObjectGUID', 'SID', 'Surname' and 'UserPrincipalName'
# get the user objects from AD and loop through them to see if they need to be set disabled
Get-ADUser -Filter * -SearchBase "OU=USERS,DC=domain,DC=com" | ForEach-Object {
# the $_ automatic variable now holds an AD user object
# or use if($_.SamAccountName -notin $validusers). Only for PowerShell version 3.0 and up
if ($validusers -notcontains $_.SamAccountName) {
$_ | Set-ADUser -Enabled $false -WhatIf
}
}
I am trying to create a script that will check a list of user names and show the user full name and some attribute settings from AD. Basically I have been sent a list of usernames which are just numbers and management want to know the users full name for each username. they also want to know want division they work for.
Below is the script I have created which doesn't work.
$csv = Import-Csv "C:\temp\users.csv"
foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter {EmployeeID -eq $name} -Properties * |
Get-ADUser -Division $user.Programme
} | Export-Csv "C:\Temp\Results.csv"
So I'm working under the assumption that there is a column named myid in your csv file that contains the id you need to be looking up. Assuming that is the case you'll need to make a few changes here. You'll need to remove the second get-aduser as it is not really doing anything for you, and there is no -division switch available to the get-aduser cmdlet, if you need to restrict your results to just a few settings you can do that using the -properties switch and piping to select as shown below. Keep in mind that none of this will matter if the users do not have the "employeeid" and "division" properties set on their AD accounts, which is fairly rare in my experience but if your company does as a matter of policy when creating accounts should be fine. If you replace the get-aduser line in your script with this it should get the account of any user with an EmployeeID property that matches the one in your spreadsheet and then output that person's full name, division, and employeeid to your CSV file.
Get-ADUser -Filter {EmployeeID -eq $name} -Properties "displayname","division","employeeid" | Select-Object "employeeid","displayname","division"
When in doubt, read the documentation. Get-ADUser doesn't have a parameter -Division. You need to select the properties you want in the output file. Also, foreach loops don't pass output into the pipeline. You need a ForEach-Object loop if you want to pass the output directly into Export-Csv:
Import-Csv 'C:\temp\users.csv' |
ForEach-Object {
$name = $_.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
} |
Select-Object SamAccountName, DisplayName, Division |
Export-Csv 'C:\Temp\Results.csv' -NoType
Otherwise you need to collect the output in a variable:
$users = foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
}
$users | Export-Csv 'C:\Temp\Results.csv' -NoType
or run the loop in a subexpression:
$(foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
}) | Export-Csv 'C:\Temp\Results.csv' -NoType
This is a generic code structure that can be adapted for data collection / enumeration and production of CSV files, tailored to your scenario. We use similar at my workplace. It contains some error handling - the last thing you'd want is inaccurate results in your CSV file.
# Create an array from a data source:
$dataArray = import-csv "C:\temp\users.csv"
# Create an array to store results of foreach loop:
$arrayOfHashtables = #()
# Loop the data array, doing additional work to create our custom data for the CSV file:
foreach($item in $dataArray)
{
try
{
$ADObject = Get-ADUser -Filter { EmployeeID -eq $item.MyID } -Properties DisplayName,Division -ErrorAction Stop
}
catch
{
Write-Output "$($item.MyID): Error looking up this ID. Error was $($Error[0].Exception.Message)"
}
if($ADObject)
{
# Create a hashtable to store information about a single item:
$hashTable = [ordered]#{
EmployeeID=$item.myID
DisplayName=$ADObject.DisplayName
}
# Add the hashtable into the results array:
$arrayOfHashtables += (New-Object -TypeName PSObject -Property $hashTable)
}
else
{
Write-Output "$($item.MyID): No result found for this ID."
}
}
# If the results array was populated, export it:
if($arrayOfHashtables.Count -gt 0)
{
$arrayOfHashtables | Export-CSV -Path "C:\Temp\Results.csv" -Confirm:$false -NoTypeInformation
}
As mentioned elsewhere, division isn't a property on an AD object so you might need to lookup this data elsewhere. If you can do that with another line of PowerShell inside your foreach loop, you could add this to your hashtable object like so:
$hashTable = [ordered]#{
EmployeeID=$item.myID
DisplayName=$ADObject.DisplayName
Division=$DivisionFromOtherSource
}
I have a need to query AD based on a field that is not one of the fields that is not indexed. We have a field called EmployeeID. When I try to filter on that I get a invalid argument. I can query for any indexed field but I just don't have those.
Import-Module ActiveDirectory
$users = ForEach ($user in $(Get-Content "C:\Users\leaker.AUTH\Documents\MADO - General\Tools\ED Dump tool\ED Dump tool\badgem.txt"))
{
Get-AdUser $user -filter "EmployeeID -eq '$_.employeeID)'" -Properties SamAccountNAme,displayName,employeeID,mail
}
$users |
Select-Object SamAccountNAme,displayName,employeeID,mail |
Export-CSV -Path "C:\Users\leaker.AUTH\Documents\MADO - General\Tools\ED Dump tool\ED Dump tool\output.csv" -NoTypeInformation
Any Help would be appreciated.
$user will be bound to the Identity parameter - Filter and Identity does not exist in the same parameter set.
Remove -filter "EmployeeID -eq '$_.employeeID)'"
I assume that your CSV has a field named "employeeID"? If so, that will be a property of the $name variable that is created in the ForEach loop.
You don't need the $user argument for Get-ADUser and it looks like your filter syntax has strange brackets and quotes in it. Try the following:
...
Get-ADUser -Filter {EmployeeID -eq $name.employeeId} -Properties samAccountNAme,displayName,employeeID,mail
...