Free AD Tool

AD CSV generator tool

Generate any CSV file just by using the basic AD Attributes.

Copy, update Active Directory user attributes with PowerShell

Free AD Tool

Duplicate Object Audit

Find all duplicate objects in your domain with a single click.

Contents

Scanning headers...

What “replicating user attributes” really means in AD

Active Directory doesn’t have a special “copy attributes” feature for users—the directory stores an object (the user) with a set of schema-defined attributes, and your changes are just LDAP modify operations against those attributes.

PowerShell “replication” in this context usually means one of these operator tasks:

  1. Add / update attribute values for an existing user (single user or bulk)
  2. Copy a chosen set of attributes from a “template” user to another user (or many users)
  3. Copy multi-valued attributes (like proxyAddresses) safely
  4. Copy group membership (which is not the same as copying the user’s memberOf attribute)

This doc is written as a reference you can keep beside your console while you work.

 


 

Prereqs and safety rails (don’t skip in production)

Prereqs

  • You need the ActiveDirectory PowerShell module (RSAT). Microsoft documents RSAT installation via Windows capabilities (for AD DS tools) using Get-WindowsCapability / Add-WindowsCapability. (Microsoft Learn)
  • Load the module:
    Import-Module ActiveDirectory
    

Safety rails

  • Prefer running against a specific DC when testing to avoid “I updated it but I can’t see it yet” confusion:
    $Server = "dc01.contoso.com"
    
  • Export “before” state for any user you will modify:
    Get-ADUser jdoe -Server $Server -Properties * |
      Select-Object SamAccountName,DisplayName,Department,Title,Company,Office,proxyAddresses |
      Export-Csv .\jdoe-before.csv -NoTypeInformation
    
  • Use -WhatIf where you can while validating logic (many AD cmdlets support it).

 


 

Fast: view user attributes (and learn the real attribute names you must set)

By default, Get-ADUser returns only a subset of properties. To retrieve more (or all), use -Properties (including *). (Microsoft Learn)

# Commonly used view
Get-ADUser jdoe -Server $Server -Properties Department,Title,Company,Office,proxyAddresses |
  Select-Object SamAccountName,DisplayName,Department,Title,Company,Office,proxyAddresses

# Everything (heavy)
Get-ADUser jdoe -Server $Server -Properties * | Format-List *

Tip: In PowerShell you must use LDAP display names when using generic setters like -Replace / -Add. Microsoft’s Set-ADUser docs describe the -Add hashtable format and also the operation order when combining -Remove, -Add, -Replace, -Clear. (Microsoft Learn)

 


 

Core update patterns (single user)

Pattern A — Set common attributes directly

Set-ADUser exposes many common attributes as parameters (Department, Title, Office, etc.).

Set-ADUser jdoe -Server $Server `
  -Department "IT" `
  -Title "Systems Administrator" `
  -Office "Chennai"

Pattern B — Set any attribute via -Replace (works for custom/extension attributes)

-Replace takes a hashtable of ldapDisplayName = value.

Set-ADUser jdoe -Server $Server -Replace @{
  employeeType       = "Contractor"
  extensionAttribute1 = "CostCenter-431"
}

Pattern C — Clear attributes (wipe all values)

Use -Clear with one or more attribute ldapDisplayNames.

Set-ADUser jdoe -Server $Server -Clear @(
  "extensionAttribute1",
  "telephoneNumber"
)

 


 

Multi-valued attributes (proxyAddresses, otherTelephone, servicePrincipalName, …)

Multi-valued attributes need special handling: you either add/remove specific values or replace the whole set.

Add a value (keep existing values)

Set-ADUser jdoe -Server $Server -Add @{
  proxyAddresses = "smtp:jdoe@contoso.com"
}

This is the same idea shown in Microsoft community guidance for adding proxyAddresses via -Add. (Microsoft Learn)

Remove a specific value

Set-ADUser jdoe -Server $Server -Remove @{
  proxyAddresses = "smtp:oldalias@contoso.com"
}

Replace the entire attribute with a known-good list (array)

Microsoft’s scripting guidance shows using -Replace with an array for multi-valued attributes like proxyAddresses. (Microsoft for Developers)

$addresses = @(
  "SMTP:jdoe@contoso.com",    # primary SMTP in Exchange conventions
  "smtp:j.doe@contoso.com"
)

Set-ADUser jdoe -Server $Server -Replace @{ proxyAddresses = $addresses }

Important nuance: Some AD properties come back as collections (not plain arrays). Casting to an array (e.g., @($value) or [array]$value) avoids “type mismatch” surprises when you feed them back into -Replace. (Microsoft for Developers)

 


 

Copy attributes from one user to another (single + multi-valued + guardrails)

Step 1 — Decide what you will copy (don’t copy “everything”)

Copying all attributes is a common mistake. Many attributes are:

  • system-owned / system-only
  • constructed / backlink (e.g., group memberships)
  • identity-unique (SID, GUID, DN)
  • operational metadata (lastLogon*, whenChanged, uSNChanged)

Instead, define an explicit allow-list (you can expand it over time).

Example allow-list (typical HR/profile stamping):

  • department, title, company, physicalDeliveryOfficeName, streetAddress, l, st, postalCode, telephoneNumber, mobile
  • manager (careful: must exist and be correct)
  • extensionAttribute1..15 (if present in your schema)
  • proxyAddresses (only if you know the mail routing expectations)

Step 2 — Use a copy function that handles multi-valued values correctly

function Copy-ADUserAttributes {
  [CmdletBinding(SupportsShouldProcess)]
  param(
    [Parameter(Mandatory)] [string] $Source,
    [Parameter(Mandatory)] [string] $Target,
    [Parameter(Mandatory)] [string[]] $Attributes,
    [string] $Server = $env:LOGONSERVER.TrimStart("\"),
    [switch] $ClearWhenSourceEmpty
  )

  # Pull only what we need
  $src = Get-ADUser $Source -Server $Server -Properties $Attributes
  $dst = Get-ADUser $Target -Server $Server -Properties $Attributes

  $replace = @{}
  $clear   = New-Object System.Collections.Generic.List[string]

  foreach ($attr in $Attributes) {
    $val = $src.$attr

    if ($null -eq $val -or ($val -is [string] -and [string]::IsNullOrWhiteSpace($val))) {
      if ($ClearWhenSourceEmpty) { $clear.Add($attr) | Out-Null }
      continue
    }

    # Normalize multi-valued collections to a plain array
    if ($val -is [System.Collections.IEnumerable] -and -not ($val -is [string])) {
      $replace[$attr] = @($val)
    } else {
      $replace[$attr] = $val
    }
  }

  if ($PSCmdlet.ShouldProcess($Target, "Set attributes from $Source")) {
    if ($replace.Count -gt 0 -and $clear.Count -gt 0) {
      # Order matters if you combine ops (Remove > Add > Replace > Clear). :contentReference[oaicite:9]{index=9}
      Set-ADUser $Target -Server $Server -Replace $replace -Clear $clear.ToArray()
    }
    elseif ($replace.Count -gt 0) {
      Set-ADUser $Target -Server $Server -Replace $replace
    }
    elseif ($clear.Count -gt 0) {
      Set-ADUser $Target -Server $Server -Clear $clear.ToArray()
    }
  }
}

Run it:

$attrs = @(
  "department","title","company","physicalDeliveryOfficeName",
  "telephoneNumber","mobile","manager",
  "extensionAttribute1","extensionAttribute2",
  "proxyAddresses"
)

Copy-ADUserAttributes -Source "template.user" -Target "new.user" -Attributes $attrs -Server $Server -WhatIf
# then remove -WhatIf

Why this pattern works:

  • Get-ADUser -Properties ... fetches exactly what you need (and reminds you that Get-ADUser defaults are incomplete).
  • Set-ADUser -Replace accepts multiple attributes in one commit.
  • Multi-valued values are normalized to arrays, matching the documented expectation for multi-valued replaces.

 


 

Copy group memberships (don’t try to set memberOf)

memberOf is not a normal “editable” attribute. It’s a backlink/constructed view of group membership; you change membership by modifying the group’s member attribute (i.e., add the user to groups). In practice: use group cmdlets.

  • Get source groups: Get-ADPrincipalGroupMembership (Microsoft documents it and notes GC requirement).
  • Add target to groups: Add-ADGroupMember.

Example (copy direct memberships except “Domain Users”):

$sourceUser = "template.user"
$targetUser = "new.user"

$groups = Get-ADPrincipalGroupMembership $sourceUser -Server $Server |
  Where-Object { $_.SamAccountName -ne "Domain Users" }

foreach ($g in $groups) {
  Add-ADGroupMember -Identity $g -Members $targetUser -Server $Server -WhatIf
}

 


 

Bulk updates from CSV (update attributes at scale)

Option 1 — CSV columns map to AD attribute ldapDisplayNames

Example CSV (users.csv):

SamAccountName,department,title,extensionAttribute1,proxyAddresses
jdoe,IT,Systems Administrator,CostCenter-431,"SMTP:jdoe@contoso.com;smtp:j.doe@contoso.com"
asmith,Finance,Analyst,CostCenter-210,

Importer (supports single + multi-valued + optional clear when blank):

$Server = "dc01.contoso.com"
$MultiValued = @("proxyAddresses","otherTelephone","servicePrincipalName")

Import-Csv .\users.csv | ForEach-Object {
  $sam = $_.SamAccountName

  $replace = @{}
  $clear   = @()

  foreach ($prop in $_.PSObject.Properties.Name) {
    if ($prop -eq "SamAccountName") { continue }

    $raw = $_.$prop

    if ([string]::IsNullOrWhiteSpace($raw)) {
      # Decide your policy: skip vs clear
      # $clear += $prop
      continue
    }

    if ($MultiValued -contains $prop) {
      $replace[$prop] = $raw.Split(";") | ForEach-Object { $_.Trim() } | Where-Object { $_ }
    } else {
      $replace[$prop] = $raw
    }
  }

  if ($replace.Count -gt 0 -and $clear.Count -gt 0) {
    Set-ADUser $sam -Server $Server -Replace $replace -Clear $clear
  } elseif ($replace.Count -gt 0) {
    Set-ADUser $sam -Server $Server -Replace $replace
  } elseif ($clear.Count -gt 0) {
    Set-ADUser $sam -Server $Server -Clear $clear
  }
}

Remember: if you combine ops, AD cmdlets apply Remove → Add → Replace → Clear.

 


 

Troubleshooting: common Set-ADUser errors you’ll actually see

“Set-ADUser : The attribute cannot be modified because it is owned by the system”

This usually happens for one of these reasons:

  1. You tried to rename the user’s CN / Name using Set-ADUser. Use Rename-ADObject for the name attribute (and related rename semantics). Microsoft explicitly documents that Rename-ADObject sets the LDAP name attribute and that other name parts are handled via Set-ADUser.
    Get-ADUser jdoe -Server $Server | Rename-ADObject -NewName "John Doe"
    
  2. The attribute is schema-marked “systemOnly” (system-owned). Protocol documentation notes that the value of a system-only attribute cannot be modified by normal LDAP modify requests—only by the system.

    Quick check against schema:

    $schemaNC = (Get-ADRootDSE -Server $Server).schemaNamingContext
    Get-ADObject -Server $Server -SearchBase $schemaNC `
      -LDAPFilter "(lDAPDisplayName=instanceType)" -Properties systemOnly |
      Select-Object lDAPDisplayName,systemOnly
    
  3. You tried to modify a backlink / constructed attribute (like memberOf). Copy memberships using group cmdlets instead (see earlier section).

“This cmdlet does not work with a read-only domain controller”

Set-ADUser notes it won’t work with an RODC—ensure you’re targeting a writable DC (or omit -Server so it picks a suitable one).

“I changed it but ADUC doesn’t show it”

Often a visibility/timing issue:

  • You queried one DC but ADUC is showing another.
  • Force consistency during change windows: write and read back using the same -Server.

 


 

Practical “do not copy” list (keep yourself out of trouble)

Avoid copying these categories unless you fully understand the consequences:

  • Identity & uniqueness: objectGUID, objectSid, distinguishedName, sAMAccountName (unless you are explicitly renaming/logon-changing)
  • Operational metadata: whenChanged, uSNChanged, lastLogon*, pwdLastSet
  • Backlink/constructed: memberOf (copy via groups instead)
  • System-owned/systemOnly attributes: anything that fails with “owned by the system” and is schema-marked systemOnly

 


 

If your requirement is “delegate bulk attribute edits to helpdesk with approval workflows,” GUI tools can help. ManageEngine’s AD-focused tooling is one common example, but the PowerShell patterns above remain valuable even when you operationalize via a GUI (because you still need correct attribute semantics and safe allow-lists).


 

Newsletter Signup

Top Categories

Loading...

Latest Blogs

    Loading...

Top Articles

    Loading...