This script builds on a script I posted earlier in the year that produced a GUI that showed permissions and reverse permissions for Exchange Mailboxes (eg what other mailboxes a particular mailbox has access to). The previous version just looked at the Mailbox Rights and Send AS/Receive AS rights. This new version using Exchange Web Services looks at firstly the rights on the shared folders in a mailbox (eg Root,calendar,inbox,notes,task,journal) and also the Outlook Delegates and the rights assigned to the delegates such as Private Items access and Meeting recipients as well as all the other permissions it did previously. Sorry i haven't got the snapshot functionality done yet which i think i promised before but...
The cool thing is this script now lets us answer a bunch of new questions such as
Which users have given acess to paricular folders in their Mailbox to other people(including the default user which may mean the have unwillingly delegated access to everyone). And we can look at the reverse of this which is what mailboxes folders a particular mailbox has been given access to.
We can see all the Outlook delegations that have been configured and who will receive who's meeting request etc. And the reverse which is what delegate meeting request a particular mailbox will receive.
The big thing is that this script pulls together all the disparate permissions you have to consider when determining mailbox access and displays them in one location so any of the above type of questions become exceedingly easier to answer. Well that's the theory anyway.
This script uses the EWS Powershell library I've been building for a while to provide some eaiser to use functions when accessing Exchange Web Services from Powershell . The ability to access/set folder permissions was added in SP1 with Exchange Web Services. Folder permissions are a little tricky to deal with as I've talked about in the past, basically you have two different types of permission sets, calendarpermissions and normal folder permissions. So its important to detect and differentiate between them and there is also a problem with calendar permissions in that the Outlook Roles don't map to the CalendarPermissionLevelType in EWS. Fortunately i solved this one in the past with a few helper routines that will map the custom levels back to their correct Outlook roles so they make a bit more sense. The delegate code is pretty simple and just returns the outlook delegates as a genericlist.
To report on folder permissions and Delegates using Exchange Web Services you need to have rights on the mailboxes you are going to report on. There are a few ways of granting these rights firstly you can do this by granting those rights to a specific user using add-mailboxpermission as documented here. Or you can grant the rights via EWS impersonation by allowing impersonation on the server and mailStores your going to access see this. To allow for these varying degrees of rights allocations when you run the script its will first prompt you for the EWS authentication and Autodiscover settings. If you have autodiscover configured correctly the script should be able to query AD to find the correct EWS URL to use otherwise you can manually input the URL to your CAS which would look something like "https://casservername.domain.com/ews/exchange.asmx". Once you have made the EWS authentication choices the script will start querying active directory and the mailboxes for every users permissions and depending on the number of mailboxes and users you have hopefully eventually get back to you with a result.
To use this script you need to download the latest copy of the EWSUtil from here and put it in the c:\temp directory as this is where the script expect the dll eg
[void][Reflection.Assembly]::LoadFile("c:\temp\EWSUtil.dll")
I've put a download of the script here the new bits of the code look like.
if ($seAuthCheck.Checked -eq $false) {
$ewc = new-object EWSUtil.EWSConnection($mbMailboxEmail,$useImp, $unUserNameTextBox.Text, $unPasswordTextBox.Text, $unDomainTextBox.Text,$casUrl)
}
else{
$ewc = new-object EWSUtil.EWSConnection($mbMailboxEmail,$useImp, "", "", "",$casUrl)
}
$fldarry = new-object EWSUtil.EWS.BaseFolderIdType[] 6
for ($fcint=0;$fcint -lt 6;$fcint++){
$dTypeFld = new-object EWSUtil.EWS.DistinguishedFolderIdType
switch ($fcint){
0 {$dTypeFld.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::inbox}
1 {$dTypeFld.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::calendar}
2 {$dTypeFld.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::contacts}
3 {$dTypeFld.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::tasks}
4 {$dTypeFld.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::journal}
5 {$dTypeFld.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::msgfolderroot}
}
$mbMailbox = new-object EWSUtil.EWS.EmailAddressType
$mbMailbox.EmailAddress = $mbMailboxEmail
$dTypeFld.Mailbox = $mbMailbox
$fldarry[$fcint] = $dTypeFld
}
$Folders = $ewc.GetFolder($fldarry)
If ($Folders.Count -ne 0) {
ForEach ($Folder in $Folders) {
if ($Folder.GetType() -eq [EWSUtil.EWS.CalendarFolderType]){
ForEach ($Permissions in $Folder.PermissionSet.CalendarPermissions){
if ($Permissions.UserId.DistinguishedUserSpecified -eq $false){
$sidbind = "LDAP://sid="
$AceName = $ace.IdentityReference.Value
$aceuser = [ADSI]$sidbind
[VOID]$rsTable.rows.add($uoUserobject.samaccountname.ToString(),("FolderRight-" + $Folder.DisplayName),$aceuser.samaccountname.ToString(),$ewc.enumOutlookRole($Permissions),"Allow")
$fpCount++
if ($rvFolderPerms.Containskey($aceuser.samaccountname.ToString())){
$rvFolderPerms[$aceuser.samaccountname.ToString()] = [int]$rvFolderPerms[$aceuser.samaccountname.ToString()] +1
}
else {
$rvFolderPerms.add($aceuser.samaccountname.ToString(),1)
}
}
else{
if ($Permissions.UserId.DistinguishedUser -eq [EWSUtil.EWS.DistinguishedUserType]::Default){
if ($Permissions.CalendarPermissionLevel -ne [EWSUtil.EWS.CalendarPermissionLevelType]::None){
[VOID]$rsTable.rows.add($uoUserobject.samaccountname.ToString(),("FolderRight-" + $Folder.DisplayName),"Default",$ewc.enumOutlookRole($Permissions),"Allow")
$dfCount++
}
}
}
}
}
else {
ForEach ($Permissions in $Folder.PermissionSet.Permissions){
if ($Permissions.UserId.DistinguishedUserSpecified -eq $false){
$sidbind = "LDAP://sid="
$AceName = $ace.IdentityReference.Value
$aceuser = [ADSI]$sidbind
[VOID]$rsTable.rows.add($uoUserobject.samaccountname.ToString(),("FolderRight-" + $Folder.DisplayName),$aceuser.samaccountname.ToString(),$Permissions.PermissionLevel.ToString(),"Allow")
$fpCount++
if ($rvFolderPerms.Containskey($aceuser.samaccountname.ToString())){
$rvFolderPerms[$aceuser.samaccountname.ToString()] = [int]$rvFolderPerms[$aceuser.samaccountname.ToString()] +1
}
else {
$rvFolderPerms.add($aceuser.samaccountname.ToString(),1)
}
}
else{
if ($Permissions.UserId.DistinguishedUser -eq [EWSUtil.EWS.DistinguishedUserType]::Default){
if ($Permissions.PermissionLevel -ne [EWSUtil.EWS.PermissionLevelType]::None){
[VOID]$rsTable.rows.add($uoUserobject.samaccountname.ToString(),("FolderRight-" + $Folder.DisplayName),"Default",$Permissions.PermissionLevel.ToString(),"Allow")
$dfCount++
}
}
}
}
}
}
}
$delegates = $ewc.getdeletgates($mbMailboxEmail)
foreach ($delegate in $delegates){
$sidbind = "LDAP://sid="
$AceName = $ace.IdentityReference.Value
$aceuser = [ADSI]$sidbind
$dgCount++
[VOID]$rsTable.rows.add($uoUserobject.samaccountname.ToString(),"DelegateRight",$aceuser.samaccountname.ToString(),"Mailbox Delegated","Allow")
if ($delegate.DelegateUser.ReceiveCopiesOfMeetingMessagesSpecified -eq $true){
if ($delegate.DelegateUser.ReceiveCopiesOfMeetingMessages-eq $true){
$dgCount++
[VOID]$rsTable.rows.add($uoUserobject.samaccountname.ToString(),"DelegateRight",$aceuser.samaccountname.ToString(),"Recieve Meetings","Allow")
if ($rvDelegatePerms.Containskey($aceuser.samaccountname.ToString())){
$rvDelegatePerms[$aceuser.samaccountname.ToString()] = [int]$rvDelegatePerms[$aceuser.samaccountname.ToString()] +1
}
else {
$rvDelegatePerms.add($aceuser.samaccountname.ToString(),1)
}
}
}
if ($delegate.DelegateUser.ViewPrivateItemsSpecified -eq $true){
if ($delegate.DelegateUser.ViewPrivateItems-eq $true){
$dgCount++
[VOID]$rsTable.rows.add($uoUserobject.samaccountname.ToString(),"DelegateRight",$aceuser.samaccountname.ToString(),"View Private Items","Allow")
if ($rvDelegatePerms.Containskey($aceuser.samaccountname.ToString())){
$rvDelegatePerms[$aceuser.samaccountname.ToString()] = [int]$rvDelegatePerms[$aceuser.samaccountname.ToString()] +1
}
else {
$rvDelegatePerms.add($aceuser.samaccountname.ToString(),1)
}
}
}
if ($rvDelegatePerms.Containskey($aceuser.samaccountname.ToString())){
$rvDelegatePerms[$aceuser.samaccountname.ToString()] = [int]$rvDelegatePerms[$aceuser.samaccountname.ToString()] +1
}
else {
$rvDelegatePerms.add($aceuser.samaccountname.ToString(),1)
}
}
Thursday, October 02, 2008
Subscribe to:
Post Comments (Atom)
15 comments:
Jeez, I'm impressed by this one and I can see it will be very helpful, however it only seems to work with the first 1000 or so mailbox and mailusers in our test setup - how can I get all of them - is there a ResultSize that can be configured?
Thanks
Alastair
I'd somehow managed to leave
$dfsearcher.PageSize = 1000
Out which is a bit weird because i had this in the original script. Anyway i've updated the download which should fix the issue with only 1000 results being returned.
Cheers
Glen
Great script!
Do you have a script that will do this on an exchange 2003 server?
Version 1 will work on 2003 http://gsexdev.blogspot.com/2008/04/exchange-permission-and-reverse.html but this doesn't do mailbox or delegate permission. I have older vbs scripts that do mailbox permission but not anything that will do delegates as there wasn't really any good API in 2003 to retrieve this information. http://gsexdev.blogspot.com/2005/06/reverse-permissions-audit-scripts-part.html
Cheers
Glen
Glen,
This is a great script. I have a question however. If I would want to change permissions on the user's mailbox (for example) manually as admin where would I do it? ADUC->Security, ADSIEDIT? I ran your script and found that one of my users is denying "Full Mailbox Access" of his mailbox (MailboxRight) to Administrator's account. However when I look under "Manage Full Access Permission ..." nothing is set there except "NT Authority/Self." But if I grant Administrator's account "Full Mailbox Access" it seems that it removes "Deny" permission for Administrator and then grants Administrator Full access (see below):
Summary: 2 item(s). 2 succeeded, 0 failed.
Elapsed time: 00:00:00
TAA\Administrator
Completed
Exchange Management Shell command completed:
Remove-MailboxPermission -Identity 'CN=Maxwell\, Robert,OU=TAA Users,DC=TAA,DC=net' -User 'TAA\Administrator' -Deny -InheritanceType 'All' -AccessRights 'FullAccess'
Elapsed Time: 00:00:00
TAA\Administrator
Completed
Exchange Management Shell command completed:
Add-MailboxPermission -Identity 'CN=Maxwell\, Robert,OU=TAA Users,DC=TAA,DC=net' -User 'TAA\Administrator' -AccessRights 'FullAccess'
Elapsed Time: 00:00:00
This leads me to believe that "deny" permission is set somewhere else, but I don't know where. Can you help?
The only method you should use to set mailbox permissions in Exchange 2007 is to use the Exchange Management Console or the Exchange Management Shell. You should not try to modify mailbox permissions with ADSI edit. By default administrators are denied access to every mailbox other then their own this is gernally a inherited rights not a Explicit right. This script only checks explicit rights. I would suggest having a read of http://support.microsoft.com/default.aspx?scid=kb;EN-US;310866
Cheers
Glen
How would one go about modifying this script to only make it run against a specific OU? We would like to be able to track permissions for our conference room resources, but not have to audit the entire GAL to do so.
Thanks!
-David
All you need to is change the root search path so change
$dfDefaultRootPath = "LDAP://" + $root.DefaultNamingContext.tostring()
to
$dfDefaultRootPath = "LDAP://yourOuDN "
replace yourOuDN with the Distigushed name of the OU you want as the search path.
Cheers
Glen
I tried running this script and it works great but for one user i get the following error "Exception calling "GetFolder" with "1" argument(s): "Impersonation failed."
At :line:140 char:26
+ $Folders = $ewc.GetFolder <<<< ($fldarry)"
I have verfied that I have the proper permissions to impersonate the user.
any ideas?
Thanks
Is this user disabled ? You cant impersonated a disabled user well you can but you end up impersonating the disabled part of the user meaning that you will never be able to access that users mailbox.
Hi, I'm trying this script but I get the following - can you tell me what you think the problem might be? It seems to throw these same errors for each mailbox it tried to process. Server is 2008 SP2 Enterprise with E2K7 SP1 rollup 7.
*************************
Processing Mailbox - johndoe
Doing Mailbox Permissions with EWS
New-Object : Exception calling ".ctor" with "6" argument(s): "The remote server returned an error: (404) Not Found."
At C:\temp\revpermguiv2.ps1:121 char:20
+ $ewc = new-object <<<< EWSUtil.EWSConnection($mbMailboxEmail,$useImp, "", "", "",$casUrl)
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
You cannot call a method on a null-valued expression.
At C:\temp\revpermguiv2.ps1:140 char:27
+ $Folders = $ewc.GetFolder <<<< ($fldarry)
+ CategoryInfo : InvalidOperation: (GetFolder:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\temp\revpermguiv2.ps1:143 char:23
+ if ($Folder.GetType <<<< () -eq [EWSUtil.EWS.CalendarFolderType]){
+ CategoryInfo : InvalidOperation: (GetType:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\temp\revpermguiv2.ps1:197 char:33
+ $delegates = $ewc.getdeletgates <<<< ($mbMailboxEmail)
+ CategoryInfo : InvalidOperation: (getdeletgates:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\temp\revpermguiv2.ps1:199 char:73
+ $sidbind = "LDAP://SID=" + $delegate.DelegateUser.UserId.SID.ToString <<<< () + ""
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
sounds like Autodiscover is failing you might want to try putting in the you cas uri eg https://yourservername/ews/exchange.asmx
Cheers
Glen
This script works great, one question though. When it completes you have the option to export it to a csv file. Is there anyway to automatically make that happen. I love for the script to run and export to csv so I can run it on a schedule.
You need to really rewirte the script then a pull the parts you want out and come up with something that can be run from Task Scheduler.
Cheers
Glen
I'd like to see this automated too. Is anyone out there doing this? Have it save to a file when it's done without user interaction.
Post a Comment