Tuesday, April 03, 2007

Tracking Permission Changes to Mailbox rights and Send As – Receive As ACE’s in Exchange

First up this script is not designed to audit who is making changes to permissions in Exchange. Tracking who is making changes to Active Directory objects in a distributed Network with multiple DC’s is not an easy thing to do my advice is if you need to do this hit the Google trail or look at third party products.

What this script does is give visibility of permission changes to users mailboxes/accounts made via ADUC via Exchange Mailbox Rights and Send-As/Receive as rights on the user object. It basically works by creating an XML file that is a snapshot of the current explicitly added rights on an Exchange Mailbox and any ACE’s that grant the extended rights for send and receive as. The next time the script runs it takes another snapshot of the rights and then using a couple of Scripting Dictionary object s does a comparison and finds Add ,Deletes or Permission changes and then produces a HTML report of these changes. To extend the usefulness of this script I’ve created a version that creates a WMI watcher on any ds_user modification events on a Domain controller. When a modification is detected it uses the IADstools to check the metadata in the directory to see if any of the security attributes have been modified recently an if so then does a snapshot compare to see if picks up any ACE’s changes. Any ACE changes that are found are then emailed to an emailaddress as a Htmlreport. This starts to get close to real-time reporting of changes. Now in a large network maybe you don’t want to be doing this because of the number of ds_user modification events you might receive could possible have a detrimental performance effect on the DC is question (eg don’t know really haven’t tested it)

The script itself is split up into a few different sections the first section does file management. To maintain an audit path every snap that is taken is stored so when the script has been run more then 2 times the 1st snap that is taken is then copied to an archive directory. The second section of the script handles opening, searching and comparing the different snapshots that are taken. I’ve used the Microsoft Dom object to do this although not the easiest thing in the world to use it is good for this type of data retrieval. The last section of the script is dedicated to writing the snapshot because the format of the xml was pretty simple I’ve just used the FSO item to write the XML manually.

To use the script you should first check the following 4 variables and make sure the directories that variable refers to exists.

csCurrentSnapFileName = "c:\temp\currentSnap.xml"
psPreviousSnapFileName = "c:\temp\prevSnap.xml"
adArchieveDirectory = "c:\temp\SnapArchive\"
rfReportFileName = "c:\temp\ACLChangeReport-"

I’ve created two versions of the script the first is a simple version that is designed to be run from a scheduler and just looks for changes against the last snap every time its run and then writes a HTML report to the configured directory if any changes are detected. The second version is WMI watcher script that watches for changes to the ds_user class on the server and then emails a configured address with a report of any changes.
For this version of the script there are three variables that need to be configured first for email functionality section.

SenderAddress = "sender@domain.com"
RecieverAddress = "reciever@domain.com"
EmailServername = “servername”

The script itself takes one commandline parameter which is the netbios name of the DC you want to run it against. The WMI version also requires that you have the Windows 2000/3 Support Tools installed so you will have the iadstools.dll registered. The other things to be aware of is there a 15 minute change detection period depending on the replication latency in your network you may need to make this greater.

If DateDiff("n",reformatdate(objIadsTools.MetaDataLastWriteTime(count)),Now()) < 15 Then fsnap = 1

I’ve put a downloadable copy of the script here the wmi version of the script looks like

Const RIGHT_DS_DELETE = &H10000
Const RIGHT_DS_READ = &H20000
Const RIGHT_DS_CHANGE = &H40000
Const RIGHT_DS_TAKE_OWNERSHIP = &H80000
Const RIGHT_DS_MAILBOX_OWNER = &H1
Const RIGHT_DS_SEND_AS = &H2
Const RIGHT_DS_PRIMARY_OWNER = &H4

csCurrentSnapFileName = "c:\temp\currentSnap.xml"
psPreviousSnapFileName = "c:\temp\prevSnap.xml"
adArchieveDirectory = "c:\temp\SnapArchive\"
rfReportFileName = "c:\temp\ACLChangeReport-"

SenderAddress = "sender@domain.com"
RecieverAddress = "receiver@domain.com"
EmailServername = "mailserver"

strComputer = wscript.arguments(0)

Set fso = CreateObject("Scripting.FileSystemObject")
set objIadsTools = CreateObject("IADsTools.DCFunctions")
Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/directory/LDAP")
strWQL = "SELECT * " & _
"FROM __InstanceModificationEvent " & _
"WITHIN 2 " & _
"WHERE TargetInstance ISA 'ds_user'"
WScript.Echo "Waiting User Modifications"
Set objEventSource = objWMIService.ExecNotificationQuery(strWQL)
Do
Set objEventObject = objEventSource.NextEvent()
WScript.Echo "User Modified : " & objEventObject.TargetInstance.DS_displayName
Call getUserData(strComputer,objEventObject.TargetInstance.DS_distinguishedName)
Loop

sub getUserData(dcDomainController,dnUserDN)
fsnap = 0
intRes = objIadsTools.GetMetaData(Cstr(dcDomainController),Cstr(dnUserDN),0)
if intRes = -1 then
Wscript.Echo objIadsTools.LastErrorText
WScript.Quit
end if
wscript.echo "User" & dnUserDN
wscript.echo Now()
for count = 1 to intRes
Select Case objIadsTools.MetaDataName(count)
Case "nTSecurityDescriptor" wscript.echo "nTSecurityDescriptor LastModified : "
& objIadsTools.MetaDataLastWriteTime(count)_
& " Time Diff : " &
DateDiff("n",reformatdate(objIadsTools.MetaDataLastWriteTime(count)),Now())
If DateDiff("n",reformatdate(objIadsTools.MetaDataLastWriteTime(count)),Now()) <
15 Then fsnap = 1
Case "msExchMailboxSecurityDescriptor" wscript.echo "msExchMailboxSecurityDescriptor
Last Modified : " _
& objIadsTools.MetaDataLastWriteTime(count) & " Time Diff : " &
DateDiff("n",reformatdate(objIadsTools.MetaDataLastWriteTime(count)),Now())
If DateDiff("n",reformatdate(objIadsTools.MetaDataLastWriteTime(count)),Now()) <
15 Then fsnap = 1
End Select
Next
If fsnap = 1 Then CheckACLs

end Sub

Sub CheckACLs()

rrRightReport = 0
If fso.FileExists(csCurrentSnapFileName) Then
wscript.echo "Snap Exists"
If fso.FileExists(psPreviousSnapFileName) Then
fso.deletefile(psPreviousSnapFileName)
fso.movefile csCurrentSnapFileName, psPreviousSnapFileName
set xdXmlDocument = CreateObject("Microsoft.XMLDOM")
xdXmlDocument.async="false"
xdXmlDocument.load(psPreviousSnapFileName)
Set xnSnaptime = xdXmlDocument.selectNodes("//SnappedACLS")
For Each exSnap In xnSnaptime
oldSnap = exSnap.attributes.getNamedItem("SnapDate").nodeValue
wscript.echo "Snap Taken : " & oldSnap
takesnap
afFileName = adArchieveDirectory &
Replace(Replace(Replace(exSnap.attributes.getNamedItem("SnapDate").nodeValue,":",""),",",""),"
","") & ".xml"
wscript.echo "Archiving Old Snap to : " & afFileName
fso.copyfile psPreviousSnapFileName, afFileName
Next
set xdXmlDocument1 = CreateObject("Microsoft.XMLDOM")
xdXmlDocument1.async="false"
xdXmlDocument1.load(csCurrentSnapFileName)
Set ckCurrentPerms = CreateObject("Scripting.Dictionary")
Set pkPreviousPerms = CreateObject("Scripting.Dictionary")
Set xnCurrentPermsUsers = xdXmlDocument1.selectNodes("//User")
For Each xnUserNode In xnCurrentPermsUsers
unUserName = xnUserNode.attributes.getNamedItem("SamaccountName").nodeValue
For Each caACLs In xnUserNode.ChildNodes
ckCurrentACL = unUserName & "|-|" &
caACLs.attributes.getNamedItem("User").nodeValue
ckCurrentPerms.add ckCurrentACL,
caACLs.attributes.getNamedItem("Right").nodeValue
Next
Next
Set xnPrevPermsUsers = xdXmlDocument.selectNodes("//User")
For Each xnUserNode1 In xnPrevPermsUsers
unUserName1 = xnUserNode1.attributes.getNamedItem("SamaccountName").nodeValue
For Each caACLs1 In xnUserNode1.ChildNodes
pkPrevACL = unUserName1 & "|-|" &
caACLs1.attributes.getNamedItem("User").nodeValue
pkPreviousPerms.add pkPrevACL,
caACLs1.attributes.getNamedItem("Right").nodeValue
rem Do a Check for Any Deleted or Changed Permisssions
If ckCurrentPerms.exists(pkPrevACL) Then
If ckCurrentPerms(pkPrevACL) <>
caACLs1.attributes.getNamedItem("Right").nodeValue Then
rrRightReport = 1
wscript.echo "Found Changed ACL "
wscript.echo "Old Rights : " & pkPrevACL & " " &
caACLs1.attributes.getNamedItem("Right").nodeValue
wscript.echo "New Rights : " & pkPrevACL & " " & ckCurrentPerms(pkPrevACL)
hrmodHtmlReport = hrmodHtmlReport & "<tr><td><font face=""Arial""
color=""#000080"" size=""2"">" & unUserName1 & " </font></td>" & vbcrlf
hrmodHtmlReport = hrmodHtmlReport & "<td><font face=""Arial"" color=""#000080""
size=""2"">Old Rights: " & caACLs1.attributes.getNamedItem("User").nodeValue _
& " " & caACLs1.attributes.getNamedItem("Right").nodeValue & " </font></td>" &
vbcrlf
hrmodHtmlReport = hrmodHtmlReport & "<td><font face=""Arial"" color=""#000080""
size=""2"">New Rights: " _
& caACLs1.attributes.getNamedItem("User").nodeValue & " " &
ckCurrentPerms(pkPrevACL) & " </font></td></tr>" & vbcrlf
End if
Else
rrRightReport = 1
hrDelHtmlReport = hrDelHtmlReport & "<tr><td><font face=""Arial""
color=""#000080"" size=""2"">" & unUserName1 & " </font></td>" & vbcrlf
hrDelHtmlReport = hrDelHtmlReport & "<td><font face=""Arial"" color=""#000080""
size=""2"">" & caACLs1.attributes.getNamedItem("User").nodeValue _
& " " & caACLs1.attributes.getNamedItem("Right").nodeValue & "
</font></td></tr>" & vbcrlf
Wscript.echo "Found Deleted ACL : " & pkPrevACL & " " &
caACLs1.attributes.getNamedItem("Right").nodeValue
End if
Next
Next
rem Do forward check of ACL's
For Each dkCurrenPermKey In ckCurrentPerms.keys
If Not pkPreviousPerms.exists(dkCurrenPermKey) Then
rrRightReport = 1
dknewpermarry = Split(dkCurrenPermKey,"|-|")
hrnewHtmlReport = hrnewHtmlReport & "<tr><td><font face=""Arial""
color=""#000080"" size=""2"">" & dknewpermarry(0) & " </font></td>" & vbcrlf
hrnewHtmlReport = hrnewHtmlReport & "<td><font face=""Arial"" color=""#000080""
size=""2"">" & dknewpermarry(1) _
& " " & ckCurrentPerms(dkCurrenPermKey) & " </font></td></tr>" & vbcrlf
Wscript.echo "Found new ACL : " & dkCurrenPermKey & " " &
ckCurrentPerms(dkCurrenPermKey)
End if
next
Else
wscript.echo "No current permissions snap exists taking snap"
Call TakeSnap
End If
If rrRightReport = 1 Then
wscript.echo "Writing Report"
hrHtmlReport = "<html><body>" & vbcrlf
NewSnapDate = WeekdayName(weekday(now),3) & ", " & day(now()) & " " &
Monthname(month(now()),3) & " " & year(now()) & " " & formatdatetime(now(),4) &
":00"
hrHtmlReport = hrHtmlReport & "<p><font size=""4"" face=""Arial Black""
color=""#008000"">Change To Mailbox Rights Report for Snaps Taken Between -
</font>" & oldSnap & " and "_
& NewSnapDate & "</font></p>" & vbcrlf
If hrnewHtmlReport <> "" Then
hrHtmlReport = hrHtmlReport & "<p><font face=""Arial"" color=""#000080""
size=""2"">ACL's Added</font></p>"
hrHtmlReport = hrHtmlReport & "<table border=""1"" width=""100%"" id=""table1""
cellspacing=""0"" cellpadding=""0"" bordercolor=""#000000"">"
hrHtmlReport = hrHtmlReport &
Replace(Replace(hrnewHtmlReport,"-exra-",""),"-exsa-","") & "</table>"
End If
If hrmodHtmlReport <> "" Then
hrHtmlReport = hrHtmlReport & "<p><font face=""Arial"" color=""#000080""
size=""2"">ACL's Modified</font></p>"
hrHtmlReport = hrHtmlReport & "<table border=""1"" width=""100%"" id=""table1""
cellspacing=""0"" cellpadding=""0"" bordercolor=""#000000"">"
hrHtmlReport = hrHtmlReport &
Replace(Replace(hrmodHtmlReport,"-exra-",""),"-exsa-","") & "</table>"
End If
If hrDelHtmlReport <> "" Then
hrHtmlReport = hrHtmlReport & "<p><font face=""Arial"" color=""#000080""
size=""2"">ACL's Deleted</font></p>"
hrHtmlReport = hrHtmlReport & "<table border=""1"" width=""100%"" id=""table1""
cellspacing=""0"" cellpadding=""0"" bordercolor=""#000000"">"
hrHtmlReport = hrHtmlReport &
Replace(Replace(hrDelHtmlReport,"-exra-",""),"-exsa-","") & "</table>"
End If
hrHtmlReport = hrHtmlReport & "</body></html>" & vbcrlf
Set objEmail = CreateObject("CDO.Message")
objEmail.From = SenderAddress
objEmail.To = RecieverAddress
objEmail.Subject = "ACL Change Report"
objEmail.htmlbody = hrHtmlReport
objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing")
= 2
objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver")
= EmailServername
objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport")
= 25
objEmail.Configuration.Fields.Update
objEmail.Send
wscript.echo "Email Sent"
End If

End Sub

Sub TakeSnap

set wfile = fso.opentextfile(csCurrentSnapFileName,2,true)
wfile.writeline("<?xml version=""1.0""?>")
wfile.writeline("<SnappedACLS SnapDate=""" & WeekdayName(weekday(now),3) & ", "
& day(now()) & " " & Monthname(month(now()),3) & " " & year(now()) & " " &
formatdatetime(now(),4) & ":00" & """>")

Set objSystemInfo = CreateObject("ADSystemInfo")
strdname = objSystemInfo.DomainShortName
set conn1 = createobject("ADODB.Connection")
strConnString = "Data Provider=NONE; Provider=MSDataShape"
conn1.Open strConnString
set conn = createobject("ADODB.Connection")
set com = createobject("ADODB.Command")
Set iAdRootDSE = GetObject("LDAP://RootDSE")
strNameingContext = iAdRootDSE.Get("defaultNamingContext")
Conn.Provider = "ADsDSOObject"
Conn.Open "ADs Provider"
Query = "<LDAP://" & strNameingContext & ">;(&(&(& (mailnickname=*) (|
(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*)))
))));samaccountname,displayname,distinguishedName;subtree"
Com.ActiveConnection = Conn
Com.CommandText = Query
Com.Properties("Page Size") = 1000
Set Rs = Com.Execute
While Not Rs.EOF
dn = "LDAP://" & replace(rs.Fields("distinguishedName").Value,"/","\/")
set objuser = getobject(dn)
Set oSecurityDescriptor = objuser.Get("msExchMailboxSecurityDescriptor")
Set oUserSecurityDescriptor = objuser.Get("ntSecurityDescriptor")
Set oUserdacl = oUserSecurityDescriptor.DiscretionaryAcl
Set oUserace = CreateObject("AccessControlEntry")
Set dacl = oSecurityDescriptor.DiscretionaryAcl
Set ace = CreateObject("AccessControlEntry")
fwFirstWrite = 0
For Each ace In dacl
if ace.AceFlags <> 18 then
if ace.Trustee <> "NT AUTHORITY\SELF" Then
If fwFirstWrite = 0 Then
wfile.writeline(" <User SamaccountName=""" & rs.fields("samaccountname") &
""">")
fwFirstWrite = 1
End if
wfile.writeline("<ACE User=""" & ace.Trustee & """ Right=""" &
getRights(ace.AccessMask) & """></ACE>")
end if
end if
Next
For Each oUserace In oUserdacl
if lcase(oUserace.ObjectType) = "{ab721a54-1e2f-11d0-9819-00aa0040529b}" and
oUserace.AceType = 5 Then
if oUserace.Trustee <> "NT AUTHORITY\SELF" and oUserace.AceFlags <> 6 Then
if fwFirstWrite = 0 Then
wfile.writeline(" <User SamaccountName=""" & rs.fields("samaccountname") &
""">")
fwFirstWrite = 1
End If
wfile.writeline("<ACE User=""" & oUserace.Trustee & "-exsa-" & """ Right=""Send
As""></ACE>")
end if
end if
if lcase(oUserace.ObjectType) = "{ab721a56-1e2f-11d0-9819-00aa0040529b}" and
oUserace.AceType = 5 Then
if oUserace.Trustee <> "NT AUTHORITY\SELF" and oUserace.AceFlags <> 6 then
If fwFirstWrite = 0 Then
wfile.writeline(" <User SamaccountName=""" & rs.fields("samaccountname") &
""">")
fwFirstWrite = 1
End If
wfile.writeline("<ACE User=""" & oUserace.Trustee & "-exra-" & """
Right=""Recieve As""></ACE>")
end if
end if
Next

If fwFirstWrite = 1 then
wfile.writeline("</User>")
End if
rs.movenext
Wend
wfile.writeline("</SnappedACLS>")
wscript.echo "New Snap Taken"

End Sub

Function getRights(hvHexValue)
If (hvHexValue And RIGHT_DS_SEND_AS) Then
getRights = "Send As"
End If
If (hvHexValue And RIGHT_DS_CHANGE) Then
getRights = "Modify user attributes"
End If
If (hvHexValue And RIGHT_DS_DELETE) Then
getRights = "Delete mailbox store"
End If
If (hvHexValue And RIGHT_DS_READ) Then
getRights = "Read permissions"
End If
If (hvHexValue And RIGHT_DS_TAKE_OWNERSHIP) Then
getRights = "Take Ownership"
End If
If (hvHexValue And RIGHT_DS_MAILBOX_OWNER) Then
getRights = "Mailbox Owner"
End If
If (hvHexValue And RIGHT_DS_PRIMARY_OWNER) Then
getRights = "Mailbox Primary Owner"
End If
End Function

Function reformatdate(dtDatetoTransform)
dtarry = split(dtDatetoTransform,"/")
tmArry = split(dtarry(2)," ")
rdReturnDate = formatdatetime(dateserial(tmArry(0),dtarry(0),dtarry(1)) & " " &
tmArry(1) & " " & tmArry(2))
reformatdate = rdReturnDate
End function

22 comments:

Gary said...

Glen,

I love this new script and love the site! I am trying to get the capturePermMods.vbs script to work and running into a small problem. The initial snapshot gets taken and written to XML no problem, but then i run into an error when taking the second snapshot. After the second snapshot is taken I get this error: CapturePermMods\capturePermMods.vbs(42, 7) Microsoft VBScript runtime error: This key is already associated with an element of this
collection.

Looking at the code on that line, i can't see anything that jumps out at me. Any suggestions?

Gary said...

A little more digging and I found the issue. It seems that it's possible to have two identical entries in the ACE record under a user. For example, if the sendas right is inherited from an parent OU and applied explicitly to the object. In that case, the second entry can't be added to the scripting dictionary. Just FYI.

Glen said...

Thanks Gary I'll do some testing next week and see if i can post a fix for the script. I appreciate the feedback

Cheers
Glen

Glen said...

Okay I've made a change to the download the filters delegated permission for send and receive as. basically filtering when the oUserace.AceFlags = 26 , this seems to fix the problem for me.

Cheers
Glen

Anonymous said...

When I look at the currentSnap I do not get all the records. Any reason why?

Glen said...

What do you mean by records do you mean you don't see all the ACE's that you expect or you don't see all your users ?. This script only tracks explicitly set ACE's and not inherited ACE's. So it wont be one to one for what you see in ADUC it will only include thoses ACE that have been explicitly added.

Anonymous said...

Glen

I like the script concept however I'm having trouble running it. I want to run the "simple" version that just compares one XML to another.

The first time it runs it creates a currentSnap.xml. the second time it runs it echoes "Snap Exists" and renames the file to prevSnap.xml and then exits.

I have added to debugging echoes and found that none of the "For" loops are being entered. I presume that my host can't perform "CreateObject("Microsoft.XMLDOM")" action.

Am I missing something?

Also you state on the post the following:

"To maintain an audit path every snap that is taken is stored so when the script has been run more then 2 times the 1st snap that is taken is then copied to an archive directory"

That doesn't match up with the following lines:

If fso.FileExists(psPreviousSnapFileName) Then fso.deletefile(psPreviousSnapFileName)


thanks,
Kevin

Glen said...

If you open up the XML file do you see anything getting written into to it. Are you running this on a Windows XP machine. You should have XMLDOM avaible maybe not on vista i haven't really tested it. What i think might be your problem is that maybe you have corrupted data being written to the XML file. You should be able to read the file in Internet exporer etc if you get a parse error then you know this is the problem. If this is the case then XMLDOM may not be able to parse this. This can happen if you have special characters in the SamaccountName. To get around this you just need to workout what the character is an escape it when its being written the the XML file.

The logic is a little wacky but what happens is that it always archives the last Snap. Eg when the script runs

It first deletes the file for the previous SNAP (the previous snap is the snap before the last snap)The last snap is still in the currentsnap file. So it deletes the previous snap. Copies the current snap to the previous snap.Takes a new snap and then it archives the previous snap file which was the old current snap file.The previous snap file was already archived the last time the script ran.

I admit it was poor variable name choice and maybe logic order but i m sure the logic itself stands up.

Cheers
Glen

Anonymous said...

Thanks for the response Glen.

I'm running XP and the XML is generated fine. I can read the XML file generated the first time without a problem. So the takesnap function works.

It is just the second time I run it the "If fso.FileExists(csCurrentSnapFileName) Then" condition is entered and the code just zips through without processing anything.

I added some of the following type checks through the code:

err.clear
xdXmlDocument.load(psPreviousSnapFileName)
if err <> 0 then wscript.echo "* Error: " & err.description & " " & err.number

but no errors are reported.

Cheers
Kevin

Glen said...

The script in the download didn't have any error checking in it if you remove the on error resume next do you get an line errors anywhere ?. Its strange i asked someone else to give the script a go who had never ran this and they didn't have a problem (although they just run it directly on their SBS server). the only thing that most people forget to do is create the snaparchive directory

One thing that might be worth trying is after the

xdXmlDocument.load(psPreviousSnapFileName)

line add

xdXmlDocument.save("c:\temp\tempsave.xml")

This will save whatever the XMLDom is parsing if you end up with a blank file then you know you have a parser problem.

Cheers
Glen

Anonymous said...

Hi Glen,

Thank you for posting this, it's been my first step into looking how to write scripts against the ntSecurityDescriptor and msExchMailboxSecurityDescriptor attributes.

I'm using this table as a reference:: http://www.microsoft.com/technet/scriptcenter/topics/security/adenums.mspx#EYBAC. When you're looking at the mailbox rights, you check aceflags is 18 (I think INHERITED_ACE & INHERIT_ACE) but when you're looking at the AD object rights it's 26 (I think INHERIT_ONLY_ACE , INHERITED_ACE & INHERIT_ACE). Can you explain why?

My second question, where did you get the constants for the Exchange rights, or is it just a case of applying them and then using a script to read and echo out what has been applied?

And finally, you define the RIGHT_DS_SEND_AS constant but use aceflag and the objecttype guid to see who has this right. You don't seem to use the constant, am I missing something?

Again, thanks for the script and any help.
Mark

Glen said...

I designed the script to only look at explicit rights and ignore and inherited rights so that why the checks are in place why I've used 26 and 18 it was due to problems i had when i implemented the script.To be honest i never really tracked it down. The script was built from hours of trial and error and represent what works for me. Its also a combination of other script so things like RIGHT_DS_SEND_AS is a carry over from http://support.microsoft.com/kb/252459.
Just sloppiness on my part.

When you dealing with extended rights (like SendAS and Recieve AS) you need to use Objecttype GUID

There is a section in the Exchange SDK that deals with Security and ACL's. The extended rights are documented on http://www.microsoft.com/technet/scriptcenter/topics/security/allrights.mspx.
I don't really know of a definitive source personally I've always had to work this stuff out from what i had available and then test it extensively.

Cheers
Glen

Jake said...

Getting the same thing...

CapturePermMods\capturePermMods.vbs(42, 7) Microsoft VBScript runtime error: This key is already associated with an element of this
collection.

Anyone have any updates on this? Would LOVE to use this script

Glen said...

It sound like there might a logic problem in the script when it running in your environment. That error means for some reason its finding a duplicate ACE. If you modify the for-next loop at line 45 like

For Each caACLs In xnUserNode.ChildNodes
ckCurrentACL = unUserName & "|-|" & caACLs.attributes.getNamedItem("User").nodeValue
if ckCurrentPerms.exists(ckCurrentACL) then
wscript.echo "***Duplicate ACL : " & ckCurrentACL
else
ckCurrentPerms.add ckCurrentACL, caACLs.attributes.getNamedItem("Right").nodeValue
end if
Next

This should mean it will skip over any duplicates it does find and it will also echo out any it does. It would be good to know why this error is occuring which would help me fix the logic in the script

Cheers
Glen

Jake said...

Thanks for the update Glen..

Here is what I am now getting after the change.

It does echo out a duplicate acl three times then throws the following error-

Line 71
Char 5
Object required: 'caACLs1'
800A01A8
VBruntime error...

The XML that is written looks good, and it does not have a problem with anything but the comparison

Here is the first line of the currentsnap.xml that it is having issues with...


SnappedACLS SnapDate="Fri, 28 Sep 2007 08:40:00">
- User SamaccountName="1econfrm">
ACE User="XXXXX\goodlinkadmin-exsa-" Right="Send As" />
ACE User="XXXXX\NxMbxMgt-exsa-" Right="Send As" />
ACE User="XXXXX\NxMbxMgt-exra-" Right="Recieve As" />
/User>
- User SamaccountName="1floormtg">
ACE User="XXXXX\NxMbxMgt-exsa-" Right="Send As" />
ACE User="XXXXX\NxMbxMgt-exra-" Right="Recieve As" />
ACE User="XXXXX\goodlinkadmin-exsa-" Right="Send As" />
/User>

- had to remove some characters to post the xml- mainly the < in front of the users

Glen said...

Its looks a little weird that part of the script i looping though a for next

For Each caACLs1 In xnUserNode1.ChildNodes

There shouldn't be a case where there calcls1 wouldn't exists unless something else is causing an issue eg maybe an invalid character in the xml file. Can you open the XML file successfully in Internet Explorer or do you get a parse error. A parse error would indicate a bad character in the XML which should be relatively easy to filter out.

The other thing you could do is put a

on error resume next

At the top of the script this mean its will skip over any errors and should produce some sort of output at the end.

Cheers
Glen

Jake said...

Glen,

Yes, the xml file is not having any problems with the parse.

I added the on error resume next , and all is working flawlessly.

THANKS FOR THE HELP!

Jake

Anonymous said...

Great idea for a script, but I'm having a problem getting the html report-- it never gets created, though the snaps are there. Any troubleshooting thoughts?

Glen said...

What type of domain structure do you have. Is there anything in the snap files are you seeing the changes you make reflected as differances in the snap file. Are they parasable , ar you running this on XP or Vista ?

Cheers
Glen

AK said...

Hi Glen-- we have one domain, tried running the vbs script on XP and 2k3. here's what happens:

1. run script. "no current permissions snap exists, taking snap" displays. CurrentSnap.xml created in c:\temp and shows all accounts with all send-as permissions. No files appear in c:\temp\SnapArchive\ or c:\temp\ACLChangeReport-

2. On the next run, "Snap Exists" displays, the currentsnap.xml gets deleted, and the script stops.

3. repeat steps with same results.

Paolo said...

Thank-you very much Glen. This script really helps us discover users with Send as rights.

Anonymous said...

Glen,

I got this error when I ran the WMI version on XP SP2 with Windows 2003 support tools.

Line: 18
Char: 1
Error: Subscript out of range
Code: 800A0009

I would appreciate if you could help me out with this error.

Thanks.