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 "TestSVR1adamadmin",$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:ADAMAdminADAM_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> </td><td colspan=2>") $createbutton.RenderControl($writer) $writer.Write(" ") $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