Change Active Directory titles for all csv users - powershell

I would like to change 150 employees their job title.
I have a csvfile called Titletest.csv with columns UserPrincipalName [the user.name under it] and Title [job title under it]
The PowerShell script:
Import-Module ActiveDirectory
$users = Import-Csv -Path c:\scripts\Titlestest.csv | Foreach-Object {
$user = $_.user
$title = $_.title
#Selects the specified user and sets Job Title
Get-ADUser -Filter {(UserPrincipalName -eq $user)} | Set-ADUser -Title $title
}
I get errors saying:
Get-ADUser : Variable: 'user' found in expression: $user is not defined.
At line:14 char:1
+ Get-ADUser -Filter {(UserPrincipalName -eq $user)} | Set-ADUser -Titl ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADUser], ArgumentException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDirectory.Management.Commands.GetADUser
Can someone please advise?
Thank you.

The reason for your error is because $user has no assignment. You are attempting to assign $user the value of a property that does not exist. The header user apparently does not exist in your CSV file. See below for how to convert a csv into PowerShell objects and access their properties.
# Sample CSV TitleTest.csv
UserPrincipalName,Title
covid19#domain.com,Usurper
jsmith#domain.com,CEO
bossman#domain.com,CFO
Import-Csv -Path c:\scripts\TitleTest.csv | Foreach-Object {
$user = $_.UserPrincipalName
$title = $_.Title
Get-ADUser -Filter 'UserPrincipalName -eq $user' | Set-ADUser -Title $title
}
Explanation:
When using Import-Csv on a proper CSV file, the first row of delimited data will be converted to the properties of all input objects. All succeeding rows will be converted to individual objects with the header properties and output as a collection (array) of those objects. If the -Header parameter is used, then values passed into the parameter will become the properties of the objects. It is important to have the same number of delimited items on each row to ensure proper mapping.
Once you are dealing with objects, you can access their property values using the member access operator .. The syntax is object.property. So since you have headers UserPrincipalName and Title, you will need to use $_.UserPrincipalName and $_.Title to access the associated values.
$_ is the current pipeline object within your Foreach-Object {} script block.
Note that you don't technically need to define $user and $title here. You can just access the properties directly from the current object:
Import-Csv -Path c:\scripts\TitleTest.csv | Foreach-Object {
Get-ADUser -Filter "UserPrincipalName -eq '$($_.UserPrincipalName)'" |
Set-ADUser -Title $_.Title
}

Related

Importing csv data into custom attribute in Active Directory

I have a .csv file that I am using to modify custom attributes on users in Active Directory, but PowerShell does not like the script:
Import-Csv -path c:\users\user\desktop\doc.csv | ForEach-Object {
Set-ADUser $_.mail -replace #{
ExtensionAttribute1 = $_.ExtensionAttribute1
}
}
I get the following error:
Set-ADUser : replace
At line:2 char:4
Set-ADUser $_.mail -replace #{
CategoryInfo: InvalidOperation: (user123:ADUser) [Set-ADUser], ADInvalidOperationException
FullyQualifiedErrorId: ActiveDirectoryServer:0,Microsoft.ActiveDirectory.Management.Commands.SetADUser
The CSV only has 2 columns:
extensionAttribute1,mail
Any help would be appreciated
The -Identity parameter for Set-ADUser does not take an email address.
It needs either the DistinguishedName, objectGUID, SID or SamAccountName. You can also pipe a user object directly to the cmdlet.
Because of that, you need to first try to find the user with Get-ADUser and if that succeeds set the attribute.
Import-Csv -Path 'c:\users\user\desktop\doc.csv' | ForEach-Object {
$user = Get-ADUser -Filter "EmailAddress -eq '$($_.mail)'" -ErrorAction SilentlyContinue
if ($user) {
$user | Set-ADUser -Replace #{ extensionAttribute1 = $_.extensionAttribute1 }
}
else {
Write-Warning "No user with email address '$($_.mail)' found.."
}
}
PS. I always use the exact LDAP name inside the Hash for the key name when using -Add, -Replace etc. Case sensitive.

Need help using a variable to define -Properties for Get-ADUser

I have a script for getting all the members of various AD Groups but recently we have been needed to get more then just the names of the members and need to get various properties such as Title or Office. I tried adjusting my script so that you could input what properties you needed to define but it isn't working as I would like so I was hoping someone might be able to help.
Here is my original script:
$EndDate = (Get-Date).ToString("yyyy-MM-dd_HHmm")
$FileName = $ADGroup + '_' + $EndDate + '_ADGroupReport.csv'
$FilePath = 'P:\Information Technology\IT Reports\' + $FileName
function Get-Members {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, HelpMessage="Enter a valid AD Group.")]
[string]$ADGroup,
[Parameter(Mandatory=$false, HelpMessage="Enter valid AD Properties seperated by a comma.")]
$Properties
)
process {
if (!$Properties) {
Get-ADGroupmember -identity $ADGroup | select name | Export-Csv -Path $FilePath
} else {
Get-ADGroupmember -identity $ADGroup | where{$_.ObjectClass -eq "user"} | Get-ADUser -Properties '$Properties' | select name, $Properties | Export-Csv -Path $FilePath
}
}
}
$Group = Read-Host -Prompt 'Enter a valid AD Group:'
$Prop = Read-Host -Prompt 'Enter any additional properties needed:'
Get-Members -ADGroup $Group -Properties $Prop
This appears to work in the try phase if I only enter 1 property, but then fails on the finally stage. If I enter multiple properties, such as title,office then it fails at both stages.
The error I get when entering additional properties is below. My assumption is that it doesn't like this as a string and would prefer an array? I am not sure honestly on how to handle this.
Get-ADUser : One or more properties are invalid.
Parameter name: $Properties
At line:10 char:79
+ ... bjectClass -eq "user"} | Get-ADUser -Properties '$Properties' | selec ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (REDACTED) [Get-ADUser], ArgumentException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDirectory.Management.Commands.GetADUser
Before anyone says anything, I am aware the try block will fail if no properties are entered, its only in there for my testing currently.
I could see three issues on your code, first one, single quotes on -Properties '$Properties' will not allow the expansion of the variable $Properties, it would be as passing the literal string.
Should be:
Get-ADUser -Properties $Properties
Second issue, doing this Select-Object Name, $Properties will throw the following exception (assuming $Properties would have been an array):
$properties = 'email', 'title'
[PSCustomObject]#{
Name = 'User'
Email = 'user#domain.com'
Title = 'Administrator'
} | Select-Object Name, $properties
Cannot convert System.Object[] to one of the following types {System.String, System.Management.Automation.ScriptBlock}.
You could do something like this so that Name is always included in the $Properties variable:
$properties = ,'name' # => This is hardcoded
$properties += 'email', 'title' # => This is user input
[PSCustomObject]#{
Name = 'User'
Email = 'user#domain.com'
Title = 'Administrator'
} | Select-Object $properties
Name Email Title
---- ----- -----
User user#domain.com Administrator
Third issue is the one pointed out by Theo on his comment, Read-Host will store the user input as string, so, assuming the user is actually using , as delimiter of each property, you can convert the input to an array using -split or .split():
$prop = ,'name'
$prop += (
Read-Host -Prompt 'Enter any additional properties needed'
).Split(',').ForEach('Trim')
Supposing the input was for example email, title:
Enter any additional properties needed: email, title
name
email
title

Set-AdUser a referral was returned from the server

I'm trying to set a new company value for users from a CSV.
I read that you get the error when not setting the server in my Set-AdUser command.
At line:18 char:18
+ ... $query | Set-ADUser -Server tstdc01 -Company "New Company"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (CN=testUser\, H...DC=domain,DC=local:ADUser) [Set-ADUser], ADReferralException
+ FullyQualifiedErrorId : ActiveDirectoryServer:8235,Microsoft.ActiveDirectory.Management.Commands.SetADUser
--------------------------------------------------------------------------------------------------------
Import-Module ActiveDirectory
$users = Import-Csv -Path "pathToCsv.csv" -Encoding UTF8 -Delimiter ";"
$setUsers = #()
$domain = "domain.local:3268"
foreach ($user in $users) {
$samAccountName = $user.samAccountName
$query = Get-ADUser -Filter {Samaccountname -eq $samAccountName} -Server $domain
if ($query) {
$query | Set-ADUser -server tstdc01-Company "New Company"
$setUsers += $query
}
}
As Santiago implied this looks like an issue of cross domain or forest communication. And/or you are passing a user from one domain and attempting to set it in another.
See here, and a link here
An aside, a few pointers; You don't need to filter for samAccountName when you already have the samAccountName, the query can be something like:
$setUsers =
Get-ADUser $samAccountName -Server $domain |
ForEach-Object{
Set-ADUser $_ -Server tstdc01 -Company "New Company" -PassThru
}
Also note: you should avoid += I don't know how big a job this is, but it can degrade performance as it causes the creation of a new array and a copy of the existing array. Repeated many times that can cause big performance issues. There are a number of ways to address that, but the preferred approach is to let PowerShell gather the results for you. So above assign the $setUsers variable to the output of the loop. Add -PassThru to output the object that was set.
Update:
With the point regarding += demonstrated, #SantiagoSquarzon pointed out we don't even need the loop anymore:
$setUsers =
Get-ADUser $samAccountName -Server $domain |
Set-ADUser -Server tstdc01 -Company "New Company" -PassThru

"Cannot validate argument on parameter 'Identity'" while changing the description for multiple users

I have a simple script to change part of the description for a user in AD.
Get-ADUser testuser -Properties description | ForEach-Object {
Set-ADUser $_.SamAccountName -Description "ChgDescript,$($_.Description.Split(',')[1])"
}
However, I now have 700 users, where I need to change part of the description, using the command above. I'm unable to figure out the script correctly to import the .csv file and run the script against it.
$csvFile = "path_is_here"
Import-Module ActiveDirectory
Import-Csv $csvFile | Get-ADUser -Properties description | ForEach-Object {
Set-ADUser $_.SamAccountName -Description "ChgDescript,$($_.Description.Split(',')[1])"
}
When I run the script above, I receive the following error:
Cannot validate argument on parameter 'Identity'.
The error is coming from the Get-ADuser cmdlet and informing you that its -Identity parameter is null. I don't know the structure of your input file; but lets assume that its just a list of account names (so I added a header value of AccountName for readability), pass that property of your custom object created by your Import-Csv cmdlet to the Get-ADUser's -Identity parameter and see if it helps.
Unit Test Example:
Import-Csv -Path "C:\Temp\Users.txt" -Header "AccountName" | ForEach-Object {
Get-ADUser -Identity $_.AccountName
}
Checkout method 3 in the help examples for Set-ADUser
http://go.microsoft.com/fwlink/?LinkID=144991
Modify the Manager property for the "saraDavis" user by
using the Windows PowerShell command line to modify a local instance
of the "saraDavis" user. Then set the Instance parameter to the local
instance.
See if this works:
$Users = Import-Csv -Path "C:\test_users.txt" -Header "AccountName"
foreach($User in $Users){
$ADUser = Get-ADUser -Identity $User.AccountName -Properties Description
$ADUser.Description = "PUT YOUR MODIFIED DESCRIPTION HERE"
Set-ADUser -Instance $ADUser
}
May you have to store the description in a variable before, like:
Get-Content users.txt | Get-ADUser -Prop Description | Foreach {
$desc = $_.description + " Disabled 21122012 123456"
Set-ADUser $_.sAMAccountName -Description $desc
}
(just copied from technet)
Tell PowerShell which delimiter to use, when it is not comma:
import-csv -Path "c:\test.csv" -Delimiter ";"
And it will work fine.

Powershell AD: Export CSV of specific fields based on CSV input of Names?

I need to pass in a list of Users and get back a CSV with Name, SamAccountName, email
My Input CSV is as follows:
"John Doe"
"Jane Doe"
Here's the current code I'm using. I'm not sure what the problem is. The users actually do exist under the "DC" specified...
Import-Module ActiveDirectory
Function Get-ADUsersDetailsCSV
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$True,Position=1)]
[String]$InCSV,
[Parameter(Mandatory=$True)]
[String]$OutCSV
)
If($InCSV)
{
If(Test-Path -Path $InCSV)
{
$USERS = Import-CSV $InCSV -Header Name
$USERS|Foreach{Get-ADUser $_.Name -Properties * |Select Name, SAMAccountName, mail}|Export-CSV -Path $OutCSV
} #End Test that the files exist
Else
{
Write-Warning "Cannot find path '$InCSV' because it does not exist."
}
} #End Ensure Input and Output files were provided
} #End Function Get-UsersDetailsCSV
Here's the error:
Get-ADUser : Cannot find an object with identity: 'John Doe' under: 'DC=blah,DC=com'.
At U:\data\GetADUserInfo PS Script\GetADUsersDetailsCSV.psm1:19 char:28
+ $USERS|Foreach{Get-ADUser $_.Name -Properties * |Select Name, SAMAcc ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Name:ADUser) [Get-ADUser], ADIdentityNotFoundException
+ FullyQualifiedErrorId : Cannot find an object with identity: 'John Doe' under: 'DC=blah,DC=com'.,Microsoft.ActiveDirectory.Management.Commands.GetADUser
Based upon your feedback above, I will make changes to this answer. However, there is no need to run Get-ADUser twice as you get both the name and email properties with the Get-ADUser object.
$user = Get-ADuser -Filer { Name -eq $Name }
In addition, you are able to pipe different objects together. Try this and see what you get
$ExportCSVPath = "C:\Exportedcsv.csv"
$users = (Import-Csv -Path $CsvFilePath) |
% {Get-ADUser -Filter { Name -eq $_.DisplayName } |
Select -ExpandProperty SamAccountName, mail } |
Export-Csv $ExportCSVPath