HOW TO:Set folder level permissions using CDO 1.21 and ACL.dll


This is not something everyone would want to do, but just in case below is the sample code that uses ACL.dll (found in the Platform SDK) to set "Reviewer" permissions on all the folders for a specific user.

The following sample is a simple VBScript code sample that iterates through all folders in multiple mailboxes and sets the "Reviewer" permissions. To use this sample, paste the following code in a new text file, and then name the file SetFolderPermissions.vbs:

'This script logs on to a server that is running Exchange Server and iterates through all the mailboxes
'recursively setting the "Reviewer" permission on each folder for a specific user.

' USAGE: cscript SetFolderPermissions.vbs SERVERNAME DATAFILE FullUserName
' This requires that CDO 1.21 and the Acl.dll is installed on the computer.

Dim obArgs
Dim cArgs
Dim objSession
Dim objInfoStores
Dim FullUserName

Set obArgs = WScript.Arguments
cArgs = obArgs.Count

Const CdoMsg = 3,ForReading = 1, ForWriting = 2, ForAppending = 8, TristateFalse = 0

Main

Sub Main()
Dim FileSysObj
Dim DataFileName
Dim DataFile
Dim alias

    If cArgs <> 3 Then
        WScript.Echo "Usage: cscript SetFolderPermissions.vbs SERVERNAME DATAFILE(Name and Path) FullUserName"
        Exit Sub
    End If

    Set FileSysObj = CreateObject("Scripting.FileSystemObject")

    DataFileName = obArgs.Item(1)
    FullUserName = obArgs.Item(2)


    Set DataFile = FileSysObj.OpenTextFile(DataFileName, ForReading, False,0)
    
    'Read line by line
    Do While Not DataFile.AtEndOfStream
         alias = DataFile.ReadLine
    
    'Loop through the mailboxes
        Call IterateInfoStores(obArgs.Item(0), alias)
    Loop
   
    DataFile.Close

    'Clean Up    
    Set DataFile = Nothing
    Set FileSysObj = Nothing

End Sub


Sub IterateInfoStores(ServerName,UserName)

Dim objFolder
Dim intCounter
Dim objInfoStore
Dim sMsg

    On Error Resume Next
    
    'Create the new Session Object
    Set objSession = CreateObject("MAPI.Session")

    If Err.Number <> 0 Then
      sMsg = "Error creating MAPI.Session."
      sMsg = sMsg & "Make sure CDO 1.21 is installed. "
      sMsg = sMsg & Err.Number & " " & Err.Description
      WScript.Echo sMsg
      Exit Sub
    End If

    'Logon to the Mailbox
    objSession.Logon "", "", False, True, 0, False, ServerName & vbLf & UserName
    
    If Err.Number <> 0 Then
      sMsg = "Error logging on: "
      sMsg = sMsg & Err.Number & " " & Err.Description
      WScript.Echo sMsg
      WScript.Echo "Server: " & ServerName
      WScript.Echo "Mailbox: " & UserName
      Set objSession = Nothing
      Exit Sub
    End If

    WScript.Echo "Logged On to:" & objSession.CurrentUser

    'Loop through the Infostores
    For intCounter = 1 To objSession.InfoStores.Count
        Set objInfoStore = objSession.InfoStores(intCounter)

    If Err.Number <> 0 Then
          sMsg = "Error retrieving InfoStore Object: "
          sMsg = sMsg & Err.Number & " " & Err.Description
          WScript.Echo sMsg
          WScript.Echo "Server: " & ServerName
          WScript.Echo "Mailbox: " & UserName
          Set objInfoStore = Nothing
          Set objSession = Nothing
          Exit Sub
    End If
    
        If objInfoStore.Name = "Mailbox - " & objSession.CurrentUser Then
            Exit For
        End If
    Next
    
    Set objFolder = objInfoStore.RootFolder
    
    If Err.Number <> 0 Then
    sMsg = "Error retrieving RootFolder Object: "
    sMsg = sMsg & Err.Number & " " & Err.Description
    WScript.Echo sMsg
    WScript.Echo "Server: " & ServerName
    WScript.Echo "Mailbox: " & UserName
    Set objInfoStore = Nothing
    Set objFolder = Nothing
    Set objSession = Nothing
    Exit Sub
    End If

    'Recurse through the sub-folders
    NavigateFolders objFolder

    If Err.Number <> 0 Then
    sMsg = "Error: "
    sMsg = sMsg & Err.Number & " " & Err.Description
    WScript.Echo sMsg
    WScript.Echo "Server: " & ServerName
    WScript.Echo "Mailbox: " & UserName
    End If
    
    'Logoff from the session
    objSession.Logoff

    'Clean Up
    Set objFolder = Nothing
    Set objInfoStore = Nothing
    Set objSession = Nothing
End Sub

Sub NavigateFolders(MAPIFolder)
Dim intCounter
Dim oDelegate
Dim oAddrBook
Dim oNewAce
Dim ACLObj
Dim FolderACEs
Dim objAce

Const ROLE_REVIEWER = &H401
Const ROLE_OWNER = &H5E3 
Const ROLE_PUBLISH_EDITOR = &H4E3 
Const ROLE_EDITOR = &H463 
Const ROLE_PUBLISH_AUTHOR = &H49B 
Const ROLE_AUTHOR = &H41B 
Const ROLE_NONEDITING_AUTHOR = &H413 
Const ROLE_CONTRIBUTOR = &H402 
Const ROLE_NONE = &H400 


    WScript.Echo "Folder Name:" & MAPIFolder.Name

    'Create the ACL object
    Set ACLObj = CreateObject("MSExchange.aclobject")
    
    ' Associate the ACLObject to the CDO Folder
    ACLObj.CDOItem = MAPIFolder
    Set FolderACEs = ACLObj.ACEs

    ' Create a MAPI object for UserA
    Set oAddrBook = objSession.AddressLists("Global Address List")

    Set oDelegate = oAddrBook.AddressEntries.Item(FullUserName)

    Set oNewAce = CreateObject("MSExchange.ACE")

    oNewAce.ID = oDelegate.ID
    oNewAce.Rights = ROLE_REVIEWER
    FolderACEs.Add oNewAce
    ACLObj.Update

    ' Loop through all of the ACEs for the folder and display them
    For each objAce in  FolderACEs
    WScript.Echo GetACLEntryName(objAce.ID) & " - " & DispACERules(objAce)
    Next
    WScript.Echo ""

    ' Clean up objects
    Set objAce = Nothing
    Set oNewAce = Nothing
    Set FolderACEs = Nothing
    Set ACLObj = Nothing

    If MAPIFolder.Folders.Count > 0 Then
        For intCounter = 1 To MAPIFolder.Folders.Count
            NavigateFolders MAPIFolder.Folders(intCounter)
        Next
    End If


End Sub

Function GetACLEntryName(ACLEntryID)
On Error resume Next
' This function finds the user that is listed as an ACE on the folder.
' It takes the ID that it is passed and uses the Session.GetAddressEntry method
' to find the name.
    
    Dim tmpEntry
    Dim tmpName

    Select Case ACLEntryID
    Case "ID_ACL_DEFAULT"
            GetACLEntryName = "Default"
    Case "ID_ACL_ANONYMOUS"
            GetACLEntryName = "Anonymous"
    Case else
       ' Get the name of the ACE
        Set tmpEntry = objSession.GetAddressEntry(ACLEntryID)
            tmpName = tmpEntry.Name
            GetACLEntryName = tmpName
    End Select
    
End Function

Function DispACERules(DisptmpACE)
' This function checks the roles of the ACE that is passed to it and    returns
' the Role back.
Const ROLE_NONE = 1024
Const ROLE_AUTHOR = 1051
Const ROLE_CONTRIBUTOR = 1026
Const ROLE_PUBLISH_AUTHOR = 1179
Const ROLE_NONEDITING_AUTHOR = 1043
Const ROLE_REVIEWER = 1025
Const ROLE_EDITOR = 1147
Const ROLE_OWNER = 2043
Const ROLE_PUBLISH_EDITOR = 1275  

    ' Check the roles on the folder
    Select Case DisptmpACE.Rights
        Case ROLE_NONE, 0  ' Checking in case the role has not been set on that entry.
                DispACERules = "None"
        Case ROLE_AUTHOR
                DispACERules = "Author"
        Case ROLE_CONTRIBUTOR
                DispACERules = "Contributor"
        Case ROLE_EDITOR
                DispACERules = "Editor"
        Case ROLE_NONEDITING_AUTHOR
                DispACERules = "Nonediting Author"
        Case ROLE_OWNER
                DispACERules = "Owner"
        Case ROLE_PUBLISH_AUTHOR
                DispACERules = "Publishing Author"
        Case ROLE_PUBLISH_EDITOR
                DispACERules = "Publishing Editor"
        Case ROLE_REVIEWER
                DispACERules = "Reviewer"
        Case Else
        ' This will grab all other custom permissions on the folder
                DispACERules = "Custom"
    End Select

End Function
 

The list of mailboxes can be provided via a text file(Datafile). The Datafile contains the aliases of the users(one on each line). So assuming your Datafile is called "Aliases.txt" and is on the C:\, you would run the script as follows:

C:\>Cscript SetFolderPermissions.vbs Exchange2003 C:\Aliases.txt "Akash Bhargava"

The script currently sets and also dumps out the permissions on each folder in the mailbox.

The account that you are logged on the computer with must have permissions on the mailboxes that you are trying to iterate through. You can give the permissions by following the steps in the article below:

How to assign service account access to all mailboxes in Exchange Server 2003

http://support.microsoft.com/kb/821897/

Enjoy!

Comments (9)

  1. Jim Edelman says:

    Hi,

    Would this work with both Exchange 2003 and Exchange 2007 mailboxes?

    Regards,

    -Jim

  2. Akashb says:

    This works on Exchange 2003 for sure. I have not tested it on Exchange 2007.

  3. Andreas says:

    hi,

    i am still receiving ‘mapi_e_not_found’ failure, permission of local account has been set to full rights in ESM ?

    please help

  4. Akashb says:

    Hi,

    Can you please let me know on which line the error is comming @.

    Do you get the error on all the mailboxes or just one?

  5. Andreas says:

    it happens here:

    ‘Recurse through the sub-folders

       NavigateFolders objFolder

       If Err.Number <> 0 Then

       sMsg = "Error: "

       sMsg = sMsg & Err.Number & " " & Err.Description

       WScript.Echo sMsg

       WScript.Echo "Server: " & ServerName

       WScript.Echo "Mailbox: " & UserName

       End If

    i am receiving the error on all mailboxes. also tried to create new mailboxes on different exchange server and information store,no effect.

  6. Andreas says:

    hi,

    is it also possible to select an explicit subfolder e.g. privatemails ?

  7. Akashb says:

    Are you running this under the service account? Can you give me the exact line that is failing. Yes you can select a subfolder.

    You will need to alter the code an get a reference to that folder first..

      Set CdoFolders = objFolder.Folders

      Set CdoFolder = CdoFolders.GetFirst

      Do While Not (CdoFolder Is Nothing)

        WScript.Echo "Folder Found: " & CdoFolder.Name

           Set CdoFolder = CdoFolders.GetNext

      Loop

    Folders Collection Object

    http://msdn.microsoft.com/en-us/library/ms527121(EXCHG.10).aspx

  8. Andreas says:

    hi,

    it happens on line 126, when the sub-routine ‘Sub NavigateFolders(MAPIFolder)’ is called. has the acl.dll be compiled ?

    thanx a lot

  9. Akashb says:

    If you comment out the "On Error Resume Next" statements in the code, it should give you the exact line the error is happening on.

Skip to main content