Skip to content

Instantly share code, notes, and snippets.

@phyoewaipaing
Last active August 26, 2023 11:25
Show Gist options
  • Save phyoewaipaing/0fde39f26266e7698fb644f88ea98752 to your computer and use it in GitHub Desktop.
Save phyoewaipaing/0fde39f26266e7698fb644f88ea98752 to your computer and use it in GitHub Desktop.
Powershell Script to set any attribute for AD users
<#
.SYNOPSIS
Script that will set any attributes of bulk AD users.
.DESCRIPTION
This script will set any attributes of AD users read from csv file. You can also use it to rename the CN (Common Name) with -RenameCN option. If the csv file contains some blank attributes for some users, you will need to use with -OverwriteEmptyAttrib with $True or $False Option as below.
-OverwriteEmptyAttrib:$True --> Overwrite the user attributes with empty values if the empty attributes are found in the csv file.
-OverwriteEmptyAttrib:$False --> Skip those attributes if the empty attributes are found in csv file. All other attributes will be set according to csv file.
For the multi-value attributes, you will need to specify as @('value1','value2','value3') in the csv file where value(n) is the data to be inserted into the attribute.
Example usage:
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv
Set all attributes of AD users as found in csv file. It will give an error message when the empty attributes are found in the csv file.
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -OverwriteEmptyAttrib:$False
Set all attributes of AD users as found in csv file. If some attributes are found as empty in the csv file, it will skip those attributes in setting AD user attributes.
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -OverwriteEmptyAttrib:$True
Set all attributes of AD users as found in csv file. If some attributes are found as empty in the csv file, it will overwrite those attributes with empty values in setting AD user attributes.
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -RenameCN
Set all attributes of AD users as found in csv file. The CN (Common Name) will be renamed accordingly, but you need to define these CN in advance in csv file.
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -NewLinesOutput
Set all attributes of AD users as found in csv file. The output results are grouped for each user and seperated by newlines for better visibility.
Author : Phyoe Wai Paing
Country : Myanmar(Burma)
Website : https://www.scriptinghouse.com
Version : v1.0 : 14.Jan.2023 : Initial Release
v1.1 : 15.Jan.2023 : Fixed the incorrect changed attribute number output
v1.2 : 16.Apr.2023 : There is no longer a limitation of changing the SamAccountName to any value.
You need to use 'Identity' in csv header to define source users (which was defined as SamAccountName in version 1.1).
Added the effective changed users' count and total user count with colorized summary output.
Added newlines for separation of multiple user's outputs.
.EXAMPLE
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv
Set all attributes of AD users as found in csv file. It will give an error message when the empty attributes are found in the csv file.
.EXAMPLE
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -RenameCN
Set all attributes of AD users as found in csv file. The CN (Common Name) will be renamed accordingly, but you need to define these CN in advance in csv file.
.EXAMPLE
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -OverwriteEmptyAttrib:$False
Set all attributes of AD users as found in csv file. If some attributes are found as empty in the csv file, it will skip those attributes in setting AD user attributes.
.EXAMPLE
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -OverwriteEmptyAttrib:$True
Set all attributes of AD users as found in csv file. If some attributes are found as empty in the csv file, it will overwrite those attributes with empty values in setting AD user attributes.
.EXAMPLE
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -OverwriteEmptyAttrib:$True -RenameCN
Set all attributes of AD users as found in csv file. If some attributes are found as empty in the csv file, it will overwrite those attributes with empty values in setting AD user attributes. The CN of the user will be renamed accordinly.
.EXAMPLE
.\Set_All_ADAttributes_v1.2.ps1 -FilePath AD_Users_Attributes.csv -OverwriteEmptyAttrib:$True -NewLinesOutput
Set all attributes of AD users as found in csv file. If some attributes are found as empty in the csv file, it will overwrite those attributes with empty values in setting AD user attributes.
The output results (on screen) are grouped together for each user and separated by new lines by newlines for multiple users for better visibility.
.PARAMETER FilePath
The path of csv file which should include the AD user attribute information.
.PARAMETER OverwriteEmptyAttrib
The bool parameter which indicates whether the specific user attributes should be overwritten or not if the empty attribute values are found in the csv file.
.PARAMETER RenameCN
The (switch) parameter used to rename the CN of users. If you don't specify the parameter, it will not rename the CN (Common Name / Full Name) of the users even it's present in the csv file.
.PARAMETER NewLinesOutput
The (switch) parameter for better visibility. The output results (on screen) are grouped together according to each user events and seperated by new lines for multiple users.
.LINK
You can find this script and more at: https://www.scriptinghouse.com/
#>
param ([parameter(Mandatory=$True,Position=0)][string]$FilePath, [parameter(Mandatory=$False,Position=1)][bool]$OverwriteEmptyAttrib, [parameter(Mandatory=$False,Position=2)][switch]$RenameCN,[parameter(Mandatory=$False,Position=3)][switch]$NewLinesOutput)
## check the csv file existence ##
Try {
$FileContents = import-csv $FilePath
}
catch [System.IO.FileNotFoundException]{
Write-Host -fore red "Csv file doesn't exit at $FilePath. Please input the correct file path. Script exits."
}
## If the csv header doesn't contain 'Identity' which is SamAccountName of users, then exit the script ##
If ($FileContents[0].psobject.Properties.Name.Trim() -Notcontains 'Identity')
{
Write-Host -fore red "The csv headers must contain 'Identity' which is the SamAccountName of users. Script exits."
EXIT;
}
## Unless the user specify the -RenameCN parameter although csv header contains 'Name', then exit the script ##
If ($RenameCN -eq $False -AND $FileContents[0].psobject.Properties.Name.Trim() -contains 'Name')
{
Write-Host -fore red "The csv headers contain 'Name' as the attribute in the csv file, so you will need to enable the parameter -RenameCN when running the script which means it will rename the Common Name (CN). See the example command below. Script exits."
"$($MyInvocation.Line) -RenameCN"
EXIT;
}
$EffectiveUserCount = 0; ## Initially set the effective user count
## Loop each user and build the string which contains the parameters ##
$FileContents | % {
$ReplaceString = $Null;
$ClearAttributeNames = $Null;
$ClearAttributeNamesWithExtraComma = $Null;
$Manager = $Null;
$User_New_CN = $Null;
$Is_User_CN_Renamed = $Null;
$CurUserObj = $_;
## Loop each properties(attributes) of current user and build the -replace @{??????} string to be used with Set-ADUser ##
$CurUserObj.psobject.Properties.Name | % {
$CurrentAttributeName = $_;
$CurrentAttributeValue = $CurUserObj.$($CurrentAttributeName)
## If the attribute is 'manager', we will get the manager's DN from SamAccountName (because we don't know manager's DN in advance) ##
If ($CurrentAttributeName -match '^manager$' -AND !([string]::IsNullOrWhiteSpace($CurrentAttributeValue)))
{
Try {
$Manager = (Get-ADUser -Identity $($CurUserObj.manager) -EA Stop).DistinguishedName
$ReplaceString += "$CurrentAttributeName `= `"$Manager`";"
}
catch {
Write-Host -fore red "[Error] : $($CurUserObj.Identity) : Manager SamAccountName is not found. So, it manager attribute will be skipped from being set."
}
}
## If the attribute is not 'Name' and not equal to 'Identity', then we'd need to consider adding the attrib into the replace-string ##
elseIf ($CurrentAttributeName -notmatch '^Name$' -AND $CurrentAttributeName -notmatch '^Identity$')
{
## If the current attribute is null or empty and the -OverwriteEmptyAttrib is defined and set to True (when running the script), then put the current attrib in building the command-string ##
If ([string]::IsNullOrWhiteSpace($CurrentAttributeValue) -AND $PSBoundParameters["OverwriteEmptyAttrib"] -eq $True)
{
$ClearAttributeNamesWithExtraComma += $CurrentAttributeName + ','
}
## If the current attribute is null or empty and the -OverwriteEmptyAttrib is defined and set to False (when running the script), then ignore the current attribute in building the command-string ##
elseif ([string]::IsNullOrWhiteSpace($CurrentAttributeValue) -AND $PSBoundParameters["OverwriteEmptyAttrib"] -eq $False)
{
#Nothing to do. This statement will just skip the replace-string from being added
}
## If the current attribute is null or empty and the -OverwriteEmptyAttrib is NOT defined (when running the script), then prompt the user to enter additional commandline option and exit the script ##
elseIf([string]::IsNullOrWhiteSpace($CurrentAttributeValue) -AND $PSBoundParameters["OverwriteEmptyAttrib"] -eq $NULL)
{
Write-Host -fore red "[Error] : $($CurUserObj.Identity) : Some of the attributes contain empty or whitespaces. If you want to overwrite users attributes with these empty values, then use -OverwriteEmptyAttrib:`$True if not, use -OverwriteEmptyAttrib:`$False. Script exits."
EXIT;
}
## The current attribute may contains the array (by catching pattern like @('example1',example2') ), so we build the string with double quotes ##
elseif ( [regex]::Match($CurrentAttributeValue,'\@\(.*\)').Success )
{
$ReplaceString += "$CurrentAttributeName `= $CurrentAttributeValue; "
}
## If the current attribute is fine, then just put it in building the command-string ##
else
{
$ReplaceString += "$CurrentAttributeName `= `"$CurrentAttributeValue`";"
}
}
## If the CN is 'Name' but empty in value, then exit the script ##
elseif($CurrentAttributeName -match '^Name$')
{
If ([string]::IsNullOrWhiteSpace($CurUserObj.$($CurrentAttributeName) ))
{
Write-Host -fore red "[Error] : $($CurUserObj.Identity) : CN (Common Name) cannot be blank. Script exits."
EXIT;
}
else
{
$User_New_CN = $CurrentAttributeValue; ## Get the value of CN of current user
}
}
else
{
#Nothing to do here
}
}
$CommandString = $Null; ## We better empty this value for every loop
## Build the command-string based on the presene of replace-string and clear-string ##
# No clear-string and only replace-string
If ($ClearAttributeNamesWithExtraComma.Count -eq 0 -AND $ReplaceString)
{
$CommandString = "Set-ADUser -Identity $($CurUserObj.Identity) -Replace @{$ReplaceString}"
}
# Only clear-string and not replace-string
elseif ($ClearAttributeNamesWithExtraComma.Count -ne 0 -AND !($ReplaceString))
{
## Remove the last comma in the clear string ##
$ClearAttributeNames = $ClearAttributeNamesWithExtraComma -replace ',$',''
$CommandString = "Set-ADUser -Identity $($CurUserObj.Identity) -Clear $ClearAttributeNames"
}
# Only replace-string
elseif ($ReplaceString)
{
## Remove the last comma in the clear string ##
$ClearAttributeNames = $ClearAttributeNamesWithExtraComma -replace ',$',''
$CommandString = "Set-ADUser -Identity $($CurUserObj.Identity) -Replace @{$ReplaceString} -Clear $ClearAttributeNames"
}
else
{
## Nothing to here
}
## Invoke the command by using command-string and also rename the CN ##
Try{
## Rename the Common Name of the user if the $User_New_CN is flagged ##
If ($User_New_CN -AND $RenameCN -eq $True)
{
$CurADUser = Get-ADUser -Identity $CurUserObj.Identity -Properties * -EA Stop -ErrorVariable Err
If ($CurADUser.Name -Notmatch "$($CurUserObj.Name)$")
{
$CurADUser | Rename-ADObject -NewName $CurUserObj.Name
Write-Host "[Info] : $($CurUserObj.Identity) : User CN has been renamed from `'$($CurADUser.Name)`' to `'$($CurUserObj.Name)`'"
$Is_User_CN_Renamed = $True;
$EffectiveUserCount++; ## Increment the effective user count just after the successful execution
}
}
Invoke-Expression -Command $CommandString -EA Stop -ErrorVariable Err
## Here we again increment the effective count only if the Invoke-Expression is success (Try/Catch block) and the user's CN rename operation didn't happen. Otherwise, there will be incremented twice ##
If ($Is_User_CN_Renamed -eq $NULL)
{
$EffectiveUserCount++;
}
## If the clear-string contains more than one comma, then we can consider there are some attributes that need to be cleared ##
$ClearAttributesCount = ($ClearAttributeNamesWithExtraComma -split ',').Count
## Calculate the attribute count before outputting the message ##
## If the replace-string contains more than one semicolumn, then it's more than @{SamAccountName = 'xxxxx';} meaning that there are other attributes that need to be updated ##
$ChangedAttributes = ($ReplaceString -split ';') | % { ($_ -split '=')[0].Trim() } | ? { $_ }
$ChangedAttributesString = $ChangedAttributes -join ','
$ChangedAttributesCount = (Select-String -InputObject $ReplaceString -Pattern "`"`;" -AllMatches).Matches.Count
## We will also count if the replace-string contains an array pattern for any of the attributes (for multi-value attribute, the pattern is @('xy','yz') )and if so, get the number ##
$MultiValue_AttributesCount = (Select-String -InputObject $ReplaceString -Pattern "(\@\(.*?\))" -AllMatches).Matches.Count
## If the user CN is to be changed, we added one more count ##
$ChangedAttributesCount = $ChangedAttributesCount + $MultiValue_AttributesCount + $(If ($Is_User_CN_Renamed) { 1 } )
## Output message ##
If ( $ChangedAttributesCount -gt 0 )
{
Write-Host "[Info] : $($CurUserObj.Identity) : $($ChangedAttributes.Count) Attribute(s) have been updated successfully. Changed attributes name(s): $ChangedAttributesString"
}
If ($ClearAttributesCount -gt 1)
{
Write-Host "[Info] : $($CurUserObj.Identity) : $($ClearAttributesCount-1) Attribute(s) have been cleared successfully. Cleared attribute name(s): $ClearAttributeNames"
}
}
catch [Microsoft.ActiveDirectory.Management.ADException]{
Write-Host -fore red "[Error1] : $($CurUserObj.Identity) : " -NoNewline
$ErrorMessage = $Err.Exception | Out-String
($ErrorMessage[0..($ErrorMessage.Length - 3)] -join '') | Write-Host -fore red -NoNewline
Write-Host -ForegroundColor red ". If you are setting 'manager' attribute, make sure it is an existing one and is specified in distinguishedName format."
}
catch [System.ArgumentException]{
Write-Host -fore red "[Error2] : $($CurUserObj.Identity) : " -NoNewline
$ErrorMessage = $Err.Exception | Out-String
Write-Host -fore red "$($ErrorMessage | findstr "The specified directory service attribute or value does not exist"). " -NoNewline
Write-Host -fore red "$($ErrorMessage | findstr "Parameter name:")"
EXIT;
}
catch [System.Management.Automation.ParseException]{
Write-Host -fore red "[Error3] : The csv header values contain some whitespaces. Please check and correct. Script exits."
EXIT;
}
catch [System.Management.Automation.ParameterBindingException]{
Write-Host -fore red "[Error4] : $CurUserObj : It seems that SamAccountName is missing for the following user. Please check and correct."
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]{
$pattern = "(?<=Cannot find an object with identity: ').+?(?=' under:)"
$NotFoundUser = [regex]::Matches($_.Exception.Message, $pattern).Value
Write-Host -fore red "[Error5] : $NotFoundUser : The directory object is not found. Please check if your SamAccountName (Identity in the csv header) is correct."
}
catch{
Write-Host -fore red "[Error6] : $($CurUserObj.Identity) : Generic error occurred."
$Err.Exception | Out-String | Write-Host -fore red
}
## For clear visibility of output, we put new line after each user loop ##
If ($NewLinesOutput)
{
Write-Host "`n"
}
}
### Output message with different colors ##
$SummaryOutput = "$EffectiveUserCount of $($FileContents.Count) users attributes have been changed. Script exits."
If ($EffectiveUserCount -eq $($FileContents.Count))
{
Write-Host -fore green $SummaryOutput
}
else
{
Write-Host -fore yellow $SummaryOutput
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment