This script fetches emails from a given monitoring mailbox by searching messages for a given subject string.  In this case email messages sent by the ENow Management Suite.

Status messages are parsed to extract Disk Performance alert data for further processing in Power BI.

The mailbox is queried using Exchange Web Services (EWS). The EWS endpoint is identified by AutoDiscover.

The script exports the following columns for further processing: 

 

Requirements

 

PowerBI Result Example

This example shows that P04 and P08 have exceeded the critical and warning state disk performance thresholds more often than the other servers.


 

Example

 

PowerShell
Edit|Remove
 # Run script using default parameters 
 .\Get-EmailContent.ps1

Updates

Links

 

 

Code

 

PowerShell
Edit|Remove
<# 
  .SYNOPSIS 
  Fetch email content from monitoring emails generated by ENow Management Suite for further processing 
    
  Thomas Stensitzki 
     
  THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE  
  RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER. 
     
  Version 1.0, 2017-05-19 
 
  .DESCRIPTION 
     
  This script fetches emails from a given monitoring mailbox by searching messages for a given subject string. 
  In this case email messages sent by the ENow Management Suite (http://enowsoftware.com/) 
  The mailbox is queried using Exchange Web Services (EWS). The EWS endpoint is identified by AutoDiscover. 
 
  The script exports the following columns for further processing: 
  SERVER = Name of Exchange server reporting issue 
  DATE = Date of issue occurance (Short Date) 
  TIME = Time of issue occurance (Long Time) 
  IO = READ or WRITE 
  THRESHOLD = WARNING or CRITICAL 
  VALUE = reported value  
 
  .LINK  
  More information can be found at http://scripts.granikos.eu 
 
  .NOTES  
  Requirements  
  - Windows Server 2012 R2+   
  - Exchange Server 2013+ 
  - Exchange Web Services Library 
 
  Revision History  
  --------------------------------------------------------------------------------  
  1.0     Initial release 
     
  .PARAMETER TargetMailbox   
  Email address of the monitoring mailbox, Example: monitoring@mcscmemail.de 
 
  .PARAMETER MailboxFolderPath 
  mailbox folder path to search. The string is language specific (EN starts with '\Inbox', DE starts with '\Posteingang'), Example '\Inbox\My Monitoring' 
 
  .PARAMETER SubjectSearchString 
  Message subject of monitoring messages to find. Query uses LIKE. 
 
  .PARAMETER CsvFilename 
  File name of exported CSV 
 
  .EXAMPLE 
  Run script using default parameters 
  .\Get-EmailContent.ps1 
 
#> 
[CmdletBinding()] 
param( 
  [string]$TargetMailbox = 'exchangeadmins@bdr.de', 
  [string]$MailboxFolderPath = '\Posteingang\Mailscape\DiskPerformance Alert', 
  [string]$SubjectSearchString = 'DiskPerformance Alert', 
  [string]$CsvFilename = 'DiskPerformance.csv' 
) 
 
# Add Exchange Web Services DLL 
 
# local path to manages EWS library 
Add-Type -Path "D:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.WebServices.dll" 
 
# Some variables ####################### 
 
$MessageSubjectReplaceString = 'Critical Mailscape DiskPerformance Alert:' 
$SearchViewItemLimit = 1000 
 
# Preset string values 
$IssueWarning = 'Warning' 
$IssueCritical = 'Critical' 
 
# Any value larger than 50 milliseconds will be identifed as critical 
[double]$ThresholdCriticalRead = 50 
 
$ScriptDir = Split-Path -Path $script:MyInvocation.MyCommand.Path 
$CsvOutputFile = Join-Path $ScriptDir -ChildPath $CsvFilename 
 
function Parse-MessageBody { 
[CmdletBinding()] 
param( 
  [Parameter(Mandatory=$true)][string]$ServerName, 
  [Parameter(Mandatory=$true)][datetime]$DateTime, 
  [Parameter(Mandatory=$true)][string]$TheBody 
) 
  # Remove Html Tags 
  $TheBody = $TheBody -replace "<.*?>" 
  $TheBody2 = $TheBody.Split([System.Environment]::NewLine) 
  $ThresholdReadIssue = '' 
 
  [array]$ResultMatrix = @() 
 
  $DiskIoReadString = 'The Disk averaged read time of the Disk Performance test is' 
  $DiskIoWriteString = 'Disk Average Write Time is' 
 
  foreach ($item in $TheBody2) 
  { 
    if($item.Trim() -ne '') {  
      if($item.StartsWith($DiskIoReadString)) { 
        $string = $item.Replace($DiskIoReadString,'').Replace('millisecond.','').Trim() 
        $value = [double]($string.Replace(',','.')) 
 
        # Check whether critical or warning 
        if($value -ge $ThresholdCriticalRead) { 
          $ThresholdReadIssue = $IssueCritical 
        } 
        else { 
          $ThresholdReadIssue = $IssueWarning 
        } 
 
        $resultItem = @{} 
        $resultItem.Add('SERVER',$ServerName) 
        $resultItem.Add('DATE',$DateTime.ToShortDateString()) 
        $resultItem.Add('TIME',$DateTime.ToLongTimeString()) 
        $resultItem.Add('IO','READ') 
        $resultItem.Add('THRESHOLD',$ThresholdReadIssue) 
        $resultItem.Add('VALUE',$string) 
        $resultItem 
       
        $ResultMatrix +New-Object -TypeName PSObject -Property $resultItem 
      } 
      if($item.StartsWith($DiskIoWriteString)) { 
        $string = $item.Replace($DiskIoWriteString,'').Replace('.','').Trim() 
        $value = [double]($string.Replace(',','.')) 
 
        # Check whether critical or warning 
        if($value -ge $ThresholdCriticalRead) { 
          $ThresholdReadIssue = $IssueCritical 
        } 
        else { 
          $ThresholdReadIssue = $IssueWarning 
        } 
 
        $resultItem = @{} 
        $resultItem.Add('SERVER',$ServerName) 
        $resultItem.Add('DATE',$DateTime.ToShortDateString()) 
        $resultItem.Add('TIME',$DateTime.ToLongTimeString()) 
        $resultItem.Add('IO','WRITE') 
        $resultItem.Add('THRESHOLD',$ThresholdReadIssue) 
        $resultItem.Add('VALUE',$string) 
        $resultItem 
       
        $ResultMatrix +New-Object -TypeName PSObject -Property $resultItem 
      } 
    } 
 
  } 
 
  return $ResultMatrix 
} 
 
## MAIN ############################## 
 
try { 
  # We are working with Exchange 2013SP1+ 
  $Exchange2013SP1 = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1 
   
 
  # Create EWS Service object for the target mailbox name and EWS version 
  $EwsObject = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList $Exchange2013SP1  
 
  # We use the default credntials of the logged on user 
  $EwsObject.UseDefaultCredentials = $true 
  $EwsObject.AutodiscoverUrl($TargetMailbox) 
 
  # Fetch the Root folder ID for further  
  $RootFolderId = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$TargetMailbox) 
 
  $TargetFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($EwsObject,$RootFolderId)   
 
  # Split the mailbox folder path into an array   
  $FolderArray = $MailboxFolderPath.Split("\")  
 
  #Loop through the Split Array and do a Search for each level of folder  
  for ($FolderIndex = 1; $FolderIndex -lt $FolderArray.Length; $FolderIndex++) {  
    # $FolderArray[$FolderIndex]  
 
    #Perform search based on the displayname of each folder level  
    $FolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)  
    $FolderSearchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$FolderArray[$FolderIndex])  
 
    $FolderResults = $EwsObject.FindFolders($TargetFolder.Id,$FolderSearchFilter,$FolderView)  
     
    if ($FolderResults.TotalCount -gt 0){  
      foreach($folder in $FolderResults.Folders){  
          $TargetFolder = $folder                 
      }  
    }  
    else{  
      Write-Host 'Folder not found!' 
      $TargetFolder = $null   
      break   
    }      
  }   
 
  # Now search the appropriate folder for messages 
  # Create search message subject based search filter   
  $SearchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring([Microsoft.Exchange.WebServices.Data.ItemSchema]::Subject,$SubjectSearchString)  
 
  # Create an item count limited search view 
  $SearchView = New-Object Microsoft.Exchange.WebServices.Data.ItemView($SearchViewItemLimit) 
 
  # Create search target folder object 
  $SearchFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($EwsObject,$TargetFolder.ID)   
 
  # Fetch items from folder 
  $ItemResults = $SearchFolder.FindItems($SearchFilter,$SearchView) 
 
  # Define the result array 
  [array]$Results = @() 
 
  # A little host output  
  Write-Host ('Fetching on {0} messages' -f ($ItemResults.Items | Measure-Object).Count) 
 
  foreach ($item in $ItemResults.Items) 
  { 
    # Load item from web service 
    $item.Load() 
 
    # Fetch server name from message subject 
    $ServerName = ([string]$item.ConversationTopic).Replace($MessageSubjectReplaceString,'').Trim() 
 
    # Fetch datetime of message sent 
    $DateTime = [DateTime]::Parse([string]$item.DateTimeSent.DateTime) 
    $body = $item.Body 
 
    # Fetch email content and add to results 
    $Results += Parse-MessageBody -TheBody $body -DateTime $DateTime -ServerName $ServerName 
  } 
 
  # Create CSV export capable object 
  $Output = $Results.GetEnumerator() | ForEach-Object{New-Object -TypeName PSObject -Property([ordered]@{COMPUTER=$_.SERVER;DATE=$_.DATE;TIME=$_.TIME;IO=$_.IO;THRESHOLD=$_.THRESHOLD;VALUE=$_.VALUE})} 
 
  # Write output to disk 
  $Output| Export-Csv -Path $CsvOutputFile -Force -NoTypeInformation -Delimiter ';' -Encoding UTF8 
   
} 
catch { 
  Throw $_.InvocationInfo.PositionMessage 
}