IT Eclectia - A variety technical topics and tips.

ADAM Administration with SharePoint and PowerShell

Welcome!

Recently I worked on finding a simple way to create a web based administrative interface for an ADAM directory. The requirements were to create a simple web based interface to allow business personnel to manage users and groups for an application directory. It was also desirable if this solution would easily integrate with SharePoint.

After doing a little searching on the web, I found a combination that fit the bill.

The Quest AD Management Shell CmdLets – This is a PowerShell Snap-In that allows administration of AD and ADAM. The cmdlets are from Quest Software you can find more info here. I have used them in other scripts and they have come in very handy. To make these work in this solution from SharePoint, the Quest Snapin .dll and it’s dependants need to be copied to the global assembly cache and entered as a safecontrol in the sharepoint web.config.

The iLoveSharePoint PowerWebPart 3.0 – This is a web part which allows the execution of PowerShell code from the web part. This web part is from the CodePlex project iLoveSharePoint by Christian Glessner. I was impressed with this web part. It is easy to install and configure and relatively simple to use.

The PowerWebPart allows you to execute scripts that will render asp.net web controls in the web part. This allows you to retrieve user input from the controls to use as script inputs. The possibilities are endless. For my purposes I only needed a very simple user interface.

I wanted a way to use this for different ADAM partitions so I tried to allow for different configuration scripts. The design I decided on consisted of three levels of scripts one for configuration one for data access and one UI script for each web part.

The code sample below is the configuration and connection script. This script defines the user and group containers and the directory connect and disconnect functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# ---------------------------------------------------------------------------
### <Library name='ADAM_Config_Lib.ps1'>
### <Author>David Muegge</Author>
### <Description>
### 	Adam connection and configuration library
### </Description>
### <Dependencies>
###	Quest AD CmdLets 1.2
### </Dependencies>
### </Library>
# ---------------------------------------------------------------------------
$SnapInName = "Quest.ActiveRoles.ADManagement"
$testsnapin = $null
$testsnapin = get-pssnapin | where { $_.Name -eq $SnapInName}
if(-not $testsnapin){add-pssnapin -Name $SnapInName}
 
# Container paths
$usercontainer = "cn=Users,cn=ADAMDEV"
$groupcontainer = "cn=Groups,cn=ADAMDEV"
 
 
function connect-ADAM{
 
	# This allows the use of a windows account for ADAM athentication without granting the application pool account rights to ADAM
	$passwd = Get-Content "C:\testpwd.txt" | convertto-securestring
	$adamcred = new-object -typename System.Management.Automation.PSCredential -argumentlist "TestSVR1\adamadmin",$passwd
 
	connect-QADService -Service localhost -Credential $adamcred
 
 
}
 
function disconnect-ADAM{
 
	param($adamconnection)
 
	Disconnect-QADService -Connection $adamconnection
 
}

The next script is the function library for data access to the ADAM directory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# ---------------------------------------------------------------------------
### <Library name='ADAM_Lib.ps1'>
### <Author>David Muegge</Author>
### <Description>
### 	Adam directoy function library
### </Description>
### <Dependencies>
###	Quest AD CmdLets 1.2
### </Dependencies>
### </Library>
# ---------------------------------------------------------------------------
function get-Users{
 
	$adamconnection = connect-ADAM
	$results = get-QADObject -SearchRoot $usercontainer -Connection $adamconnection
	disconnect-ADAM -adamconnection $adamconnection
	return $results
 
 
}
 
 
function get-Groups{
 
	$adamconnection = connect-ADAM
	$results = get-qadgroup -SearchRoot $groupcontainer -Connection $adamconnection
	disconnect-ADAM -adamconnection $adamconnection
	return $results
 
 
}
 
 
function new-User{
 
	param([String]$logonid)
 
	# Random password generator here
	$newpassword = "password123$"
 
	$adamconnection = connect-ADAM
	New-QADUser -Name $newlogonid -UserPassword $newpassword -ParentContainer $usercontainer -Connection $adamconnection
	disconnect-ADAM -adamconnection $adamconnection
 
}
 
function delete-user{
 
	param([String]$logonid)
 
	$adamconnection = connect-ADAM
	$UserDN = "CN=$logonID," + $usercontainer
	Remove-QADObject -Identity $UserDN -Connection $adamconnection
	disconnect-ADAM -adamconnection $adamconnection
 
}
 
 
function new-Group{
 
	param([String]$groupid)
 
	$adamconnection = connect-ADAM
	New-QADGroup -Name $groupid -GroupType "Default" -ParentContainer $groupcontainer -Connection $adamconnection
	disconnect-ADAM -adamconnection $adamconnection
}
 
 
function delete-group{
 
	param([String]$groupid)
 
	$adamconnection = connect-ADAM
	$GroupDN = "CN=$groupid," + $groupcontainer
	Remove-QADObject -Identity $GroupDN -Connection $adamconnection
	disconnect-ADAM -adamconnection $adamconnection
 
}
 
 
function Add-UserToGroup{
 
	param([string]$username,[String]$groupname)
 
	$adamconnection = connect-ADAM
	# Get user dn
	$results = Get-QADUser -Name $username -Connection $adamconnection
	foreach($result in $results){$userdn = $result.dn.ToString()}
 
	# Get Group DN
	$results = Get-QADGroup -Name $groupname -Connection $adamconnection
	foreach($result in $results){$groupdn = $result.dn.ToString()}
 
	# Add User to Group
	Add-QADGroupMember -Identity $groupdn -Member $userdn -Connection $adamconnection
	disconnect-ADAM -adamconnection $adamconnection
 
}

The next script is an example of a UI script for the web part. When a new PowerWebPart is created a template script is added by default. This script provides a framework and some sample code. Christian also has an add-on which allows you to use PowerGui to edit your script from SharePoint. The entire solution contains one script similar to this for each web part.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
########### Initialize ############
. c:\ADAMAdmin\ADAM_Lib.ps1
 
### declare global variables and functions
$groupnametext = New-Object System.Web.UI.WebControls.TextBox
$createbutton = New-Object System.Web.UI.WebControls.Button
$groupnamelabel = New-Object System.Web.UI.WebControls.Label
$deletebutton = New-Object System.Web.UI.WebControls.Button
 
 
############## Load ##############
 
### first time the OnLoad fires before CreateChildControls
#function OnLoad
#{
#	# Check if GET Request (first request). 
#	if($isPostBack -eq $false)
#	{
#		$label.Text = 'GET request.'
#	}
#}
 
######## 3. Create Controls ########
 
## create child controls
function CreateChildControls($controls)
{
	$controls.Add($groupnametext)	
 
	$createbutton.Text = 'Add Group'
	Subscribe-Event $createbutton 'Click' 'OnCreateButtonClicked'
  	$controls.Add($createbutton)
 
	$deletebutton.Text = 'Delete Group'
	Subscribe-Event $deletebutton 'Click' 'OnDeleteButtonClicked'
  	$controls.Add($deletebutton)
 
	$groupnamelabel.Text = "Groupname"
	$controls.Add($groupnamelabel)
}
 
######## Events ########
 
## handle control events
## subscribe to an event with "Subscribe-Event($control, 'eventName','callback function name')"
function OnCreateButtonClicked($sender, $Args)
{
 
   $newgroupid = $groupnametext.text
   # Create new group
   new-Group -groupid $newgroupid
   $groupnametext.text = [string]::Empty
 
 
}
 
function OnDeleteButtonClicked($sender, $Args)
{
 
   $newgroupid = $groupnametext.text
   # Delete group
   Remove-Group -groupid $newgroupid
   $groupnametext.text = [string]::Empty
 
 
}
 
########## Render  #########
 
### render html
function Render($writer)
{
    $writer.Write("<table><tr><td>")
	$groupnamelabel.RenderControl($writer)
	$writer.Write("</td><td>")		
	$groupnametext.RenderControl($writer)
	$writer.Write("</td></tr><tr><td>&nbsp</td><td colspan=2>")
  	$createbutton.RenderControl($writer)
	$writer.Write("&nbsp")
	$deletebutton.RenderControl($writer)
  	$writer.Write("</td><td></td></tr></table>")
 
}
 
######### Error Handling #########
 
### render custom error message
##function OnError($exception, $writer){}
 
########## Unload #########
 
### clean up
##function OnUnload()
##{
##}

The screenshot below shows the complete solution. This method was simple, effective and easy to create. I dot sourced the corresponding web part script and the connection script in each web part.

This is a pretty quick and easy way to expose some simple administrative or user functionality on a SharePoint Intranet.

I hope this helps.

Regards,

Dave

7 Comments

rssComments RSS transmitTrackBack Identifier URI


Hi David,
I’m pleased to see that you like Power WebPart :-)
If your interested I can link your post on the CodePlex page.

Bye,Christian

Comment by Christian Glessner on June 12, 2009 6:28 am


Christian,

I appreciate your contribution. I know a few other places I am going to use it in the future.

Sure, a link to my post would be great.

Thanks,

Dave

Comment by dmuegge on June 12, 2009 7:49 am


Hi,

I stll trying to install your ADAM Administration with SharePoint and PowerShell sloution.

Could you explain how to install the quest dll to GAC and how to set as a safecontrol in the sharepoint web.config?

Many thanks in advanced.

Greetings

Martin

Comment by Martin on November 23, 2009 4:11 pm


Martin,

To GAC the Quest DLL you must drag and drop copy the dll from it’s installed location into the %windir%\assembly directory.
You can also use the regasm tool from the .Net framework SDK. Instructions for this method are on MSDN.

To set a safe control in sharepoint you need to add entries like below to the section of the web config. There should be other entries there already.

1
2
<SafeControl Assembly="iLoveSharePoint.WebControls.PowerWebPart, Version=3.0.0.0, Culture=neutral, PublicKeyToken=7f77686204a6dd39" Namespace="iLoveSharePoint.WebControls" TypeName="*" Safe="True" />
<SafeControl Assembly="Quest.ActiveRoles.ArsPowerShellSnapIn, Version=1.1.0.0, Culture=neutral, PublicKeyToken=37ba620bec38a887" Namespace="Quest.ActiveRoles" TypeName="*" Safe="True" />

Thanks,

Dave

Comment by dmuegge on November 29, 2009 10:29 am


When i add ilovesharepoint (power web part v3.0) on the site it is giving an error “Error on Initialization Exception: Requested registry access is not allowed” for non-admin user. It is giving the error for plain web part, which is downloded from http://ilovesharepoint.codeplex.com/releases/view/18883
And it is running for server administrator fine.

Could you update me on this ASAP. It is little urgent.

Comment by Murali on February 12, 2010 10:48 am


Murali,

Without knowing details about your installation. I can only guess at the issue.

I would check to make sure the control was GAC’d properly and also added to the safecontrols in the SharePoint Web.config. There is some information on this in the comments on this post.

It is also possible there are some permissions problems in SharePoint or the application eventlog registry key, which gets created for each .Net application was not created properly.

I hope this helps point you in the right direction.

Thanks,

Dave

Comment by dmuegge on February 12, 2010 7:06 pm


Dave,

Everything is updated as specified in iLoveSharePoint package’s readme.txt file And it is working fine for sharepoint server administrators..
The below error is simply shown on the webpart itself, it is not added in event log.
The error message appears while displaying the plain web part, without any custom script.

“Error on Initialization Exception: Requested registry access is not allowed”

Let me know if you need any more details on this issue.

Thanks,
Murali

Comment by Murali on February 16, 2010 9:09 am

addLeave a comment