I agree with what @veefu suggests, and would like to build off that. To start with, you have different columns in your CSV as to what Set-ADUser
is expecting. To work around this I would suggest creating a property map hashtable.
$PropMap = @{
EmployeeNumber='EmployeeNumber'
Department='Department'
Title='Title'
office='Office'
Address='StreetAddress'
City='City'
State='State'
PostalCode='PostalCode'
Company='Company'
telephone='OfficePhone'
cell='Mobile'
Fax='Fax'
custom1='ExtensionAttribute1'
custom2='ExtensionAttribute2'
custom3='ExtensionAttribute3'
custom4='ExtensionAttribute4'
}
Then you want to find out what the valid parameters for Set-ADUser
are to determine if a given column should be applied as a parameter, or be fed to the -Replace
parameter.
#Find the valid parameters for the Set-ADUser cmdlet (only strings, to avoid complex objects and switches, and no common parameters)
$ValidParams = Get-Command Set-ADUser -ShowCommandInfo |% ParameterSets |% Parameters |?{$_.ParameterType.FullName -match 'String' -and $_.Name -notin [System.Management.Automation.PSCmdlet]::CommonParameters} |Select -Expand Name -Unique
Then you import the CSV and loop through the users. For each user you find what properties they have filled in on the spreadsheet, see if it is a parameter for the Set-ADUser
cmdlet, and build a hashtable to splat to the cmdlet.
#Import the list of users and updates
$Users = Import-Csv C:\Scripts\Employees.csv
#Loop through users
ForEach($User in $Users){
#Set an empty hashtable for what this user needs to have updated
$UserParams = @{}
#Find the properties for this user that have values
$UserProps = $User.PSObject.Properties.Name |?{![string]::IsNullOrWhiteSpace($User.$_)}
#If it has a parameter in Set-ADUser add it to $UserParams
$UserProps |?{($ParamName=If($_ -in $PropMap.Keys){$PropMap[$_]}Else{$_}) -in $ValidParams} |%{$UserParams.Add($ParamName,$User.$_)}
#If it doesn't have a valid parameter build a hashtable for the -Replace parameter, and add that to $UserParams
$UserProps |?{($ParamName=If($_ -in $PropMap.Keys){$PropMap[$_]}Else{$_}) -notin $ValidParams} |% -Begin {$ToReplace = $_} -Process {$ToReplace.Add($ParamName,$User.$_)} -End {$UserParams.Add('Replace',$ToReplace)}
Here I added a little Try/Catch
to let you know if it failed to find or update any of the users, and if it failed to find them, or failed to update them, and gives the error. I used the shortened -ea
instead of -ErrorAction
out of habit.
#Try to find the user, and apply the updates
Try{
Get-AdUser -Filter "EmployeeID -eq '$($user.EmployeeID)'" -SearchBase "ou=Logins,dc=domain,dc=com" -ea Stop | Set-ADUser @UserParams -ea Stop
}Catch{
#If the Get-ADUser or Set-ADUser cmdlets failed throw a warning with the user's EmployeeID for investigation
#Determine if it was Get-ADUser or Set-ADUser that failed, to see if we couldn't find the user or couldn't update the user
$WarningMessage = If($_.InvocationInfo.MyCommand -eq 'Get-ADUser'){'find'}else{'update'}
Write-Warning "Unable to $WarningMessage user with EmployeeID (actual error follows): $($User.EmployeeID)"
Write-Warning "$_`n"
}
}
-Replace [hashtable]
syntax, even if a cmdlet parameter is also provided for the attribute. The documentation contains an example that does this with the Title attribute:Set-ADUser -Identity GlenJohn -Replace @{title="director";mail="[email protected]"}
. \$\endgroup\$-PropertyName
arguments from theSet-ADUser
and move them into the hashtable passed to-Remove
. \$\endgroup\$