July 1st, 2009
Uncategorized
dmuegge
no comments
I ran across a useful post today as I was roaming through Google Analytics.
Using PowerShell, LogParser and PowerGadgets to get Exchange 2003 storage information – Part 1
Wes Stahler uses Log Parser and PowerShell to report on the free space in an Exchange Database.
This is a task I have done in the past. I will add this script to my toolkit.
Regards,
Dave
May 10th, 2009
Uncategorized
dmuegge
7 comments
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> </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
March 20th, 2009
Uncategorized
dmuegge
3 comments
Welcome!
This is a little trick some might find useful. I was working on decommissioning some servers and I needed a way to find out what was connecting to these machines. I decided to create a script to log connections. I have done this in the past in various ways which usually involved logging a bunch of data and then querying against it to find the unique connections.
This time it finally occurred to me, just filter the data as it is being collected. So I set out to write a PowerShell script that would keep a running list of client TCP connections to a given machine. This information would be stored in a text file.
The first step was to collect the information and put it into a PowerShell object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # Create array to hold netstat data
$allnetstatdata = @()
# Get TCP connections from netstat
$netstatResults = & netstat -p TCP
foreach($line in $netstatResults){
# Create object data and add to object
$netstatdata = "" | Select local,port,foreign
if(-not (($line.Trim() -eq [String]::Empty) -or ($line.contains("Active Connections")) -or ($line.contains("Local Address")))){
if ($line -match '\s*(TCP)\s{1,}(\D\S{1,})\s{1,}(\D\S{1,})\s{1,}(\D\S{1,}$)'){
$localhost = $matches[2].Split(":")
$netstatdata.local = $dchost[0]
$netstatdata.port = $dchost[1]
$foreignhost = $matches[3].Split(":")
$netstatdata.foreign = $foreignhost[0]
$allnetstatdata = $allnetstatdata + $netstatdata
}
}
} |
Then the next step was to read the file with the previous information and add it to the PowerShell object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Define Log File
$logfile = C:\TCPConnections.txt
# Get data from file and add to object
$filedata = Get-Content $logfile
if($filedata){
foreach($line in $filedata){
$netstatdata = "" | Select local,port,foreign
$entry = $line.Split("`t")
$netstatdata.port = $entry[0]
$netstatdata.local = $entry[1]
$netstatdata.foreign = $entry[2]
$allnetstatdata = $allnetstatdata + $netstatdata
}
} |
We can now remove the duplicates from the combined information and save the updated file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Get unique rows
$newnetstatdata = $allnetstatdata | Select-Object * -unique
# Add combined data to string
$tempcontent = New-Object System.Text.StringBuilder
foreach($netstat in $newnetstatdata){
if($netstat.port){$tempcontent.Append($netstat.port.ToString()) | Out-Null}
$tempcontent.Append("`t") | Out-Null
if($netstat.local){$tempcontent.Append($netstat.local.ToString()) | Out-Null}
$tempcontent.Append("`t") | Out-Null
if($netstat.foreign){$tempcontent.Append($netstat.foreign.ToString()) | Out-Null}
$tempcontent.Append("`n") | Out-Null
}
# Write to file
Set-Content -path $logfile $tempcontent.ToString() |
We can run this script in a scheduled task at whatever interval is required. Now we have a log of unique inbound TCP connections.
Best Regards,
Dave