Checking Digital Signatures of a specific file against multiple servers

Scenario:  The other day an article was written by ARS Technica on a mail server attack that steals massive number of passwords. One of the symptoms is finding an unsigned OWAAuth.DLL and in some cases the file was located in a different directory.

Solution: Here is a quick way to check all of your Exchange servers to make sure all of your OWAAUTH.DLL files are signed and in the correct path:

#Build your Servers Variable
$Servers = Get-exchangeserver
#Build your Auth Variable
$Auth = $Servers |  %{Get-childitem -path "\$_c$program filesMicrosoftExchange Serverv15" -filter owaauth.dll -recurse | Get-authenticodeSignature}
#Export your Auth Variable to read it in Excel
$Auth | Export-csv C:tempAuth.csv

 

Some internal recipients are not receiving messages when sent to Distribution Groups

Scenario:  Users are complaining that they sporadically miss email communications when the emails were sent to a specific distribution groups.  Upon further investigation of the distribution groups, the recipients that did not receive the email were members of other distribution groups that were nested two,three, and/or four times of that distribution group that was originally sent to.

Troubleshooting:  After pulling the message tracking log against all exchange servers, we noticed that the distribution groups were not expanding by seeing a 0 recipient count:

get-transportserver | Get-messagetrackinglog -subject “Testing” -resultsize unlimited -eventID Expand | Select RecipientCount,RelatedRecipientAddress

After investigating the distribution groups that were not expanding, we found that these distribution groups were mail enabled security groups AND they were set to Global and not Universal.  Apparently these groups were changed back to Global after the mail enabled security groups were created so they could be members of other global distribution groups. Thus we were experiencing ‘Black Hole’ distribution groups.

Solution:  After the user changed all the groups from Global to Universal, mail flow returned to normal.

EWS Script to Export Calendar Items to a CSV file via PowerShell

Scenario:  You need a script to export the calendar items of a mailbox into a CSV file.

Solution: Use the script below to export the calendar items of a mailbox into a CSV file.  Please note that the date range has a 2 year/1000 appointment max.  Depending on the number of items in the calendar between your date range, you may have to adjust the date range to accommodate the 1000 item limit. Also, give yourself full access to the mailbox you are querying. I used a section of Glen’s script because he nailed the attendee’s query. Props to Glen!

#Declare Variables
$EWSDLL = "C:Program FilesMicrosoftExchange ServerV15BinMicrosoft.Exchange.WebServices.dll"
$MBX = "teststeve@domain.com"
$EWSURL = "https://Ex2013Svr1.domain.com/EWS/Exchange.asmx"
$StartDate = (Get-Date).AddDays(-60)
$EndDate = (Get-Date)  

#Binding of the calendar of the Mailbox and EWS
Import-Module -Name $EWSDLL
$mailboxname = $MBX
$service = new-object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.Exchangeversion]::exchange2013)
$service.Url = new-object System.Uri($EWSURL)
$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar,$MailboxName) 
$Calendar = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)  
$Recurring = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([Microsoft.Exchange.WebServices.Data.DefaultExtendedPropertySet]::Appointment, 0x8223,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Boolean); 
$psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)  
$psPropset.Add($Recurring)
$psPropset.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;

$RptCollection = @()

$AppointmentState = @{0 = "None" ; 1 = "Meeting" ; 2 = "Received" ;4 = "Canceled" ; }

#Define the calendar view  
$CalendarView = New-Object Microsoft.Exchange.WebServices.Data.CalendarView($StartDate,$EndDate,1000)    
$fiItems = $service.FindAppointments($Calendar.Id,$CalendarView)
if($fiItems.Items.Count -gt 0){
 $type = ("System.Collections.Generic.List"+'`'+"1") -as "Type"
 $type = $type.MakeGenericType("Microsoft.Exchange.WebServices.Data.Item" -as "Type")
 $ItemColl = [Activator]::CreateInstance($type)
 foreach($Item in $fiItems.Items){
  $ItemColl.Add($Item)
 } 
 [Void]$service.LoadPropertiesForItems($ItemColl,$psPropset)  
}
foreach($Item in $fiItems.Items){      
 $rptObj = "" | Select StartTime,EndTime,Duration,Type,Subject,Location,Organizer,Attendees,AppointmentState,Notes,HasAttachments,IsReminderSet
 $rptObj.StartTime = $Item.Start  
 $rptObj.EndTime = $Item.End  
 $rptObj.Duration = $Item.Duration
 $rptObj.Subject  = $Item.Subject   
 $rptObj.Type = $Item.AppointmentType
 $rptObj.Location = $Item.Location
 $rptObj.Organizer = $Item.Organizer.Address
 $rptObj.HasAttachments = $Item.HasAttachments
 $rptObj.IsReminderSet = $Item.IsReminderSet
 $aptStat = "";
 $AppointmentState.Keys | where { $_ -band $Item.AppointmentState } | foreach { $aptStat += $AppointmentState.Get_Item($_) + " "}
 $rptObj.AppointmentState = $aptStat 
 $RptCollection += $rptObj
 foreach($attendee in $Item.RequiredAttendees){
  $atn = $attendee.Address + "; "  
  $rptObj.Attendees += $atn
  }
 foreach($attendee in $Item.OptionalAttendees){
  $atn = $attendee.Address + "; "  
  $rptObj.Attendees += $atn
 }
 foreach($attendee in $Item.Resources){
  $atn = $attendee.Address + "; "  
  $rptObj.Resources += $atn
 }
 $rptObj.Notes = $Item.Body.Text
#Display on the screen
 "Start:   " + $Item.Start  
 "Subject: " + $Item.Subject 
}   
#Export to a CSVFile
$RptCollection |  Export-Csv -NoTypeInformation -Path "c:temp$MailboxName-CalendarCSV.csv"

Replace A Mailbox’s Explicit Full Access Permission With A Mail Enabled Security Group To Allow Non-Admins To Manage Access.

Scenario:  Currently you have mailboxes that have explicit full access to a shared mailbox. Instead of giving full access permission at the root mailbox level, you want an automated way to define the full access permission to a mail enabled security group. You would like the distribution group populated with those mailboxes who had the explicit full access permission at the root mailbox level and then to remove those users explicit permission at the root mailbox level.  What you will be left with is a populated mail enabled security group with full permissions to a shared mailbox.

One of the biggest benefits for this is that you can assign a user as a  manager/owner of the distribution group who does not need Exchange permission.  They can then modify the membership of the group, thus giving or taking away full permission to other users for the shared mailbox without a call to the help desk.

Solution:  The script below will create a mail enabled security group which will be prefixed with ‘grp-‘, add the membership of the group for those users explicitly defined with full access to the shared mailbox and send-as permissions, add the group as having full control to the shared mailbox, and then remove the users explicit full access permission from the shared mailbox.

All you need is to either query, or import from a csv file, a list of shared mailboxes. If you use a csv file, make sure the column header is labeled Name.

#This script replaces a users explicit full access permission to a mailbox with a Mail Enabled Security Group that will have full access permission.

#This script will automatically gather those explicit users with full access permissions and put them into the mail enabled security group.

#This script give also make a specific user managedby permissions for the group.

#Import service accounts from CSV
$SvcMbx = Import-csv C:tempsvcmbx.csv

#Loop through each Service Mailbox
$SvcMbx | %{

#Define Variables
$N = $_.Name
$g = "GRP-"+$N
Write-Host "Now starting this service mailbox:$N"

#Gather FullMailbox permission with Explicit Access
$explicitmembers = (Get-MailboxPermission $N | Where {($_.IsInherited -eq $false) -and ($_.User -notlike '*Authority*') -and ($_.AccessRights -like "FullAccess")}).user

#Create the Mail Enabled Security Group and add the manager(s) of the group. Then lock the group down so it cannot accept messages except from the manager.
Write-Host "Creating the AD Universal Security Group"
New-ADGroup -name $g -GroupScope Universal -Path "OU=TestGroups,DC=domain,DC=com" -DisplayName $g 
Write-Host "Waiting for Replication"
Sleep 30
Write-Host "Provision the AD group as a Mail enabled Security Group"
Enable-DistributionGroup $g 
Write-Host "Waiting for Replication"
Sleep 30
Write-Host "Configuring the Mail Enabled Security Group:$g"
Set-distributionGroup $g -managedby "jdoe1" -bypasssecuritygroupmanagercheck -acceptmessagesonlyfrom "jdoe1" 

#Populate the explicit mailboxes that have permission to the service mailbox to the new mail enabled distribution group

Write-Host "Populating the Mail Enabled Security Group: Group:$g"
$explicitmembers | %{
Add-DistributionGroupMember $g -member $_.RawIdentity -bypasssecuritygroupmanagercheck 
}

#Add the mail enabled security group to the service mailbox with full permission and automapping set to false
Write-Host "Adding $g with Full Permission and Send As permission to $n" 
Add-mailboxpermission $n -user $g -accessrights fullaccess -automapping $false 
Add-ADPermission $n -user $g -extendedRights 'Send-As'

#Remove the users explicit access to the service mailbox
Write-host "Removing the users Explicit access to $n"
$explicitmembers | %{
Remove-mailboxPermission $n -user $_.RawIdentity -accessrights FullAccess -confirm:$false 
}
}

 

 

Script to Create Database and Database Copies

Scenario:  You would like to create Databases and Database Copies via a script. For each database, you want to set the Quotas for Send, Send/Receive, and Warning to unlimited as well.

Solution:

Create a db.csv file with the following column headers: DB,1,2,3,4.  In that CSV File, put the name of the DB in the DB column, and each server in its numerical location based on Activation Preference:

db,1,2,3,4
DB1,Ex2013Srv1,Ex2013Srv2,Ex2013Srv3,Ex2013Srv4
DB2,Ex2013Srv2,Ex2013Srv3,Ex2013Srv4,Ex2013Srv1
DB3,Ex2013Srv3,Ex2013Srv4,Ex2013Srv1,Ex2013Srv2
DB4,Ex2013Srv4,Ex2013Srv1,Ex2013Srv2,Ex2013Srv3

Then run the script:

#Import the CSV File into a Variable
$DBs = Import-CSV C:tempDb.csv

#Loop the Variable
$DBs | %{
#Declare variables for each column
$n = $_.DB
$1 = $_.1
$2 = $_.2
$3 = $_.3
$4 = $_.4

#Create the DB
Write-Host "Creating $n"
New-MailboxDatabase $n -EDBFilePath C:$nDB$n.edb -LogFolderPath C:$nLogs -Server $1 

#Wait for replication
Write-Host "Sleeping 3 minutes for replication"
Sleep 180

#Mount the Database
Write-Host "Mounting $n"
Mount-Database $n

#Wait for additional replication
Write-Host "Sleeping 3 minutes for replication"
Sleep 180

#Setting the DB Quotas
Write-Host "Setting DB Quotas to unlimited"
Set-MailboxDatabase $n -ProhibitSendReceiveQuota Unlimited -ProhibitSendQuota Unlimited -IssueWarningQuota Unlimited

#Create the additional Database Copies
Write-Host "Creating ActivationPreference2 for $n"
Add-MailboxDatabaseCopy $n -MailboxServer $2 -ActivationPreference 2
Write-Host "Creating ActivationPreference3 for $n"
Add-MailboxDatabaseCopy $n -MailboxServer $3 -ActivationPreference 3
Write-Host "Creating ActivationPreference4 for $n"
Add-MailboxDatabaseCopy $n -MailboxServer $4 -ActivationPreference 4
}

 

 

 

 

Configuring UploadReadAheadSize for Certificate Based Authentication for ActiveSync

Scenario: When configuring Certificate Based Authentication, you will have to configure the UploadReadAheadSize property in IIS to  allow message content greater than 48K.  Without the UploadReadAheadSize properly set, some symptoms you may experience are HTTP Status codes of 413 for ActiveSync Requests in the IIS logs  and mobile devices may experience size errors when attempting to send email.

Solution:

How to set the uploadReadAheadSize in IIS 7.5

  1. Launch “Internet Information Services (IIS) Manager”
  2. Expand the Server field
  3. Expand Sites
  4. Expand Default Web Site
  5. Click on Microsoft-Server-ActiveSync
  6. In the Features section, double click “Configuration Editor”
  7. Under “Section” select: system.webServer>serverRuntime
  8. Modify the “uploadReadAheadSize” section to 36700160 for 35MB.
  9. Click Apply

 

“The computer account ‘DAG1’ could not be validated. Access was denied. Check that the current user (NT AuthoritySystem) has permissions to create computer accounts in the domain or to claim the computer account”

Scenario:  When attempting to add your first server to a new DAG, you may receive the following error:

A server-side database availability group administrative operation failed. Error The operation failed. CreateCluster errors may result from incorrectly configured static
addresses. Error: The computer account ‘DAG1’ could not be validated. Access was denied. Check that the current user (NT AUTHORITYSYSTEM) has permissions to create
computer accounts in the domain or to claim the computer account.

Solution:  Once the DAG  Computer Account (CNO) is created and disabled, perform the following:

  1. Assign full control permission on the DAG CNO of the first Exchange Server you are trying to add to the DAG.
  2. Assign full control on the DAG CNO of Exchange Trusted Subsystem.

Try it again.

 

“The fully qualified domain name for node ‘DAG1’ could not be found” when trying to add a mailbox server as a member of the DAG.

Scenario:  When trying to add the first mailbox server to a new DAG, you receive the following error:  The fully qualified domain name for node ‘DAG1’ could not be found

Solution:   Add the FQDN to the dNSHostName AD attribute of the DAG for the computer account.

 

Exchange Script to collect the Alias and the LastLogonTime for a list of users.

Scenario:  You have a list of mailboxes in a csv file that you need to check the lastlogontime property for each mailbox.

Solution:

#Import CSV
$1 = Import-csv C:tempusers.csv

#Create the Variable
$final = @()

#Loop through your users.
$1 | %{
$alias = $_.name
$2 = Get-mailboxStatistics $_.name | Select DisplayName, LastLogonTime
$disp = $2.DisplayName
$LastLogon = $2.LastLogonTime

#Build the Array
 $ServerObj = New-Object PSObject
 $ServerObj | Add-Member NoteProperty -Name "Alias" -Value $alias
 $ServerObj | Add-Member NoteProperty -Name "DisplayName" -Value $disp
 $ServerObj | Add-Member NoteProperty -Name "LastLogonTime" -Value $lastlogon
     $Final += $ServerObj    
}

$final | Export-csv C:tempresults.csv

 

Exchange PowerShell to check to see if a list of mailboxes exist.

Scenario:  You have a list of mailboxes that you want to check to see if a mailbox exists for each user.  You want to output it to a table with a true or false.

Resolution: In my users.csv that I import, the column that I reference in this script has a column name labeled ‘name’. Note: If a mailbox doesn’t exist, it may display with “The operation couldn’t be performed because object couldn’t be found” in the Powershell window.  The $Final variable will have a clean list with true or false for each mailbox.

#Create the Variable
$final = @()

#Import the CSV file with a column labeled 'name'.
$1 = Import-CSV C:tempusers.csv
 
#Loop it for each entry
$1 | %{
$n = $_.name
$r = [bool](get-mailbox "$n")

#Build the Array
 $ServerObj = New-Object PSObject
 $ServerObj | Add-Member NoteProperty -Name "User" -Value $n
 $ServerObj | Add-Member NoteProperty -Name "Exists" -Value $r
     $Final += $ServerObj    
}

#Display the Results
$Final

#Export the CSV to a file
$Final | Export-csv C:tempResults_Users.csv