Extending Active Directory Users and Computers Console to Move User Groups
I decided to build upon the work discussed in the previous post to extend the Active Directory Users and Computers console. In particular, I wanted to add a new context menu option to user objects, that when invoked, would move the groups of the selected user to the user chosen via the object picker dialog.
The first step was to write the code to move the groups from one user account to another. The code expects the fully qualified path of the source user object as an argument. It then invokes the object picker dialog (refer to the previous post for more information) and prompts the administrator to select the target user. Finally, the groups of the source user are retrieved, and for each group, the target user is added and the source user is removed. A check is also performed to ensure that the administrator has not selected the source user as the target.
Imports CubicOrange.Windows.Forms.ActiveDirectory
Imports System.Windows.Forms
Imports System.DirectoryServices
Module Module1
Sub Main()
Dim Args() As String = System.Environment.GetCommandLineArgs()
Dim ObjectPicker As New DirectoryObjectPickerDialog
Dim ObjectPickerResult As DialogResult
Dim SelectedObject As DirectoryObject
Dim SourcePath As String
Dim TargetPath As String
ObjectPicker.AllowedObjectTypes = ObjectTypes.Users
ObjectPicker.DefaultObjectTypes = ObjectTypes.Users
ObjectPicker.AllowedLocations = Locations.JoinedDomain
ObjectPicker.DefaultLocations = Locations.JoinedDomain
ObjectPicker.MultiSelect = False
ObjectPickerResult = ObjectPicker.ShowDialog()
If ObjectPickerResult = DialogResult.OK Then
SelectedObject = ObjectPicker.SelectedObject
SourcePath = Args(1)
TargetPath = SelectedObject.Path
If TargetPath.IndexOf(SourcePath.Split("/")(3)) > 0 Then
Exit Sub
End If
Dim SourceUser As New DirectoryEntry(SourcePath)
For Each GroupPath In SourceUser.Properties("memberOf")
Dim Group As New DirectoryEntry("LDAP://" & GroupPath.ToString())
Group.Invoke("Add", New Object() {TargetPath})
Group.Invoke("Remove", New Object() {SourcePath})
Next
End If
End Sub
End Module
To modify the code to copy instead of move the groups, comment out line 37.
The next step was to make the compiled executable (which I copied to C:\Windows\MoveGroups.exe) accessible from within the Active Directory Users and Computers console. This was achieved by starting adsiedit.msc and navigating to CN=409,CN=DisplaySpecifiers under the Configuration partition of the domain, and modifying the properties of the CN=user-Display object. In particular, I added the following value to the adminContextMenu attribute:
2,Move &Groups,C:\Windows\MoveGroups.exe
This entry will create a new item on the context menu of user objects called Move Groups (with a shortcut key of G), that when selected, will invoke the executable C:\Windows\MoveGroups.exe.
The dialog used to modify the value of the adminContextMenu is shown below:

The modified context menu is shown below:

The requirements for using this extension are the .NET Framework and the Active Directory Users and Computers console.
You can download either the compiled executable file or the project source code.
If you intend to deploy this code across a corporate environment, I recommend you host MoveGroups.exe on a network share that is accessible to all computers running the Active Directory Users and Computers console. For example: \\domain.net\netlogon\MoveGroups.exe. If you do this, you'll need to configure the .NET runtime security policy to permit the execution of the code from a remote location. Unfortunately there is no way (that I know) to configure the security settings via group policy. Instead, you will need to use the Code Access Security Policy Tool (caspol.exe) to modify the settings on the computers that will run the code.
The following command will permit the execution of MoveGroups.exe from the network share named \\domain.net\netlogon:
caspol.exe -m -ag LocalIntranet_Zone -url file://domain.net/netlogon/* FullTrust