Notice: This website is an unofficial Microsoft Knowledge Base (hereinafter KB) archive and is intended to provide a reliable access to deleted content from Microsoft KB. All KB articles are owned by Microsoft Corporation. Read full disclaimer for more details.

Users cannot send e-mail messages from a mobile device or from a shared mailbox in Exchange 2000 Server and in Exchange Server 2003


View products that this article applies to.

Symptoms

When you try to send an e-mail message in Microsoft Exchange 2000 Server or in Microsoft Exchange Server 2003, you cannot send the e-mail message. Additionally, you may receive one of the following error messages or one of the following non-delivery reports (NDRs).

Error messages

  • Access denied
  • You do not have sufficient permission to perform this operation on this object. See the folder contact or your system administrator.
  • Unlisted Message Error
  • MAPI_E_NO_ACCESS -2147024891
  • Failed to submit mail message for user USERNAME (HRESULT:-2147024891) Pausing user USERNAME. (Security error - Cannot access the users mailbox.)
  • Resource Not Found
Note You receive the "Access denied" error message or the "Resource not found" error message from Microsoft Outlook Web Access when you are logged in as a delegate account.

NDRs

  • You do not have permission to send to this recipient. For assistance, contact your system administrator.
  • The message could not be sent by using your mailbox. You do not have the permission to send the message on behalf of the specified user.

Products affected

This issue is known to affect the following third-party products:
  • Research In Motion (RIM) BlackBerry Enterprise Server (BES)
  • Good Technology GoodLink Wireless Messaging
This issue may also affect custom MAPI or Collaborative Data Objects (CDO)-based programs that send e-mail messages.

Other third-party products that use service accounts to send e-mail messages may also be affected. If you are running a third-party product that is affected by this issue, we recommend that you contact the vendor for help with resolving this issue.

However, it has been confirmed that the following third-party products are not affected by this issue:
  • Cisco Unity Unified Messaging
  • Quest Migration Suite for Exchange
  • The Microsoft ExMerge utility for Exchange

↑ Back to the top


Cause

This issue may occur if one of the following conditions is true:
  • You do not have permissions to send e-mail messages as the mailbox owner in the account that you are using to send the e-mail message.
  • You are running Microsoft Exchange 2000 Server Service Pack 3 (SP3) together with a Store.exe file version that is equal to or later than version 6619.4. Version 6619.4 was first made available in the following Microsoft Knowledge Base article:
    915358 A hotfix is available to change the behavior of the Full Mailbox Access permission in Exchange 2000 Server
  • You are running Microsoft Exchange Server 2003 SP1 together with a Store.exe file version that is equal to or later than version 7233.51.
  • You are running Exchange Server 2003 SP2 together with a Store.exe file version that is equal to or later than version 7650.23. Version 7650.23 was first made available in the following Microsoft Knowledge Base article:
    895949 �Send As� permission behavior change in Exchange 2003
    This change is not included with Exchange Server 2003 SP2. If you have been running the Exchange Server 2003 SP1 version of the Store.exe file that includes this change, and you upgrade to Exchange Server 2003 SP2, you must install the SP2 version of this hotfix to retain the new behavior. This change will be included in Microsoft Exchange Server 2003 SP3.

↑ Back to the top


Security concerns

Before the Store.exe file versions that are listed in the "Cause" section, granting the Full Mailbox Access permission implicitly granted permission to send as the mailbox owner. This meant that another account that has the Full Mailbox Access permission could send e-mail messages that appeared as if they were sent by the mailbox owner.

Many Microsoft Exchange customers have requested that the Send As permission be separated from the Full Mailbox Access permission for the following two reasons:
  • To deter e-mail spoofing.
  • To make sure that e-mail messages that are sent by a delegate can always be clearly distinguished from e-mail messages that are sent by the actual mailbox owner.
All new versions of the Exchange store will now explicitly require the Send As permission to send e-mail messages as the mailbox owner. However, the following lists the three exceptions to this requirement:
  • The mailbox owner account does not require explicit Send As permissions for its own mailbox.
  • The Associated External Account for a mailbox does not require explicit Send As permissions.
  • A delegate account that also has the Full Mailbox Access permission does not require explicit Send As permissions.
For more information about these exceptions, see the "More Information" section.

↑ Back to the top


Resolution

All accounts that are granted partial or full access to a mailbox, except those mentioned in the "Cause" section, must now be explicitly granted the Send As permission for the mailbox owner account in order to send mail as the mailbox owner. This includes application service accounts that perform functions such as sending e-mail messages for mobile device users.

The Send As permission applies to the identity of an Active Directory user object, not to mailbox contents that are stored in a database. Therefore, the Send As permission must be granted to the service account on each user object that owns a mailbox. When e-mail messages are sent, they are not sent from a particular mailbox or database, but from a user. The user may be the mailbox owner or any other account that has the Send As permission.

You cannot grant the Send As permission on a server that is running Exchange Server or on a database object and achieve the effect of granting the Send As permission for all mailboxes in the database. Granting the Send As permission on an Exchange database object gives you permission to the database itself. The permission is inherited by all mailboxes in the database. However, it does not give you permission to the users who have Send As permissions and who have mailboxes in the database.

Note Granting the Receive As permission on an Exchange database is the functional equivalent of granting the Full Mailbox Access permission to all mailboxes in the database. This differs from the behavior of the Send As permission.

How to grant the Send As permissions for one account

To explicitly grant another account permission to send as a mailbox owner, follow these steps:
  1. Start the Active Directory Users and Computers management console.
  2. On the View menu, make sure that the Advanced Features option is selected. If this option is not selected, the Security page will not be visible for User account objects.
  3. Open the properties of the user account that owns the mailbox.
  4. Click the Security tab.
  5. If the account is not already in the list of group or user names, add the account that should have the Send As permission for this user.
  6. In the Permissions box, click the Allow for the "Send As" permission for the appropriate account.
  7. Click OK.
  8. Restart the Microsoft Exchange Information Store service on the affected Exchange server.
Note If you do not restart the Microsoft Exchange Information Store service, the Microsoft Exchange Information Store service will update its permissions cache to make the new permissions take effect according to the value that is set in the following registry subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSExchangeIS\ParametersSystem

Value name: Mailbox Cache Age Limit
Value type: REG_DWORD
Radix: Decimal
Value data: The mailbox information cache age limit in minutes.
The default value for this registry entry is 120 minutes (two hours). If you modify this registry entry, you must restart the Microsoft Exchange Information Store service.

Note If you set the time-out values to a very low value, you may affect the performance of the server.

How to grant the Send As permission for multiple accounts

A sample script is provided at the end of this article that will search an Active Directory service domain for accounts that have the Full Mailbox Access permission without the Send As permission for a mailbox. These are the characteristics of a service or resource account that will be affected by this security change. The script can generate an export file that you can review, edit, and then re-import to grant the Send As permission to accounts that require this permission.

You can also grant the Send As permission by inheritance on every user object in an Active Directory domain or in a container. If you grant the Send As permission by this method, you may grant permissions for objects that you did not intend. Additionally, you may lose permissions for objects that are moved from the container. Therefore, this method is not preferred and may have security implications that should be carefully considered before you implement it.

If you grant Send As permission by using this method, the accounts that have inherited the Send As permission will become invisible to the script that is referenced at the end of the article. To process these accounts by using the script at a later date, you must remove the inherited Send As permission first.

To grant the Send As permission for a single account on all user accounts in an Active Directory domain or container by using inheritance, follow these steps:
  1. Start the Active Directory Users and Computers management console.
  2. On the View menu, make sure that the Advanced Features option is selected. If this option is not selected, the Security page will not be visible for domain and container objects.
  3. Open the properties of the domain or container, and then click the Security page.
  4. Click Advanced.
  5. If the account that needs permission is not already listed, click Add, and then select the account. Otherwise, double-click the account for editing.
  6. In the Applies Onto list, click User Objects.
  7. Grant the account Send As permission.
  8. Click OK until you have exited and saved all changes.

Special rules for adminSDHolder protected accounts

If you use the script to grant the Send As permission for a mailbox owner that is also a domain administrator, the Send As permission will not be effective. We strongly recommend that you do not mailbox-enable user accounts that have domain administrator rights or that are adminSDHolder protected.

The adminSDHolder object is a template for accounts that have broad Active Directory administrative rights. To prevent unintended elevation of privileges, any account that is protected by the adminSDHolder object must have permissions that match those that are listed on the adminSDHolder object itself.

If you change the rights or the permissions on the adminSDHolder object for a protected account, a background task will undo the change within several minutes. For example, if you grant the Send As permission on a domain administrator object for an application service account, the background task will automatically revoke the permission.

Therefore, you cannot grant the Send As permission to an application service account for an account that is protected by the adminSDHolder object unless you change the adminSDHolder object itself. If you do change the adminSDHolder object, the access permissions for all protected accounts will change. You should only change the adminSDHolder object after a complete review of the security implications that may occur with the change.

To associate a mailbox with an account that is protected by the adminSDHolder object, follow these steps:
  1. Start the Active Directory Users and Computers management console.
  2. On the View menu, make sure that the Advanced Features option is selected. If this option is not selected, the Security page will not be visible for User account objects.
  3. Create an ordinary user account to act as the mailbox owner.
  4. Assign the ordinary user account a mailbox on an Exchange server.
  5. Open the properties of the new mailbox owner account.
  6. In the Exchange Advanced box, grant the Full Mailbox Access permission to the protected administrator account.
  7. In the Security page, grant the Send As permission to the protected administrator account.
  8. Click OK to exit the properties of the mailbox owner object.
  9. Right-click the mailbox owner account object, and then click Disable Account to disable the account for all logons.
For more information about adminSDHolder-protected accounts, click the following article numbers to view the articles in the Microsoft Knowledge Base:
907434 The "Send As" right is removed from a user object after you configure the "Send As" right in the Active Directory Users and Computers snap-in in Exchange Server
318180 AdminSDHolder thread affects transitive members of distribution groups
817433 Delegated permissions are not available and inheritance is automatically disabled
306398 AdminSDHolder object affects delegation of control for past administrator accounts

Special tasks for BlackBerry Enterprise Server

Task 1: Make sure that the BlackBerry Enterprise Server is running as a separate, unique account

Make sure that the BlackBerry Enterprise Server is running as a separate account that is specifically created for administrative tasks. By default, this account is called "BESAdmin."

If you have a separate account for administering the BlackBerry Enterprise Server, go to task 2.

If you do not have a separate account, create a separate account. Then, use this account to perform administrative tasks. For instructions about how to do this if you are running BlackBerry Enterprise Server 4.0 or BlackBerry Enterprise Server 4.1, see the BlackBerry Enterprise Server Installation Guide. �For instructions about how to do this if you are running BlackBerry Enterprise Server 3.6, see the BlackBerry Enterprise Server 2000/2003 Installation and Getting Started Guide.

Task 2: Make sure that the BlackBerry Enterprise Server service account has the appropriate permissions

Verify that the BlackBerry Enterprise Server service account has the appropriate permissions.

Note If the account is in a domain, make sure that the account is a member of only the Domain Users group. On a domain controller, the account should be member of the Built-in Administrators group.
  1. On the BlackBerry Enterprise Server, follow these steps:
    1. Make sure that the account is a member of the Local Administrators group.
    2. Assign "Log on Locally" and "Log on as a Service" permissions to the account.
  2. Grant Exchange View-Only Administrator permissions at the administrative group level. To do this, follow these steps:
    1. In Exchange System Manager, right-click the first Exchange Server administrative group name, and then click Delegate Control.
    2. Notice that the BlackBerry Enterprise Server service account is listed as having the role of Exchange View-Only Administrator.
  3. Grant "Send As," "Receive As," and "Administer Information Store" permissions at the server level for each Exchange server. To do this, follow these steps:
    1. In Exchange System Manager, right-click the first Exchange Server administrative group name, and then expand the Servers group.
    2. Right-click an Exchange server, click Properties, and then click Security.
    3. In the top pane, select the BlackBerry Enterprise Server service account. In the bottom pane, make sure that the "Send As," "Receive As," and "Administer Information Store" permissions are set to Allow.
    4. Repeat steps 3b and 3c for each Exchange server.
  4. Grant "Send As," "Receive As," and "Administer Information Store" permissions to the mailbox store. To do this, follow these steps:
    1. In Exchange System Manager, right-click the first Exchange administrative group name, and then expand the Servers group.
    2. Expand the first mailbox store group, right-click each mailbox store, click Properties, and then click Security.
    3. In the top pane, select the BlackBerry Enterprise Server service account. In the bottom pane, make sure that the "Send As," "Receive As," and "Administer Information Store" permissions are set to Allow.
    4. Repeat steps 4b and 4c for each mailbox store on each Exchange server.
  5. In the Active Directory Users and Computers snap-in, follow these steps:
    1. Right-click the user who you want to add permissions for, and then click Properties.
    2. On the Security tab, add the BlackBerry Enterprise Server service account, and then click to select the Send As check box.
If you are not running Exchange Server 2003, see task 3.

Task 3: Clear the cache on the BlackBerry Enterprise Server

To clear the permissions cache in the Exchange store, restart the Blackberry-related services, and then restart the Microsoft Exchange Information Store. After you restart the Exchange store, you must restart the RIM Blackberry-related services to grant the "BESAdmin" account the newly-added Send As permission on the Exchange store.

↑ Back to the top


More information

Exchange mailbox and folder access permissions are split between Active Directory and Microsoft Exchange databases. However, both kinds of permissions are set in the Active Directory user management console, but different permissions are stored in two separate locations.

Generally, if a permission is set on the Security page for an object, it is an Active Directory permission. If it is set on the Exchange Advanced Mailbox Rights page, it is an Exchange database permission.

The msExchMailboxSecurityDescriptor Active Directory attribute is a backup copy of a subset of the effective mailbox rights. It is used internally by Exchange for a variety of purposes. Additionally, the msExchMailboxSecurityDescriptor attribute is updated to match current effective rights if administrators use supported interfaces to assign rights. However, if the msExchMailboxSecurityDescriptor attribute is modified directly by an administrator, the changes will not be propagated to the Exchange store, and the changes will not take effect. It is not guaranteed to be synchronized with actual mailbox rights. You should not use the msExchMailboxSecurityDescriptor attribute to read or write mailbox rights.
For more information, click the following article number to view the article in the Microsoft Knowledge Base:
310866 How to set Exchange Server 2003 and Exchange 2000 Server mailbox rights on a mailbox that exists in the information store

The Full Mailbox Access permission is an Exchange database store permission. The Send As permission is an Active Directory permission. Before the Exchange Store.exe file changes that are described in this article, the Exchange system did not consult the setting for the Send As permission if the sender already had the Full Mailbox Access permission.

Inclusion of the Send As permission with the Full Mailbox Access permission has enabled Exchange server administrators to grant themselves effective Send As permissions for any mailbox on a server that they administer. By separating the Send As permission from the Full Mailbox Access permission, Active Directory administrators can now block this process because the Send As permission is an Active Directory permission and not an Exchange store permission. Therefore, the process is not necessarily under the control of Exchange administrators.

Mailbox owners

A mailbox owner is defined as the Active Directory user account whose msExchMailboxGUID attribute carries the globally unique identifier (GUID) for a particular mailbox. Only one account in a whole forest is permitted to carry the GUID for a particular mailbox. If you try to set a second owner with the same GUID, Active Directory will reject the change with an error.

When you mailbox-enable an account or when you connect a disconnected mailbox to an Active Directory account, the mailbox GUID is automatically set on that account. It is rarely necessary or recommended for administrators to set mailbox GUIDs directly.

Associated external accounts

A common Exchange configuration is to install Exchange in a resource forest. A resource forest is a forest in a different forest from the user accounts that will have mailboxes in the system. This presents a problem because the msExchMailboxGUID attribute can only be set on objects in the same forest as the Exchange server.

The solution to this problem is to mailbox-enable an account in the Exchange server forest. Then, you link this mailbox-enabled account to one in another forest or in a Microsoft Windows NT 4 domain. You can do this by granting the Associated External Account permission. Only a single account can be granted the Associated External Account permission. The account that is selected must be from a different forest.

When you set the Associated External Account permission, you are writing the SID value for the external account to the msExchMasterAccountSID attribute of the mailbox owner. Therefore, this is not a permission at all, but a convenient way to control the value of the msExchMasterAccountSID attribute. After the msExchMasterAccountSID attribute has been set, the external account that owns the SID will be granted Exchange access as if it were the actual mailbox owner account.

Note This applies only to Exchange access, not to all Active Directory access. Additionally, you should mark the mailbox owner account as Disabled for logons after you set the Associated External Account permission so that all permissions work as expected.
For more information, click the following article number to view the article in the Microsoft Knowledge Base:
300456 Client permissions and delegations do not persist after being assigned in Exchange 2000

Delegation scenarios

A delegate is a user who has been granted partial access to another mailbox and the right to send e-mail messages on behalf of that mailbox owner. A common delegation scenario is to grant delegate access to an administrative assistant for an executive's calendar. The delegate can typically read and update the calendar. Additionally, the delegate can reply to any e-mail messages on behalf of the executive.

You can use the following two interfaces to grant the Send on Behalf Of and delegate permissions:
  • On the mailbox owner object, grant the Send on Behalf Of permission in the Exchange General dialog box.
  • In Microsoft Office Outlook, use the Delegates dialog box.
Both these methods set the publicDelegates attribute of the mailbox. All users who are listed in this attribute have the Send on Behalf Of permission for the mailbox owner. When such delegates send an e-mail message that has the owner's name in the From box, the e-mail message is sent from the delegate and not from or as the mailbox owner. The e-mail message's From box displays the following value:
<Delegate's Name> on behalf of <Mailbox Owner>
In some cases, you may be unable to set the publicDelegates attribute in Outlook. For more information, click the following article number to view the article in the Microsoft Knowledge Base:
329622 "Send on behalf" permission is not assigned to a user after you delegate access in Outlook

If you grant delegate access to your mailbox, the delegate can use the Send on Behalf Of permission even if you do not grant access to any one of your mailbox folders. The fundamental permission that a delegate has is the Send on Behalf Of permission. Permissions to access your mailbox folders are separate and must be granted in addition to delegation permissions. Typically, delegates will use Outlook to access individual folders to which you have given them permission. To do this, click Open on the File menu in Outlook, and then click Other User's Folder.

Alternatively, delegates can open your mailbox by listing it as an additional mailbox in the Advanced tab of their Outlook profiles. This method causes your mailbox to appear in the delegate's Outlook folder tree. Additionally, this method allows for access to all folders in your mailbox for which a delegate has been granted permissions.

You may want your delegate to sometimes have the Send on Behalf Of permission and at other times have the Send As permission. To configure a delegate with these two permissions, follow these steps:
  • Grant the delegate the Full Mailbox Access permission. This cannot be done through Outlook. Instead, an Active Directory administrator must do this on the mailbox owner account. Even if you grant Owner permissions on every folder in your mailbox, that is not the same permission as the Full Mailbox Access permission.
  • Do not grant the delegate the Send As permission. If you grant the delegate the Send As permission, all e-mail messages that are sent by the delegate will be done with the Send As permission. The delegate will no longer be able to use the Send on Behalf Of permission.
In this scenario, delegates that want to use the Send on Behalf Of permission should log on to their own mailboxes. If the delegates are replying to or forwarding an e-mail message that is already in one of your folders, the e-mail message will automatically be sent on behalf of you. If the delegates create a new e-mail message on your behalf, they must enter your name in the From box for the e-mail message to be sent on your behalf.

Regardless of whether the delegates have opened your folders or your whole mailbox as a secondary mailbox, all e-mail messages that they send from you will use the Send on Behalf Of permission as long as their own mailbox is the primary mailbox for the current Outlook profile.

When delegates want to send an e-mail message as you, they should log on to your mailbox by using a separate Outlook profile that opens only your mailbox. E-mail messages that the delegates send while they are logged on to this profile will automatically be sent from you.

Finding accounts that have the Full Mailbox Access permission without the Send As permission

The sample script that is described in this section can search one Active Directory domain at a time for user accounts where the Full Mailbox Access permission has been granted to a mailbox without the Send As permission.

Important Before you change permissions, see the "About mailbox owners with delegates" section.

The script has the following three modes:
  • Export You can output a list of users who have the Full Mailbox Access permission but not the Send As permission. You can then review this list in Notepad or another editor to remove any accounts that you do not want to have the Send As permission.
  • Import You can import a list of users who have the Full Mailbox Access permission to whom the Send As permission should also be granted. Note that you cannot use this script to grant both the Full Mailbox Access permission and the Send As permission. Each account must already have the Full Mailbox Access permission to be granted the Send As permission.
  • SetAll You can grant the Send As permission to all users in the domain who already have the Full Mailbox Access permission for a particular mailbox. A log file will be generated in the same format as the export file. This is equivalent to running the Export and Import modes without editing the export file.
Note There is no undo function in this script.

Permissions that are required for the script

You must run the script while you are logged on with an administrative account that is from the same forest that the mailbox owner accounts are from. The script may not work with an account that has cross-forest administrative permissions. The script may also not work when you run it from a workstation that is joined to a different forest than the forest to which the mailbox owner accounts are joined.

Given these conditions, you can run the script with multiple administrative accounts in a single logon session by using the RunAs.exe command. This procedure may be useful if you have segmented Active Directory and Exchange Server permissions, and you have no single account that can administer all Exchange servers or all Active Directory domains. You can open a command prompt to run the script as each administrative account. Consider the following example:
RunAs.exe /user:domain\account CMD.EXE
Note You should not run multiple copies of the script at the same time against the same domain.

The fields in the export file are as follows. The fields are described in the order in which they are presented in the export file.
  • Display name of the mailbox owner account

    There may be more than one line in the output file that lists the same mailbox owner. This behavior occurs when multiple other accounts have Full Mailbox Access permissions to the same mailbox.
  • Domain and logon name of an account that has the Full Mailbox Access permissions but not the Send As permission

    The same account may appear multiple times throughout the export file when the account has access to multiple mailboxes. This is likely to be the case for an application service account or for a person who manages multiple resource mailboxes.
  • Display Name of an account that has the Full Mailbox Access permission but not the Send As permission

    This field is provided in addition to the Logon Name field to make it easier for you to identify the account.
  • Delegate Status of the mailbox owner

    If the mailbox owner has delegates, the field value is Has Delegates. If the mailbox owner has no delegates, the field value is No Delegates.
  • Enabled or disabled status of the mailbox owner account

    This field is useful when you want to identify resource accounts or cross-forest mailbox accounts. Typically, these accounts are disabled.
  • Full Distinguished Name of the mailbox owner account

    This field is useful when you want to identify the domain and the container of the mailbox owner account.
  • Full Distinguished Name of the mailbox owner's mailbox database

    This field includes the database, the storage group, the server, and the administrative group for the mailbox.
In the following example, the user who has the logon name "NoSendAs" has the Full Mailbox Access permission but not the Send As permission for the "Mailbox Owner" mailbox:
"""Mailbox Owner""" """Domain\NoSendAs""" """No Send As User""" """Has Delegates""" """Enabled""" [additional fields omitted]

Administrative workstation configuration for the script

This script uses Exchange management interfaces to communicate with Exchange servers. Therefore, this script must be run from an Exchange server or from a workstation with Exchange System Administrator installed.

Editing the export file

The export file is formatted as Unicode plain text so that character sets from multiple languages can be accommodated. Some text editors may be unable to correctly view or edit the file or may save the file as ANSI or ASCII text. The Notepad utility for Windows Server 2003, Windows XP, and Microsoft Windows 2000 can correctly handle Unicode text files. Additionally, Microsoft Office Excel can correctly handle Unicode text files.

The output file is in a tab-delimited format with triple quotation marks around the values for each field. The triple quotation marks are used to make importing and exporting from Excel more deterministic. In Excel, the triple quotation marks will become single quotation marks, and will revert to triple quotation marks when the file is saved again as Unicode text. See the following instructions to correctly open and save an export file in Excel.

You can also filter an export file without using Excel by using the Find.exe utility or the Findstr.exe utility. These utilities are included with Windows. They let you search for words in a file and output only lines that contain those words or only lines that do not contain those words. For example, if you want to make a list in the file of all the mailbox owners that have delegates, use either of these commands to create a file that contains only lines with the string "Has Delegates":
Find.exe "Has Delegates" OriginalFile.txt > HasDelegates.txt

Findstr.exe /C:"Has Delegates" OriginalFile.txt > HasDelegates.txt
As another example, suppose that you filter out all the mailbox owners with delegates. The /V switch outputs all lines that do not match the search words. You can use any of these commands to generate a file that excludes all "Has Delegates" lines:
Find.exe "No Delegates" OriginalFile.txt > NoDelegates.txt

Find.exe /V "Has Delegates" OriginalFile.txt > NoDelegates.txt

Findstr.exe /C:"No Delegates" OriginalFile.txt > NoDelegates.txt

Findstr.exe /V /C:"Has Delegates" OriginalFile.txt > NoDelegates.txt
You can also use these commands to generate a file that lists all the accounts where an application service account has Full Mailbox Access permission but does not have the Send As permission. The /I switch makes the command case-insensitive:
Find.exe /I "domain\ServiceAccount" OriginalFile.txt > ServiceAccount.txt

Findstr.exe /I /C:"domain\ServiceAccount" OriginalFile.txt > ServiceAccount.txt
Note If you use the Find.exe utility to generate a filtered file, you must remove the header lines that the Find.exe utility will create at the top of the file.

Do not use wildcard file names (*.*) with the Findstr.exe utility. If you do use wildcard characters, each line in the output file will be prefaced by the file name. You should examine the output file carefully after you filter by using Find.exe or Findstr.exe to verify that your filter captured or excluded the accounts that you intended.

In the following example, the user who has the logon name "NoSendAs" has the Full Mailbox Access permission, but not the Send As permission for the "Mailbox Owner" mailbox.
"""Mailbox Owner""" """Domain\NoSendAs""" """No Send As User""" """Has Delegates""" """Enabled""" [additional fields omitted] 

About mailbox owners that have delegates

A delegate who has Full Mailbox Access (also known as a "super-delegate") usually should not be granted the Send As permission. When the super-delegate logs directly on to the mailbox owner's mailbox, the delegate can send as the owner. When the delegate uses Outlook's delegation features (Additional Mailboxes to Open or Open Other User's Folder), messages are sent on behalf of the owner.

Grant the Send As permission to a super-delegate only if you want the delegate always to send as the mailbox owner and never to send on behalf of the mailbox owner. We recommend that you search the export file for the text "Has Delegates," and then determine whether any one of the super-delegates that are listed are actually delegates of the mailbox owner.

Only super-delegates are listed in the export file. Ordinary delegates do not have the Full Mailbox Access permission. Additionally, when you grant the Send As permission to an ordinary delegate, the delegate will always send as the mailbox owner. This is true even when the ordinary delegate does not have the Full Mailbox Access permission. If you do grant Send As permissions to a delegate when you did not intend to, you can easily revoke the permission later.

How to open an export file in Excel

  1. Start Excel before you open the export file.
  2. Open the file in Excel as type Text Files. The Text Import Wizard starts.
  3. In the Text Import Wizard, change or accept the following settings:
    • Original data type: Delimited
    • Start import at row: 1
    • File Origin: Unicode (UTF-8)
    • Delimiters: Tab only
    • Treat consecutive delimiters as one: unmarked
    • Text qualifier: " (double quotation marks)

How to save an export file after you edit the file in Excel

  1. In the export file, click Save As.
  2. Save the file by using a different name so that you preserve an unedited copy of the original file.
  3. Click File, click Save As, enter a file name for saving the output, and then click Unicode text in the Save As Type list.

Script syntax

This is a text mode script, and it should be run in a command prompt window, not from the Run dialog box. To open a command prompt window, click Start, click Run, type CMD in the Open box, and then click OK.

Error log and export files will be saved to the current command prompt directory. You must have permissions to create files in this directory. To obtain command line help, enter the following command:
CSCRIPT AddSendAs.vbs
To export users who have Full Mailbox Access without the Send As permission for a domain, enter the following command:
CSCRIPT AddSendAs.vbs [domain controller name] �Export
Example:
CSCRIPT AddSendAs.vbs CORP-DC-1 �Export
The export file will be generated as "Send_As_Export_H_MM_SS.txt."

To import an edited export file, enter the following command:
CSCRIPT AddSendAs.vbs [domain controller name] �Import [filename]


Example:


CSCRIPT AddSendAs.vbs CORP-DC-1 �Import "Send_As_Export_H_MM_SS.txt"

How to grant the Send As permission for each mailbox in the domain for all users who already have the Full Mailbox Access permission for a mailbox

Note If you have delegates who also have the Full Mailbox Access permission in your organization, you should not use the SetAll mode. If you do use the SetAll mode in this situation, delegates will be granted the Send As permission. This behavior can cause all e-mail messages that they send to use the Sent As permission instead of the Sent on Behalf Of permission. You can correct this behavior by removing the Send As permission that was mistakenly granted to the delegate:
CSCRIPT AddSendAs.vbs [domain controller name] �SetAll


Example:


CSCRIPT AddSendAs.vbs CORP-DC-1 �SetAll
If you use the SetAll mode, an export file will be generated as Send_As_Export_H_MM_SS.txt. You should save this file because it is a record of all the accounts that were changed. If you were to run the script again, it would not output the same list of accounts because the accounts would already have been granted the Send As permission.

Errors that you experience while you are running the script will be saved to the Send_As_Errors_H_MM_SS.txt file. The error file name will match the hours_minutes_seconds time stamp of any associated export file.

Script modifications

There may be accounts in your organization that have permissions on many objects, but you do not want to alter the permissions. To reduce the size of the export file, you can filter these accounts by modifying the FMA_EXCLUSIVE_LIST variable that is located near the top of the script. By default, this variable lists a few accounts that should be suppressed in the script output. You can add more accounts by using the following format.
& "<Domain\Name>" & OUTPUT_DELIMITER
For example, you could change the value of the following variable.
FMA_EXCLUSIVE_LIST = OUTPUT_DELIMITER & "NT AUTHORITY\SELF" & OUTPUT_DELIMITER & "NT AUTHORITY\SYSTEM" & OUTPUT_DELIMITER
so that it appears as follows.
FMA_EXCLUSIVE_LIST = OUTPUT_DELIMITER & "NT AUTHORITY\SELF" & OUTPUT_DELIMITER & "NT AUTHORITY\SYSTEM" & OUTPUT_DELIMITER & "Mydomain\Service1" & OUTPUT DELIMITER
This change suppresses the listing of the "Mydomain\Service1" account in the export file together with "NT AUTHORITY\SELF" and "NT AUTHORITY\SYSTEM." Notice that the Domain\Name value is case-sensitive, and it must appear exactly as it does or as it would in the export file.

There is another editable variable, FMA_EXCLUSIVE_EXSVC, that has the default value "\Exchange Services" & OUTPUT_DELIMITER. "Exchange Services" is the name of an account that is granted permissions through the Active Directory Connector in Exchange Server 5.5 and in Exchange 2000 migration and co-existence scenarios. This account is created in multiple domains, and it may appear repeatedly in the export file if it is not suppressed.

The FMA_EXCLUSIVE_EXSVC variable accepts only one account as its value. The account name is not case-sensitive. The account must start with a backslash character (\) and should not include the domain to which the account belongs. The account will be suppressed for all domains in which it exists.

If you have used third-party migration tools or directory synchronization methods, a different account may exist in multiple domains that has widely-granted permissions to user mailboxes. In this scenario, you can substitute the name of that account for "\Exchange Services."

Tips and caveats

  • Do not discard log and error files that are generated by the script. They may be valuable for troubleshooting or reversing changes later. Remember, as soon as you have granted the Send As permission to an account, it will no longer be logged in the export file.
  • If an Exchange server or database is down, script processing will be slower. In such a case, you can sort the export file by database and move lines that are associated with a stopped database to a different file for later import.
  • The script suppresses output of accounts where the logon name ends in "$" or is NT AUTHORITY\SYSTEM. These system accounts should not typically need the Send As permission, and removing them from the export file greatly reduces its size.
  • The export file must be in Unicode format before it can be imported. If you have unintentionally saved the file as ANSI text, you can resolve this problem by loading the file in Notepad and saving it as Unicode text.
  • If an import is not working, troubleshoot with test accounts and a single line in the import file. You should configure a test account that has a mailbox on a running Exchange server, and then grant the Full Mailbox Access permission to another test account. Do not grant the Send As permission to the other test account.
  • There is no Undo mode for this script. To take away the Send As permissions that you have granted with this script, you must generate another script or remove them manually. An Undo mode is not provided to avoid the use of this script to remove the Send As permissions for all users in an organization.
  • The script does not correctly handle an account that has been granted Full Control of a user object together with Full Mailbox Access. Full Control includes the Send As permission, but the script will export the account as if it did not have the Send As permission. This may increase the size of the export file, but no harm occurs from importing the file, and then redundantly granting Send As permissions to such accounts.
  • Active Directory user accounts that have distinguished names and that include tabs or unmatched double quotation marks cannot be processed by using this script. The script can correctly process a name that includes matched double quotation marks such as the following:
    "CN=First "Nickname" Last,DC=domain,DC=com"
  • Each version of Excel supports a different maximum line limit. For more information, click the following article number to view the article in the Microsoft Knowledge Base:
    120596 Text files that are larger than 65,536 rows cannot be imported to Excel 97, Excel 2000, Excel 2002 and Excel 2003
    The following are row limits for Excel 2003 and Excel 2007:
    • Excel 2003: 65,536 rows
    • Excel 2007: 1,048,576 rows
    If your output file is larger than these limits, you must split the file into sections before you load it in Excel.
  • The Send_As_Errors file will list specific accounts where there was a failure to read or write permissions. If other accounts in the domain were correctly processed, these accounts may have something in common that prevents the script from running with them. Common issues include the following:
    • Lack of administrative permissions to view or set properties on the accounts.
    • The Exchange mailbox store is not running.
    • The workstation is not a member of the same domain.
    • The administrative account that is being used is not from the same forest.
To run this script, copy and paste all lines between BEGIN SCRIPT and END SCRIPT into a plain text editor such as Notepad. Save the script as AddSendAs.vbs. BEGIN SCRIPT.
Option Explicit

Dim OUTPUT_DELIMITER
OUTPUT_DELIMITER = """""""" & vbTab & """"""""

'Define exclusive list, if FMA is given to any user in this list, it's ignored.  If you 
'want to modify this list, please be sure to follow the same format. Every alias has to 
'have a OUTPUT_DELIMITER before and after it
Dim FMA_EXCLUSIVE_LIST
FMA_EXCLUSIVE_LIST = OUTPUT_DELIMITER & "NT AUTHORITY\SELF" & OUTPUT_DELIMITER & "NT AUTHORITY\SYSTEM" & OUTPUT_DELIMITER
Dim FMA_EXCLUSIVE_EXSVC
FMA_EXCLUSIVE_EXSVC = "\Exchange Services" & OUTPUT_DELIMITER

'Permission Type: Allow or Deny
const ACCESS_ALLOWED_OBJECT_ACE_TYPE  = 5
const ADS_ACETYPE_ACCESS_ALLOWED = &h0
const ADS_ACETYPE_ACCESS_DENIED = &h1

'Flags: Specifies Inheritance
const ADS_ACEFLAG_INHERIT_ACE = &h2
const ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE = &h4
const ADS_ACEFLAG_INHERIT_ONLY_ACE = &h8
const ADS_ACEFLAG_INHERITED_ACE = &h10
const ADS_ACEFLAG_VALID_INHERIT_FLAGS = &h1f
const ADS_ACEFLAG_SUCCESSFUL_ACCESS = &h40
const ADS_ACEFLAG_FAILED_ACCESS = &h80

'Declare ADSI constants
Const ADS_OPTION_SECURITY_MASK = 3
Const ADS_OPTION_REFERRALS	= 1
Const ADS_SECURITY_INFO_DACL = 4
Const ADS_CHASE_REFERRALS_NEVER = &h00 
Const ADS_CHASE_REFERRALS_SUBORDINATE = &h20 
Const ADS_CHASE_REFERRALS_EXTERNAL = &h40

'output file name
Const EXPORT_FILE = "Send_As_Export"
Const ERROR_FILE = "Send_As_Errors"

' script mode
const MODE_INVALID = -1 
const MODE_SETALL = 0
const MODE_EXPORT = 1
const MODE_IMPORT = 2
const SETALL = "-SETALL"
const EXPORT = "-EXPORT"
const IMPORT = "-IMPORT"

' argument index
Const ARG_INDEX_MODE = 1
Const ARG_INDEX_DC = 0
Const ARG_INDEX_FILENAME = 2

' column index in import/export file
Const COLUMN_INDEX_USERDISPLAYNAME = 0
Const COLUMN_INDEX_FMAALIAS = 1
Const COLUMN_INDEX_FMADISPLAYNAME = 2
Const COLUMN_INDEX_IFPUBLICDELEGATE = 3
Const COLUMN_INDEX_MAILBOXSTATUS = 4
Const COLUMN_INDEX_USERADSPATH = 5
Const COLUMN_INDEX_HOMEMDB = 6

Const EMPTYSTRING = ""
Const STRNO = "No Delegates"
Const STRYES = "Has Delegates" 
Const MIN_ARG = 2
Const INIT_ARRAY_SIZE = 100

' Microsoft Exchange 
Const EX_MB_SEND_AS_ACCESSMASK  = &H00100
Const EX_FULLMailbox_AccessMask = 1
Const MESO = "Microsoft Exchange System Objects"
Const EX_MB_SEND_AS_GUID = "{AB721A54-1E2F-11D0-9819-00AA0040529B}"

Const ForReading	= 1
Const ForWriting	= 2
Const ForAppending	= 8
Const TristateTrue	= -1
Const ADS_SCOPE_SUBTREE = 2

Dim objUser
Dim objSDMailBox
Dim objSDNTsecurity
Dim objDACLNTSD
Dim objNewACE

Dim sTrusteeAlias()
Dim sFMADeniedList
Dim sFMAExplicitAllow
Dim fACESendasFound
Dim dArraySize
Dim TotalACE
Dim i
Dim rootDSE
Dim conn
Dim objCommand
Dim objCmdDisplayName
Dim rsUsers
Dim FoundObject
Dim objFSO
Dim objfileImport
Dim objfileExport
Dim objfileError
Dim sImportFilePath
Dim cScriptMode
Dim dArgCount
Dim dArgExpected
Dim sDCServer
Dim sMailboxStatus
Dim sIfPublicDelegate
Dim sFMAUserDisplayName
Dim sExportFileName
Dim sErrorsFileName
Dim msPublicDelegates
Dim fError
Dim fOneError
Dim fFMAAllowed

On Error Resume Next
dArraySize = INIT_ARRAY_SIZE
ReDim Preserve sTrusteeAlias(dArraySize)

dArgCount = Wscript.Arguments.Count 
If ( dArgCount < MIN_ARG ) Then
	DisplaySyntax
End If

err.Clear
fError = False
fOneError = False
cScriptMode = MODE_INVALID
Select Case UCase(WScript.Arguments(ARG_INDEX_MODE))
	Case SETALL 
		cScriptMode = MODE_SETALL
		dArgExpected = ARG_INDEX_MODE + 1
	Case EXPORT 
		cScriptMode = MODE_EXPORT
		dArgExpected = ARG_INDEX_MODE + 1
	Case IMPORT 
		cScriptMode = MODE_IMPORT
		dArgExpected = ARG_INDEX_FILENAME + 1
	Case Else 
		cScriptMode = MODE_INVALID
End Select
If (cScriptMode = MODE_INVALID Or dArgCount <> dArgExpected) Then
	DisplaySyntax
End If

sDCServer = WScript.Arguments(ARG_INDEX_DC)

CreateOutputFiles

If ( cScriptMode = MODE_SETALL Or cScriptMode = MODE_EXPORT ) Then
	Dim sDomainContainer
	If (cScriptMode = MODE_SETALL) Then
		Dim strInput 
		WScript.StdOut.WriteLine("WARNING: If you continue, each account in the domain that has")
		WScript.StdOut.WriteLine("Full Mailbox Access permission for a given mailbox will also be")
		WScript.StdOut.WriteLine("granted permission to Send As the mailbox owner.")
		WScript.StdOut.WriteLine()
		WScript.StdOut.WriteLine("To preview the list of mailboxes before granting Send As,")
		WScript.StdOut.WriteLine("cancel this operation and use the -Export mode of this script.")
		WScript.StdOut.WriteLine()
		WScript.StdOut.Write("Press Y to continue or any other key to cancel: ")
		strInput = WScript.StdIn.ReadLine()
		If (UCase(strInput) <> UCase("Y")) Then
			WScript.Quit
		End If	
	End If
	
	WScript.StdOut.WriteLine()
	WScript.StdOut.WriteLine("""!"" indicates an error processing an object.")
	WScript.StdOut.WriteLine("     Check " & sErrorsFilename)
	WScript.StdOut.WriteLine("Starting...")
	WScript.StdOut.WriteLine()

	err.Clear	
	Set rootDSE = GetObject("LDAP://" & sDCServer & "/RootDSE")
	sDomainContainer = rootDSE.Get("defaultNamingContext")
	WScript.StdOut.WriteLine("Finding domain controller [ " & sDCServer & " ] for domain [ " & sDomainContainer & " ]")
	
	If (err.number <> 0) Then
		WScript.StdOut.WriteLine("Failed to find the domain or domain controller, error:" & err.Description)
		objfileError.WriteLine("Failed to find the domain or domain controller, error:" & err.Description)
		WScript.Quit
	End If
			
	err.Clear	
	Set conn = CreateObject("ADODB.Connection")
	Set objCommand = CreateObject("ADODB.Command")
	conn.Provider = "ADSDSOObject"
	conn.Open "ADs Provider"
	If (err.number <> 0) Then
		WScript.StdOut.WriteLine("Failed to bind to Active Directory server, error:" & err.Description)
		objfileError.WriteLine("Failed to bind to Active Directory server, error:" & err.Description)
		WScript.Quit
	End If

	Set objCommand.ActiveConnection = conn
	WScript.StdOut.WriteLine("Searching for mailbox owner user accounts in " & sDomainContainer)
	
	objCommand.CommandText  = "<LDAP://" & sDCServer & "/" & sDomainContainer & ">;(&(&(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(msExchHomeServerName=*)) ))));adspath;subtree"
	objCommand.Properties("searchscope") = ADS_SCOPE_SUBTREE
	objCommand.Properties("Page Size") = 100
	objCommand.Properties("Timeout") = 30 
	objCommand.Properties("Chase referrals") = (ADS_CHASE_REFERRALS_SUBORDINATE Or ADS_CHASE_REFERRALS_EXTERNAL)

	err.Clear	
	Set rsUsers = objCommand.Execute
	If (err.number <> 0) Then
		WScript.StdOut.WriteLine("Search for mailbox owners failed, error:" & err.Description)
		objfileError.WriteLine("Search for mailbox owners failed, error:" & err.Description)
		WScript.Quit
	End If

	If (rsUsers.RecordCount = 0) Then
		WScript.StdOut.WriteLine("No mailbox owner user accounts could be seen in " & sDomainContainer & ".")
		objfileError.WriteLine("No mailbox owner user accounts found in " & sDomainContainer & ".")
		fError = True		
	End If

	While Not rsUsers.EOF
		If (fOneError = True) Then
			WScript.StdOut.Write("!")
		Else
			WScript.StdOut.Write(".")
		End If
		fOneError = False
		
		'Skip any mailbox object in Microsoft Exchange System Objects container
		If (0 = Instr(rsUsers.Fields(0).Value, MESO)) Then
			err.Clear 
			Set objUser = GetObject(rsUsers.Fields(0).Value)
			If (err.number <> 0) Then
				objfileError.WriteLine("Failed to get user object: " & rsUsers.Fields(0).Value)
				objfileError.WriteLine("Error: " & err.Description)
				fError = True
				fOneError = True
				err.Clear
			End If
			Set objSDMailBox = objUser.MailboxRights
			If (err.number <> 0) Then
				objfileError.WriteLine("Failed to get mailbox rights: " & rsUsers.Fields(0).Value)
				objfileError.WriteLine("Error: " & err.Description)
				fError = True
				fOneError = True
				err.Clear
			End If
			Set objSDNTsecurity = objUser.ntSecurityDescriptor
			If (err.number <> 0) Then
				objfileError.WriteLine("Failed to get NTSD: " & rsUsers.Fields(0).Value)
				objfileError.WriteLine("Error: " & err.Description)
				fError = True
				fOneError = True
				err.Clear
			End If
			
			Set objDACLNTSD = Nothing
			If (objUser.AccountDisabled) Then
				sMailboxStatus = "Disabled"
			Else
				sMailboxStatus = "Enabled"
			End If

			'Query this user's publicDelegates list
			err.Clear 
			msPublicDelegates = objUser.Get("publicDelegates")
			If (err.number <> 0) Then
				'This user doesn't have publicDelegates list set
				sIfPublicDelegate = STRNO
				err.Clear
			Else
				sIfPublicDelegate = STRYES
			End If
			
			err.Clear 			
			FindAllFMAUsers objSDMailBox
			
			If (TotalACE > dArraySize) Then
			'Needs to allocate bigger size array
				dArraySize = TotalACE + 1
				ReDim Preserve sTrusteeAlias(dArraySize)
				FindAllFMAUsers objSDMailBox
			End If
			If (err.number <> 0) Then
				objfileError.WriteLine("Failed to query mailbox rights of user: " & rsUsers.Fields(0).Value)
				objfileError.WriteLine("Error: " & err.Description)
				err.Clear
				fError = True
				fOneError = True
			End If
			
			If TotalACE > 0 Then
				Set objDACLNTSD = objSDNTsecurity.DiscretionaryAcl

				For i = 0 to TotalACE - 1 Step 1
					
					'Check if we already have Send As ACE in NT security descriptor
					'If it exists, either allow or deny, we don't need to add send as to it 
					CheckSendAsACE objDACLNTSD, sTrusteeAlias(i)
					
					'Note: deny entries take precedence over allow entries. 
					'If there is FMA deny ACE, skip it even if we find FMA allow ACE 
					IfFMAAllowed(sTrusteeAlias(i) & OUTPUT_DELIMITER)
					If ((fFMAAllowed = True) And (fACESendasFound = 0)) Then
						If cScriptMode = MODE_SETALL Then
							Set objNewACE = CreateObject ("AccessControlEntry")
							objNewACE.AceFlags = 0 
							objNewACE.AceType = ACCESS_ALLOWED_OBJECT_ACE_TYPE
							objNewACE.AccessMask = EX_MB_SEND_AS_ACCESSMASK 
							objNewACE.Flags = 1
							objNewACE.ObjectType = EX_MB_SEND_AS_GUID
							objNewACE.Trustee = sTrusteeAlias(i)

							objDACLNTSD.AddAce objNewAce
						End If
			
						'Query trustee(FMA user) to get its displayName
						Dim rsTrustee
						Dim objTrustee
						Dim dPosition
						Dim sAlias
					
						dPosition = inStr(1, sTrusteeAlias(i), "\")
						sAlias = mid(sTrusteeAlias(i), dPosition + 1)
				
						Set objCmdDisplayName = CreateObject("ADODB.Command")			
						Set objCmdDisplayName.ActiveConnection = conn
						objCmdDisplayName.CommandText  = "<LDAP://" & sDomainContainer & ">;(&(&(& (mailnickname=" & sAlias & ") (| (&(objectCategory=person)(objectClass=user)(msExchHomeServerName=*)) ))));adspath;subtree"
						objCmdDisplayName.Properties("searchscope") = ADS_SCOPE_SUBTREE
						objCmdDisplayName.Properties("Page Size") = 100
						objCmdDisplayName.Properties("Timeout") = 30 
						objCmdDisplayName.Properties("Chase referrals") = (ADS_CHASE_REFERRALS_SUBORDINATE Or ADS_CHASE_REFERRALS_EXTERNAL)
						
						Set rsTrustee = objCmdDisplayName.Execute				
						Set objTrustee = GetObject(rsTrustee.Fields(0).Value)
						
						If (err.number <> 0) Then
							'Failed to query FMA user's display name, use its alias
							sFMAUserDisplayName = sAlias							
						Else
							sFMAUserDisplayName = objTrustee.displayName							
						End If
	
						'output to export file
						err.Clear
						objfileExport.WriteLine ("""""""" & objUser.displayName & OUTPUT_DELIMITER & sTrusteeAlias(i) & OUTPUT_DELIMITER & sFMAUserDisplayName & OUTPUT_DELIMITER & sIfPublicDelegate & OUTPUT_DELIMITER & sMailboxStatus & OUTPUT_DELIMITER & rsUsers.Fields(0).Value & OUTPUT_DELIMITER & objUser.homeMDB & """""""")
						If (err.number <> 0) Then
							objfileError.WriteLine("User " & rsUsers.Fields(0).Value & " could not be added to the export file. You should set permissions manually for this user.")
							objfileError.WriteLine("Error: " & err.Description)
							err.Clear
							fError = True
							fOneError = True
						End If
						Set objCmdDisplayName = Nothing
						Set rsTrustee = Nothing
						Set objTrustee = Nothing
					End If
				Next
					
				If cScriptMode = MODE_SETALL Then
					err.Clear
					objSDNTsecurity.DiscretionaryAcl = objDACLNTSD
					objUser.Put "ntSecurityDescriptor", Array( objSDNTsecurity )
					objUser.SetOption ADS_OPTION_SECURITY_MASK, ADS_SECURITY_INFO_DACL
					objUser.SetInfo
					If (err.number <> 0) Then
						objfileError.WriteLine("Failed to update ADSI for user: " & rsUsers.Fields(0).Value)
						objfileError.WriteLine("Error: " & err.Description)
						err.Clear
						fError = True
						fOneError = True
					End If
				End If

				TotalACE = 0
				Set objSDMailbox = Nothing
				Set objSDNTsecurity = Nothing
				Set objUser = Nothing
				Set objDACLNTSD = Nothing
			End If
		
		End If	
		rsUsers.MoveNext
	Wend
End If

If (cScriptMode = MODE_IMPORT) Then
	Dim sOneRow
	Dim sArraySplit
	Dim objUserItem
	Dim UserPath
	Dim objUserSD
	Dim objUserDACL
	Dim fNeedToAddSendAs
	
	sImportFilePath = WScript.Arguments(ARG_INDEX_FILENAME)

	WScript.StdOut.WriteLine("If you continue, each account listed in " & sImportFilePath)
	WScript.StdOut.WriteLine("that has Full Mailbox Access permission for a given mailbox")
	WScript.StdOut.WriteLine("will also be granted permission to Send As the mailbox owner.")
	WScript.StdOut.WriteLine()
	WScript.StdOut.Write("Press Y to continue or any other key to cancel: ")
	strInput = WScript.StdIn.ReadLine()
	If (UCase(strInput) <> UCase("Y")) Then
		WScript.Quit
	End If	
	WScript.StdOut.WriteLine("Starting...")
	WScript.StdOut.WriteLine()

	UserPath = EMPTYSTRING	
	err.Clear	
	Set objFSO = CreateObject("Scripting.FileSystemObject")
	Set objfileImport = objFSO.OpenTextFile(sImportFilePath, ForReading, False, TristateTrue)
	If (err.number <> 0) Then
		WScript.StdOut.WriteLine("Failed to open import file " & sImportFilePath & ", error:" & err.Description)
		objfileError.WriteLine("Failed to open import file " & sImportFilePath & ", error:" & err.Description)
		WScript.Quit
	End If	

	fNeedToAddSendAs = False
	Do While objfileImport.AtEndOfStream <> True
		If (fOneError = True) Then
			WScript.StdOut.Write("!")
		Else
			WScript.StdOut.Write(".")
		End If
		fOneError = False

		err.Clear
		sOneRow = objfileImport.ReadLine
		sArraySplit = Split(sOneRow , OUTPUT_DELIMITER)
		If (err.number <> 0) Then
			objfileError.WriteLine("Failed to parse one row: " & sOneRow )
			objfileError.WriteLine("Error: " & err.Description)
			err.Clear
			fError = True
			fOneError = True
		End If
		
		If (UserPath <> sArraySplit(COLUMN_INDEX_USERADSPATH)) Then
			'A new user
			If (fNeedToAddSendAs = True ) Then
				'update existing user
				err.Clear 
				objSDNTsecurity.DiscretionaryAcl = objDACLNTSD
				objUser.Put "ntSecurityDescriptor", Array( objSDNTsecurity )
				objUser.SetOption ADS_OPTION_SECURITY_MASK, ADS_SECURITY_INFO_DACL
				objUser.SetInfo
				If (err.number <> 0) Then
					objfileError.WriteLine("Failed to update permissions for user: " & UserPath)
					objfileError.WriteLine("Error: " & err.Description)
					fError = True
					fOneError = True
				End If
			End If
						
			fNeedToAddSendAs = False
			Set objUser = Nothing
			Set objSDNTsecurity = Nothing
			Set objDACLNTSD = Nothing

			UserPath = sArraySplit(COLUMN_INDEX_USERADSPATH)
			err.Clear 
			Set objUser = GetObject(UserPath)
			Set objSDNTsecurity = objUser.ntSecurityDescriptor  
			Set objDACLNTSD = objSDNTsecurity.DiscretionaryACL			
			If (err.number <> 0) Then
				objfileError.WriteLine("Failed to get user object: " & UserPath)
				objfileError.WriteLine("Error: " & err.Description)
				err.Clear
				fError = True
				fOneError = True
			End If
		End If
	
		'Add newACE   Do we need this check?
		CheckSendAsACE objDACLNTSD, sArraySplit(COLUMN_INDEX_FMAALIAS)
		If (fACESendasFound = 0) Then
			Set objNewACE = CreateObject ("AccessControlEntry")
			objNewACE.AceFlags = 0 
			objNewACE.AceType = ACCESS_ALLOWED_OBJECT_ACE_TYPE
			objNewACE.AccessMask = EX_MB_SEND_AS_ACCESSMASK 
			objNewACE.Flags = 1
			objNewACE.ObjectType = EX_MB_SEND_AS_GUID
			objNewACE.Trustee = sArraySplit(COLUMN_INDEX_FMAALIAS)

			objDACLNTSD.AddAce objNewACE
			fNeedToAddSendAs = True			
		End If
	Loop
	
	If (fNeedToAddSendAs = True ) Then
		'update the last user
		err.Clear 
		objSDNTsecurity.DiscretionaryAcl = objDACLNTSD
		objUser.Put "ntSecurityDescriptor", Array( objSDNTsecurity )
		objUser.SetOption ADS_OPTION_SECURITY_MASK, ADS_SECURITY_INFO_DACL
		objUser.SetInfo
		If (err.number <> 0) Then
			objfileError.WriteLine("Failed to update permissions for user: " & UserPath)
			objfileError.WriteLine("Error: " & err.Description)
			fError = True
		End If
	End If

End If 

objFSO.Close
objfileImport.Close
objfileExport.Close
objfileError.Close

Set objFSO = Nothing
Set objfileImport = Nothing
Set objfileExport = Nothing
Set objfileError = Nothing
Set objCommand = Nothing
Set conn = Nothing

WScript.StdOut.WriteLine()
If (fError = True) Then
	WScript.StdOut.WriteLine("Finished with one or more errors. See " & sErrorsFilename)
Else
	WScript.StdOut.WriteLine("Finished successfully. No errors were encountered.")
End If

Function FindAllFMAUsers (objSD)
Dim objACL
Dim objACE
Dim intACECount
Dim strIndent
Dim dAccessMaskBit
Dim dPosition
Dim sUserAlreadyFound

	On Error Resume Next
	err.Clear
	TotalACE = 0
	sFMADeniedList = EMPTYSTRING
	sFMAExplicitAllow = EMPTYSTRING
	sUserAlreadyFound = OUTPUT_DELIMITER
	intACECount = 0
	Set objACL = objSD.DiscretionaryAcl
	intACECount = objACL.AceCount

	If intACECount Then
		' Open discretionary ACL (DACL) data.
		For Each objACE In objACL		
			
		dPosition = inStr(1, objACE.Trustee, "$")
		If ((0 = Instr(UCase(objACE.Trustee & OUTPUT_DELIMITER), UCase(FMA_EXCLUSIVE_EXSVC))) And (0 = Instr(sUserAlreadyFound, OUTPUT_DELIMITER & objACE.Trustee & OUTPUT_DELIMITER)) And (0 = Instr(FMA_EXCLUSIVE_LIST, OUTPUT_DELIMITER & objACE.Trustee & OUTPUT_DELIMITER)) And (dPosition <> Len(objACE.Trustee)) And ((objACE.AccessMask And EX_FULLMailbox_AccessMask) <>0) And ((objACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED) Or (objACE.AceType = ACCESS_ALLOWED_OBJECT_ACE_TYPE) )) Then
			If (TotalACE < dArraySize) Then
				sTrusteeAlias(TotalACE) = objACE.Trustee
				sUserAlreadyFound = sUserAlreadyFound & objACE.Trustee & OUTPUT_DELIMITER
			End If
			TotalACE = TotalACE + 1	
			If ((objACE.AceFlags And ADS_ACEFLAG_INHERITED_ACE) = 0) Then
				'Keep a list who explictly set FMA at mailbox level
				sFMAExplicitAllow = sFMAExplicitAllow & objACE.Trustee & OUTPUT_DELIMITER			
			End If
		ElseIf (( (objACE.AccessMask And EX_FULLMailbox_AccessMask) <>0 ) And (objACE.AceType = ADS_ACETYPE_ACCESS_DENIED)) Then
			'Keep a list who denied FMA, use OUTPUT_DELIMITER as demiliter, 
			'include both inherited and explicit set at mailbox level
			sFMADeniedList = sFMADeniedList & objACE.Trustee & OUTPUT_DELIMITER			
		End If
		Next
	End If

	Set objACL = Nothing
End Function

Function CheckSendAsACE (objDiscretionaryACL, sTAlias)
Dim objACE
Dim intACECount

	err.Clear 
	fACESendasFound = 0
	intACECount = objDiscretionaryACL.AceCount

	If intACECount Then
		For Each objACE In objDiscretionaryACL	
			err.Clear 
			If ( (objACE.Trustee = sTAlias) And (objACE.ObjectType = EX_MB_SEND_AS_GUID) ) Then
				fACESendasFound = 1
			End If
			If (err.number <> 0) Then
				objfileError.WriteLine("Could not read permissions for this user: " & sTAlias)
				objfileError.WriteLine("Error: " & err.Description)
				err.Clear
				fError = True
				fOneError = True
			End If			
		Next			
	End If	
End Function

Function IfFMAAllowed(sTrustee)
	'FMA allow ACE has been found. Assume it's true
	fFMAAllowed = True
	
	If ( (0 <> Instr(sFMADeniedList, sTrustee)) And (0 = Instr(sFMAExplicitAllow, sTrustee))	) Then
		'If Denied ACE is found, and no explicit allow FMA 
		fFMAAllowed = False
	End If 
End Function

Function CreateOutputFiles
	Dim sTimeArray
	Dim sTimeShort
	Dim sTime
	
	err.Clear
	sTime = Time
	sTimeShort = Split(sTime, " ")
	sTimeArray = Split(sTimeShort(0), ":")

	Set objFSO = CreateObject("Scripting.FileSystemObject")
	sErrorsFileName = ERROR_FILE & "_" & sTimeArray(0) & "_" & sTimeArray(1) & "_" & sTimeArray(2) & ".txt"
	Set objfileError = objFSO.OpenTextFile(sErrorsFileName, ForWriting, True, TristateTrue)

	If (cScriptMode = MODE_SETALL Or cScriptMode = MODE_EXPORT)	Then
		sExportFileName = EXPORT_FILE & "_" & sTimeArray(0) & "_" & sTimeArray(1) & "_" & sTimeArray(2) & ".txt"
		Set objfileExport = objFSO.OpenTextFile(sExportFileName, ForWriting, True, TristateTrue)	
	End If
	
	If err.number <> 0 Then
		WScript.StdOut.WriteLine("Unable to create export or error files: " & err.Description)
		objfileError.WriteLine("Unable to create export or error files: " & err.Description)
		fError = True
		fOneError = True
		WScript.Quit	
	End If

End Function

Function DisplaySyntax
	WScript.StdOut.WriteLine("Syntax:")
	WScript.StdOut.WriteLine()
	WScript.StdOut.WriteLine("Export accounts with Full Mailbox Access that do not have Send As permission:")
	WScript.StdOut.WriteLine("     CSCRIPT """ & WScript.ScriptName & """ DOMAIN_CONTROLLER -Export")
	WScript.StdOut.WriteLine("         NOTE: The list will be saved to Send_As_Export_HH_MM_SS.txt")
	WScript.StdOut.WriteLine()
	WScript.StdOut.WriteLine("Grant Send As to all accounts listed in an export file:")
	WScript.StdOut.WriteLine("     CSCRIPT """ & WScript.ScriptName & """ DOMAIN_CONTROLLER -Import ""filename.txt""")
	WScript.StdOut.WriteLine()
	WScript.StdOut.WriteLine("Grant Send As to all accounts in the domain with Full Mailbox Access:")
	WScript.StdOut.WriteLine("     CSCRIPT """ & WScript.ScriptName & """ DOMAIN_CONTROLLER -SetAll")
	WScript.StdOut.WriteLine("         NOTE: Accounts will be listed in Send_As_Export_HH_MM_SS.txt")
	WScript.StdOut.WriteLine()
	WScript.StdOut.WriteLine("For all modes, errors are saved to Send_As_Errors_HH_MM_SS.txt")

	WScript.Quit	
End Function
END SCRIPT

Microsoft provides programming examples for illustration only, without warranty either expressed or implied. This includes, but is not limited to, the implied warranties of merchantability or fitness for a particular purpose. This article assumes that you are familiar with the programming language that is being demonstrated and with the tools that are used to create and to debug procedures. Microsoft support engineers can help explain the functionality of a particular procedure. However, they will not modify these examples to provide added functionality or construct procedures to meet your specific requirements.

For more information about the support options that are available from Microsoft, visit the following Microsoft Web site: The third-party products that this article discusses are manufactured by companies that are independent of Microsoft. Microsoft makes no warranty, implied or otherwise, about the performance or reliability of these products.

↑ Back to the top


Keywords: KB912918, kbprb, kbbug, kbpending, kbtshoot

↑ Back to the top

Article Info
Article ID : 912918
Revision : 19
Created on : 5/8/2012
Published on : 5/8/2012
Exists online : False
Views : 268