Zoho Banner September 2011

Archive for July, 2013

Occasionally, I have a need to merge the attributes of one AD user into another.  This requirement is typically the result of a migration where some users have had accounts informally created in the target environment in advance of the formal migration process.  In other words, a user ends up with two accounts and needs to merge the authoritative attribute values from one of user object to another.   The Powershell script below shows an example of how selected attributes on one object can be replaced with those from another object.  

#########################################################
#
# Name: Merge-UserAttributes.ps1
# Author: Tony Murray
# Version: 1.0
# Date: 12/06/2013
# Comment: PowerShell 2.0 script to copy a fixed set of
# attributes from one user object to another
#
#########################################################

# Import the AD module
ipmo activedirectory

#### Function to test the existence of an AD user
function Test-ADUser() {
   [CmdletBinding(ConfirmImpact="Low")]
   Param (
      [Parameter(Mandatory=$true,
                 Position=0,
                 ValueFromPipeline=$true,
                 HelpMessage="Identity of the AD object to verify if exists or not."
                )]
      [Object] $Identity
   )
   trap [Exception] {
      return $false
   }
   $auxObject = Get-ADUser -Identity $Identity -Server $dc
   return $true
}
####

#### Global variables
$dc = (Get-ADDomainController).hostname

# Create an array of the attributes we want to copy
$atts2copy = @("ipphone","mobile","facsimileTelephoneNumber",
"telephonenumber","streetAddress","st","l","c","physicalDeliveryOfficeName",
"description","department","postofficebox","thumbnailPhoto","manager")

# Users to merge 
$source = "User1"
$target = "User2"

write-host "Working on source target pair: $source --> $target"
if ( (Test-ADUser $source) -and (Test-ADUser $target) ) { $greenlight = $true }
if ($greenlight) {
    $srcatts = Get-ADUser -Identity $source -pr * -Server $dc
    # Create a hashtable to store the attributes
    $replaceHashTable = New-Object HashTable
    # Add the attributes one-by-one to the hashtable
    foreach ($att2copy in $atts2copy){
        $attvalue = $srcatts.$att2copy
        if ($attvalue) {
            if ( ($attvalue.gettype()).name -eq "ADPropertyValueCollection") {
                # We have a collection which need to convert to an array
                # otherwise the set-aduser cmdlet doesn't set the value
                $attarray = @($attvalue)
                $replaceHashTable.Add($att2copy,$attarray)
            } # end if
            else {
                $replaceHashTable.Add($att2copy,$attvalue)
            } # end else
        } # end if
        Remove-Variable -ErrorAction SilentlyContinue -Name att2copy
        Remove-Variable -ErrorAction SilentlyContinue -Name attvalue
        Remove-Variable -ErrorAction SilentlyContinue -Name attarray
    } #end foreach
    # Set the attributes on the target user
    write-host "Setting attributes on target"
    $replaceHashTable
    Set-ADUser -Identity $target -Replace $replaceHashTable -Server $dc
    } # end if
Else {
    Write-Host "No match found for either $source or $target - please check CSV"
} # end else
Remove-Variable -ErrorAction SilentlyContinue -Name source
Remove-Variable -ErrorAction SilentlyContinue -Name target
Remove-Variable -ErrorAction SilentlyContinue -Name greenlight
Remove-Variable -ErrorAction SilentlyContinue -Name srceatts
$replaceHashTable = @{}

Another scenario where this script might be useful is merging attributes from an AD Snapshot (taken with NTDSUtil) into a “live” object, e.g. following the corruption of attribute values in the production environment.  In this case you would need to modify or remove the test for the existence of the user objects.

You can download a copy of the script here: Merge-UserAttributes

Quite often I see customers that need to use generic attributes to populate user, group or contact objects with certain values that do not appear in the default AD schema.  Most of these customers have Microsoft Exchange and tend to use the extension attributes that are delivered as part of the Exchange AD schema extensions.  This is all well and good, but there are some downsides with using the Exchange extensions.  In particular, the attribute values associated with the Exchange extension attributes are cleared when an object is either mail(or mailbox)-enabled or mail(or mailbox)-disabled.  Exchange effectively “owns” the values for these attributes and does not expect them to be used for anything other than Exchange use.

Armed with this knowledge, what are you supposed to do if you want to use some “spare” schema attributes for general use?  Well, within the AD default schema you don’t have a great deal of choice available.   Your best option is to extend the schema with some custom attributes of your own.  Custom schema extensions are no longer considered the scary beast they once were.  Schema conflicts are rare nowadays and can be handled by defuncting the offending schema class objects as required.

If you plan to add some classes and attributes to the schema you can choose appropriate, non-conflicting names and simply get on  with it.  This is fine if you know the attributes will be used indefinitely, but want if you simply want some generic attributes whose values you will populate for a short period (e.g. a project or a migration) and then re-use for some other purpose?  In that case you could extend your schema with some generic custom attributes – similar to those introduced by Exchange.

The attached LDF file is a schema extension that includes 10 generic string attributes (genericExtensionAttribute1-10).  These are included in custom auxiliary classes (Generic-User, Generic-Group and Generic-Contact) that are then linked to their corresponding classes from the default AD schema (User, Group and Contact).  The attributes have a maximum length of 128 characters (rangeUpper). 

To add the schema extensions, use LDIFDE running from a Administrator command prompt.  The account you use must be a member of the Schema Admins group.

Shortly after the schema update has completed, you will see the new attributes available for population on User, Group and Contact objects.

Feel free to use these extensions as-is (but don’t blame me if anything breaks!).  The OIDs used for the attributes and classes are derived from a parent that has been assigned to me by IANA.  You can obviously modify the LDF to change the names (e.g. if they conflict with anything in your schema) or the OID (e.g. if you have your own).  In any case you will need to replace the forest distinguished name in the LDF file (DC=contoso,DC=com) with your own.  Be sure to test this in your lab environment before you go ahead in production.

The LDF file is available here: Schema_Extensions

Enjoy!