Sample Script to Search Incorrect msExchMasterAccountSid Status

 

The following script sample demonstrates a way to search Active Directory® directory service for Microsoft® Exchange Server mailbox accounts that have an incorrect msExchMasterAccountSid status. It will search for both enabled and disabled Active Directory accounts that are Exchange mailbox-enabled. The script also removes the Associated External Account right from enabled Active Directory accounts, which also clears msExchMasterAccountSid, and sets the Associated External Account for disabled accounts, which also sets msExchMasterAccountSid. If a disabled Active Directory account that is mailbox-enabled has no Associated External Account, the Associated External Account and msExchMasterAccountSid will be set to the well-known Self security identifier (SID). The log file that records problems found and changes made is called NoMAS_VBS.log.

' Begin script
Option Explicit
const LOGFILE = "NoMAS_VBS.log"

' Do not change anything below here unless you really know what you are doing.

const ACCESS_ALLOWED        = &h0
const FULL_MAILBOX_ACCESS      = &h1
const SEND_AS            = &h2
const CONTAINER_INHERIT_ACE      = &h2
const ASSOCIATED_EXTERNAL      = &h4
const READ_PERMISSIONS        = &h20000

Dim oConnection
Dim oRecordSet
Dim oRecordSet2
Dim oCommand
Dim strQuery
Dim strDomainNC
Dim oRootDSE
Dim i

Dim FSO
Set FSO = CreateObject("Scripting.FileSystemObject")

Dim TextStream
Set TextStream = FSO.OpenTextFile(LOGFILE, 8, TRUE)

TextStream.WriteLine("****************************************************************************")
TextStream.WriteLine("NoMAS.vbs, v0.2005.1.20, Microsoft Product Support Services")
TextStream.WriteLine("Started logging " + Cstr(Date()) + ", " + Cstr(Time()))
TextStream.WriteLine("****************************************************************************")

Dim oAce
Set oAce = CreateObject("AccessControlEntry")  

oAce.Trustee = "NT AUTHORITY\SELF"
oAce.AccessMask = (FULL_MAILBOX_ACCESS + SEND_AS + ASSOCIATED_EXTERNAL + READ_PERMISSIONS)
oAce.AceFlags = CONTAINER_INHERIT_ACE
oAce.AceType = ACCESS_ALLOWED

set oRootDSE = GetObject("LDAP://RootDSE")
strDomainNC = oRootDSE.Get("defaultNamingContext")
set oRootDSE = Nothing

Set oConnection   = CreateObject("ADODB.Connection")
oConnection.Provider   = "ADsDSOObject"
oConnection.Open "Active Directory Provider"

Set oCommand = CreateObject("ADODB.Command")
Set oCommand.ActiveConnection = oConnection

Dim strDomainQuery
strDomainQuery = "<LDAP://cn=System," + strDomainNC + ">;(objectCategory=trustedDomain);trustPartner;onelevel"

oCommand.CommandText = strDomainQuery
Set oRecordSet = oCommand.Execute

If oRecordSet.Eof Then
  TextStream.WriteLine("Didn't find any trusts, assuming single domain...")
  PerDomain(strDomainNC)
Else
  While Not oRecordSet.Eof
    strDomainNC = oRecordSet.Fields(0)
    PerDomain(strDomainNC)
    oRecordSet.MoveNext
  Wend
End If
      
'Clean up
oRecordSet.Close()
oRecordSet2.Close()
oConnection.Close()
TextStream.WriteLine("Finished at " + Cstr(Date()) + ", " + Cstr(Time()))
TextStream.WriteBlankLines(1)
TextStream.Close()
   
Set oRecordSet = Nothing
Set oRecordSet2 = Nothing
Set oConnection = Nothing

Sub PerDomain(strDomainNC)

  Dim strDisabledQuery
  strDisabledQuery = "<LDAP://"&strDomainNC&">;(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=2)(!(msExchMasterAccountSid=*))(msExchHomeServerName=*)(homeMDB=*));AdsPath;subTree"

  oCommand.CommandText = strDisabledQuery
  oCommand.Properties("Page Size") = 100

  Set oRecordSet2 = oCommand.Execute

  if oRecordSet2.Eof then
    TextStream.WriteLine("No broken disabled users were found.")
  Else
    
    i = 1     

    While Not oRecordSet2.Eof
      
      Dim oUser
      Set oUser = GetObject(oRecordSet2.Fields("AdsPath").Value)
      
      TextStream.WriteLine("Disabled user " + vbTab + oRecordSet2.Fields("AdsPath").Value + vbTab + " is missing msExchMasterAccountSid")
      
      Dim mailboxSD
      On Error Resume Next
      Set mailboxSD = oUser.MailboxRights
      
      If (Err.Number <> 0) Then
      TextStream.WriteLine("Failed to get MailboxRights, error 0x" + CStr(Hex(Err.Number)) + " : " + Err.Description)
      Err.Clear()
      End If
              
      Dim oDACL
      Set oDACL = mailboxSD.DiscretionaryAcl
      
      Dim bFoundMASInSD
      bFoundMASInSD = FALSE
      
      Dim ace
      for each ace in oDACL
        if ( ace.AccessMask And ASSOCIATED_EXTERNAL ) then
          bFoundMASInSD = TRUE
        end if
      next 
      
      if (FALSE = bFoundMASInSD) then
        oDACL.AddAce(oACE)
      end if
      
      ReorderDACL(oDACL)
      mailboxSD.DiscretionaryAcl = oDACL
      oUser.MailboxRights = Array(mailboxSD)
      
      On Error Resume Next
      oUser.SetInfo
      
      If (Err.Number <> 0) Then
      TextStream.WriteLine("Failed to SetInfo, error 0x" + CStr(hex(Err.Number)) + " : " + Err.Description)
      Err.Clear()
      End If            
      
      oDACL = Nothing
      mailboxSD = Nothing
      oUser = Nothing
      
      i = i+1
      On Error Goto 0
      oRecordSet2.MoveNext
      
    Wend
  TextStream.WriteLine("No more broken disabled users were found.")
  End if
      
  'Clean up
    
  oRecordSet2.Close()
    
  Dim strEnabledQuery
  strEnabledQuery = "<LDAP://"&strDomainNC&">;(&(objectCategory=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)((msExchMasterAccountSid=*))(msExchHomeServerName=*)(homeMDB=*));AdsPath;subTree"
    
  oCommand.CommandText = strEnabledQuery   
  Set oRecordSet2 = oCommand.Execute

  if oRecordSet2.Eof then
    TextStream.WriteLine("No broken enabled users were found.")
  Else
    
    i = 1     

    ' Iterate through the objects that match the filter
      
    While Not oRecordSet2.Eof
      
      Set oUser = GetObject(oRecordSet2.Fields("AdsPath").Value)
      
      TextStream.WriteLine("Enabled user " + vbTab + oRecordSet2.Fields("AdsPath").Value + vbTab + " has msExchMasterAccountSid")
      
      On Error Resume Next
      Set mailboxSD = oUser.MailboxRights
      
      If (Err.Number <> 0) Then
      TextStream.WriteLine("Failed to get MailboxRights, error 0x" + CStr(hex(Err.Number)) + " : " + Err.Description)
      Err.Clear()
      End If
              
      Set oDACL = mailboxSD.DiscretionaryAcl
      
      for each ace in oDACL
        if ((ace.AccessMask And ASSOCIATED_EXTERNAL) = ASSOCIATED_EXTERNAL) then
          ace.AccessMask = ace.AccessMask And Not ASSOCIATED_EXTERNAL            
        end if
      next 
      
      ReorderDACL(oDACL)
      mailboxSD.DiscretionaryAcl = oDACL
      oUser.MailboxRights = Array(mailboxSD)
      
      On Error Resume Next
      oUser.SetInfo
      
      If (Err.Number <> 0) Then
      TextStream.WriteLine("Failed to SetInfo, error 0x" + CStr(hex(Err.Number)) + " : " + Err.Description)
      Err.Clear()
      End If  
      
      oDACL = Nothing
      mailboxSD = Nothing
      oUser = Nothing
      
      i = i+1
      On Error Goto 0
      oRecordSet2.MoveNext
      
    Wend
    TextStream.WriteLine("No more broken enabled users were found.")
  End If

end Sub
   
Sub ReorderDACL(dacl)

  Set newdacl = CreateObject("AccessControlList")
  Set ImpDenyDacl = CreateObject("AccessControlList")
  Set InheritedDacl = CreateObject("AccessControlList")
  Set ImpAllowDacl = CreateObject("AccessControlList")
  Set InhAllowDacl = CreateObject("AccessControlList")
  Set ImpDenyObjectDacl = CreateObject("AccessControlList")
  Set ImpAllowObjectDacl = CreateObject("AccessControlList")

  For Each ace In dacl

     If ((ace.AceFlags And ADS_ACEFLAG_INHERITED_ACE) = ADS_ACEFLAG_INHERITED_ACE) Then
        InheritedDacl.AddAce ace
     Else

        Select Case ace.AceType

                        Case ADS_ACETYPE_ACCESS_ALLOWED
                        ImpAllowDacl.AddAce ace

                        Case ADS_ACETYPE_ACCESS_DENIED
                        ImpDenyDacl.AddAce ace

                        Case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
                        ImpAllowObjectDacl.AddAce ace

                        Case ADS_ACETYPE_ACCESS_DENIED_OBJECT
                        ImpDenyObjectDacl.AddAce ace

                        Case Else

        End Select

     End If
  Next

  For Each ace In ImpDenyDacl
      newdacl.AddAce ace
  Next

  For Each ace In ImpDenyObjectDacl
      newdacl.AddAce ace
  Next

  For Each ace In ImpAllowDacl
      newdacl.AddAce ace
  Next

  For Each ace In impAllowObjectDacl
     newdacl.AddAce ace
  Next

  For Each ace In InheritedDacl
     newdacl.AddAce ace
  Next

  Set InheritedDacl     = Nothing
  Set ImpAllowDacl      = Nothing
  Set ImpDenyObjectDacl = Nothing
  Set ImpDenyDacl       = Nothing

  newdacl.AclRevision = dacl.AclRevision

  Set dacl = nothing
  Set dacl = newdacl

end Sub
'End Script

For More Information

For more information about the msExchMasterAccountSid attribute, see Detecting and Correcting msExchMasterAccountSid Issues.