Exchange Custom Attribute editor with GUI, written in Powershell

Microsoft Exchange extends the default Active Directory schema with some additional attributes, also known as custom attributes.
These extra free fields are very handy, we use them for example for third party applications,employee identification numbers etc.
Recently we migrated to Exchange 2010, nice but the Exchange Management console 2010 is not supported on 32bit versions of Windows (we still use Windows XP 32bit). The only way to edit the custom attributes is through the Microsoft Exchange Management Console.
So I had two options, either give support personnel access to the one of the Exchange servers or create some script to do it. I chose the latter.
This Powershell script (with a nice GUI) allows you to edit custom attributes from any workstation (either Windows XP, Windows Vista or Windows 7 32bit or whatever runs Powershell :-) )
Here’s an impression of the script’s GUI:

And here is the (very long) Powershell code:

######################################################################
# Exchange Custom attribute editor 1.0
# Author: Maarten Damen
######################################################################

# Script configuration
$ldapstring = "ou=Users, dc=TEST, dc=NL" # LDAP string, pointing to the OU with users in it.
$username   = "accountmanagement" # Username with sufficient rights to edit custom attributes of users.
$password   = "123456" # Password of that particular user.

#----------------------------------------------
# Generated Form Function
#----------------------------------------------
function GenerateForm {

	#----------------------------------------------
	#region Import Assemblies
	#----------------------------------------------
	[void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
	[void][reflection.assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
	[void][reflection.assembly]::Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
	[void][reflection.assembly]::Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
	#endregion
	
	[System.Windows.Forms.Application]::EnableVisualStyles()
	$form1 = New-Object System.Windows.Forms.Form
	$btnSave = New-Object System.Windows.Forms.Button
	$label16 = New-Object System.Windows.Forms.Label
	$label15 = New-Object System.Windows.Forms.Label
	$label14 = New-Object System.Windows.Forms.Label
	$label13 = New-Object System.Windows.Forms.Label
	$label12 = New-Object System.Windows.Forms.Label
	$label11 = New-Object System.Windows.Forms.Label
	$label10 = New-Object System.Windows.Forms.Label
	$label9 = New-Object System.Windows.Forms.Label
	$label8 = New-Object System.Windows.Forms.Label
	$label7 = New-Object System.Windows.Forms.Label
	$label6 = New-Object System.Windows.Forms.Label
	$label5 = New-Object System.Windows.Forms.Label
	$label4 = New-Object System.Windows.Forms.Label
	$label3 = New-Object System.Windows.Forms.Label
	$custom15 = New-Object System.Windows.Forms.TextBox
	$custom14 = New-Object System.Windows.Forms.TextBox
	$custom13 = New-Object System.Windows.Forms.TextBox
	$custom12 = New-Object System.Windows.Forms.TextBox
	$custom11 = New-Object System.Windows.Forms.TextBox
	$custom10 = New-Object System.Windows.Forms.TextBox
	$custom9 = New-Object System.Windows.Forms.TextBox
	$custom8 = New-Object System.Windows.Forms.TextBox
	$custom7 = New-Object System.Windows.Forms.TextBox
	$custom6 = New-Object System.Windows.Forms.TextBox
	$custom5 = New-Object System.Windows.Forms.TextBox
	$custom4 = New-Object System.Windows.Forms.TextBox
	$custom3 = New-Object System.Windows.Forms.TextBox
	$custom2 = New-Object System.Windows.Forms.TextBox
	$custom1 = New-Object System.Windows.Forms.TextBox
	$label2 = New-Object System.Windows.Forms.Label
	$listbox1 = New-Object System.Windows.Forms.ListBox
	$label1 = New-Object System.Windows.Forms.Label
	$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState

	$FormEvent_Load={
			$root = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$ldapstring", $username, $password
			$searcher = New-Object DirectoryServices.DirectorySearcher
			$searcher.SearchRoot = $root
			$searcher.Filter = "(objectClass=user)"
			$results=$searcher.FindAll()
			
			foreach ($result in $results) {
				$listbox1.Items.Add($result.GetDirectoryEntry().cn.Value)
			}
	}
	
	$handler_listbox1_SelectedIndexChanged={
		# get current custom attributes for user
		$entry = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://CN={0}, $ldapstring" -f $listbox1.Text), $username, $password
		
		for ($i = 1; $i -lt 16; $i++) {
			$textbox = Get-Variable "custom$i"
			$propertyvalue = "extensionAttribute$i"
			$textbox.Value.Text = $entry.$propertyvalue.Value
		}
	}

	$handler_btnSave_Click={
		# Save changes in AD
		$entry = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://CN={0}, $ldapstring" -f $listbox1.Text), $username, $password
	
		for ($i = 1; $i -lt 16; $i++) {
			$textbox = Get-Variable "custom$i"
			if ($textbox.Value.Text -ne "") {
				$entry.Put("extensionAttribute$i", "{0}" -f $textbox.Value.Text)
			} else {
				$entry.PutEx(1, "extensionAttribute$i", $null)
			}
		}
		
		$entry.SetInfo()
	}
	
	$Form_StateCorrection_Load=
	{
		#Correct the initial state of the form to prevent the .Net maximized form issue
		$form1.WindowState = $InitialFormWindowState
	}
	
	#----------------------------------------------
	#region Generated Form Code
	#----------------------------------------------
	#
	# form1
	#
	$form1.Controls.Add($btnSave)
	$form1.Controls.Add($label16)
	$form1.Controls.Add($label15)
	$form1.Controls.Add($label14)
	$form1.Controls.Add($label13)
	$form1.Controls.Add($label12)
	$form1.Controls.Add($label11)
	$form1.Controls.Add($label10)
	$form1.Controls.Add($label9)
	$form1.Controls.Add($label8)
	$form1.Controls.Add($label7)
	$form1.Controls.Add($label6)
	$form1.Controls.Add($label5)
	$form1.Controls.Add($label4)
	$form1.Controls.Add($label3)
	$form1.Controls.Add($custom15)
	$form1.Controls.Add($custom14)
	$form1.Controls.Add($custom13)
	$form1.Controls.Add($custom12)
	$form1.Controls.Add($custom11)
	$form1.Controls.Add($custom10)
	$form1.Controls.Add($custom9)
	$form1.Controls.Add($custom8)
	$form1.Controls.Add($custom7)
	$form1.Controls.Add($custom6)
	$form1.Controls.Add($custom5)
	$form1.Controls.Add($custom4)
	$form1.Controls.Add($custom3)
	$form1.Controls.Add($custom2)
	$form1.Controls.Add($custom1)
	$form1.Controls.Add($label2)
	$form1.Controls.Add($listbox1)
	$form1.Controls.Add($label1)
	$form1.Text = "Exchange custom attribute editor v1.0 © Maarten Damen"
	$form1.Name = "form1"
	$form1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$form1.ClientSize = New-Object System.Drawing.Size(606,461)
	$form1.add_Load($FormEvent_Load)
	#
	# btnSave
	#
	$btnSave.TabIndex = 32
	$btnSave.Name = "btnSave"
	$btnSave.Size = New-Object System.Drawing.Size(120,23)
	$btnSave.UseVisualStyleBackColor = $True
	$btnSave.Text = "Save changes"
	$btnSave.Location = New-Object System.Drawing.Point(474,426)
	$btnSave.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$btnSave.add_Click($handler_btnSave_Click)
	#
	# label16
	#
	$label16.TabIndex = 31
	$label16.Size = New-Object System.Drawing.Size(115,19)
	$label16.Text = "Custom Attribute 15"
	$label16.Location = New-Object System.Drawing.Point(173,396)
	$label16.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label16.Name = "label16"
	#
	# label15
	#
	$label15.TabIndex = 30
	$label15.Size = New-Object System.Drawing.Size(115,19)
	$label15.Text = "Custom Attribute 14"
	$label15.Location = New-Object System.Drawing.Point(173,370)
	$label15.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label15.Name = "label15"
	#
	# label14
	#
	$label14.TabIndex = 29
	$label14.Size = New-Object System.Drawing.Size(115,19)
	$label14.Text = "Custom Attribute 13"
	$label14.Location = New-Object System.Drawing.Point(173,344)
	$label14.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label14.Name = "label14"
	#
	# label13
	#
	$label13.TabIndex = 28
	$label13.Size = New-Object System.Drawing.Size(115,19)
	$label13.Text = "Custom Attribute 12"
	$label13.Location = New-Object System.Drawing.Point(173,318)
	$label13.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label13.Name = "label13"
	#
	# label12
	#
	$label12.TabIndex = 27
	$label12.Size = New-Object System.Drawing.Size(115,19)
	$label12.Text = "Custom Attribute 11"
	$label12.Location = New-Object System.Drawing.Point(173,292)
	$label12.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label12.Name = "label12"
	#
	# label11
	#
	$label11.TabIndex = 26
	$label11.Size = New-Object System.Drawing.Size(115,19)
	$label11.Text = "Custom Attribute 10"
	$label11.Location = New-Object System.Drawing.Point(173,266)
	$label11.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label11.Name = "label11"
	#
	# label10
	#
	$label10.TabIndex = 25
	$label10.Size = New-Object System.Drawing.Size(115,19)
	$label10.Text = "Custom Attribute 9"
	$label10.Location = New-Object System.Drawing.Point(173,240)
	$label10.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label10.Name = "label10"
	#
	# label9
	#
	$label9.TabIndex = 24
	$label9.Size = New-Object System.Drawing.Size(115,19)
	$label9.Text = "Custom Attribute 8"
	$label9.Location = New-Object System.Drawing.Point(173,214)
	$label9.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label9.Name = "label9"
	#
	# label8
	#
	$label8.TabIndex = 23
	$label8.Size = New-Object System.Drawing.Size(115,19)
	$label8.Text = "Custom Attribute 7"
	$label8.Location = New-Object System.Drawing.Point(173,188)
	$label8.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label8.Name = "label8"
	#
	# label7
	#
	$label7.TabIndex = 22
	$label7.Size = New-Object System.Drawing.Size(115,19)
	$label7.Text = "Custom Attribute 6"
	$label7.Location = New-Object System.Drawing.Point(173,162)
	$label7.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label7.Name = "label7"
	#
	# label6
	#
	$label6.TabIndex = 21
	$label6.Size = New-Object System.Drawing.Size(115,19)
	$label6.Text = "Custom Attribute 5"
	$label6.Location = New-Object System.Drawing.Point(173,136)
	$label6.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label6.Name = "label6"
	#
	# label5
	#
	$label5.TabIndex = 20
	$label5.Size = New-Object System.Drawing.Size(115,19)
	$label5.Text = "Custom Attribute 4"
	$label5.Location = New-Object System.Drawing.Point(173,110)
	$label5.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label5.Name = "label5"
	#
	# label4
	#
	$label4.TabIndex = 19
	$label4.Size = New-Object System.Drawing.Size(115,19)
	$label4.Text = "Custom Attribute 3"
	$label4.Location = New-Object System.Drawing.Point(173,84)
	$label4.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label4.Name = "label4"
	#
	# label3
	#
	$label3.TabIndex = 18
	$label3.Size = New-Object System.Drawing.Size(115,19)
	$label3.Text = "Custom Attribute 2"
	$label3.Location = New-Object System.Drawing.Point(173,58)
	$label3.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label3.Name = "label3"
	#
	# custom15
	#
	$custom15.Size = New-Object System.Drawing.Size(300,20)
	$custom15.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom15.Name = "custom15"
	$custom15.Location = New-Object System.Drawing.Point(294,393)
	$custom15.TabIndex = 17
	#
	# custom14
	#
	$custom14.Size = New-Object System.Drawing.Size(300,20)
	$custom14.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom14.Name = "custom14"
	$custom14.Location = New-Object System.Drawing.Point(294,367)
	$custom14.TabIndex = 16
	#
	# custom13
	#
	$custom13.Size = New-Object System.Drawing.Size(300,20)
	$custom13.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom13.Name = "custom13"
	$custom13.Location = New-Object System.Drawing.Point(294,341)
	$custom13.TabIndex = 15
	#
	# custom12
	#
	$custom12.Size = New-Object System.Drawing.Size(300,20)
	$custom12.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom12.Name = "custom12"
	$custom12.Location = New-Object System.Drawing.Point(294,315)
	$custom12.TabIndex = 14
	#
	# custom11
	#
	$custom11.Size = New-Object System.Drawing.Size(300,20)
	$custom11.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom11.Name = "custom11"
	$custom11.Location = New-Object System.Drawing.Point(294,289)
	$custom11.TabIndex = 13
	#
	# custom10
	#
	$custom10.Size = New-Object System.Drawing.Size(300,20)
	$custom10.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom10.Name = "custom10"
	$custom10.Location = New-Object System.Drawing.Point(294,263)
	$custom10.TabIndex = 12
	#
	# custom9
	#
	$custom9.Size = New-Object System.Drawing.Size(300,20)
	$custom9.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom9.Name = "custom9"
	$custom9.Location = New-Object System.Drawing.Point(294,237)
	$custom9.TabIndex = 11
	#
	# custom8
	#
	$custom8.Size = New-Object System.Drawing.Size(300,20)
	$custom8.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom8.Name = "custom8"
	$custom8.Location = New-Object System.Drawing.Point(294,211)
	$custom8.TabIndex = 10
	#
	# custom7
	#
	$custom7.Size = New-Object System.Drawing.Size(300,20)
	$custom7.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom7.Name = "custom7"
	$custom7.Location = New-Object System.Drawing.Point(294,185)
	$custom7.TabIndex = 9
	#
	# custom6
	#
	$custom6.Size = New-Object System.Drawing.Size(300,20)
	$custom6.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom6.Name = "custom6"
	$custom6.Location = New-Object System.Drawing.Point(294,159)
	$custom6.TabIndex = 8
	#
	# custom5
	#
	$custom5.Size = New-Object System.Drawing.Size(300,20)
	$custom5.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom5.Name = "custom5"
	$custom5.Location = New-Object System.Drawing.Point(294,133)
	$custom5.TabIndex = 7
	#
	# custom4
	#
	$custom4.Size = New-Object System.Drawing.Size(300,20)
	$custom4.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom4.Name = "custom4"
	$custom4.Location = New-Object System.Drawing.Point(294,107)
	$custom4.TabIndex = 6
	#
	# custom3
	#
	$custom3.Size = New-Object System.Drawing.Size(300,20)
	$custom3.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom3.Name = "custom3"
	$custom3.Location = New-Object System.Drawing.Point(294,81)
	$custom3.TabIndex = 5
	#
	# custom2
	#
	$custom2.Size = New-Object System.Drawing.Size(300,20)
	$custom2.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom2.Name = "custom2"
	$custom2.Location = New-Object System.Drawing.Point(294,55)
	$custom2.TabIndex = 4
	#
	# custom1
	#
	$custom1.Size = New-Object System.Drawing.Size(300,20)
	$custom1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$custom1.Name = "custom1"
	$custom1.Location = New-Object System.Drawing.Point(294,29)
	$custom1.TabIndex = 3
	#
	# label2
	#
	$label2.TabIndex = 2
	$label2.Size = New-Object System.Drawing.Size(100,19)
	$label2.Text = "Custom Attribute 1"
	$label2.Location = New-Object System.Drawing.Point(173,32)
	$label2.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label2.Name = "label2"
	#
	# listbox1
	#
	$listbox1.FormattingEnabled = $True
	$listbox1.Size = New-Object System.Drawing.Size(155,420)
	$listbox1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$listbox1.Name = "listbox1"
	$listbox1.Location = New-Object System.Drawing.Point(12,29)
	$listbox1.Sorted = $True
	$listbox1.TabIndex = 0
	$listbox1.add_SelectedIndexChanged($handler_listbox1_SelectedIndexChanged)
	#
	# label1
	#
	$label1.TabIndex = 1
	$label1.Size = New-Object System.Drawing.Size(174,23)
	$label1.Text = "Please select a user:"
	$label1.Location = New-Object System.Drawing.Point(12,9)
	$label1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation 
	$label1.Name = "label1"
	#endregion Generated Form Code

	#----------------------------------------------

	#Save the initial state of the form
	$InitialFormWindowState = $form1.WindowState
	#Init the OnLoad event to correct the initial state of the form
	$form1.add_Load($Form_StateCorrection_Load)
	#Show the Form
	return $form1.ShowDialog()

} #End Function

#Call OnApplicationLoad to initialize
if(OnApplicationLoad -eq $true)
{
	#Create the form
	GenerateForm | Out-Null
	#Perform cleanup
	OnApplicationExit
}

Enjoy!

You can leave a response, or trackback from your own site.

3 Responses to “Exchange Custom Attribute editor with GUI, written in Powershell”

  1. gmickelsen says:

    Had some problems running this script. I’m getting-
    “At C:\Temp\AD_ExtAttribs.ps1:451 char:21
    + if(OnApplicationLoad <<<< -eq $true)
    + CategoryInfo : ObjectNotFound: (OnApplicationLoad:String) [], CommandNotFoun
    dException
    + FullyQualifiedErrorId : CommandNotFoundException"

    Am I doing something wrong?

    I'm certainly no PowerShell guy

    Thanks

  2. sovath says:

    It’s cool! How can I download and use this tool?

    Thanks,
    Sovath

  3. Shaun says:

    Anyone have any luck getting this to run? This is exactly what i’ve been looking for in our environment, but getting the OnApplicationLoad error also.

Leave a Reply