Collect Event Logs from Microsoft Exchange 2010 Servers

Introduction

This script could be used to collect warning and error events which generated by Microsoft Exchange Server 2010. You can collect these events by Exchange server role.

Scenarios

In a real world, IT Administrators need to collect warning and error events for troubleshooting and monitoring the health of Microsoft Exchange 2010. It will be a time-consuming task in a large scale deployment.

Script

This script contains one advanced function, Out-OSCEXEvents. You can use this script in following ways:

Method 1:

Download the script and copy it to a Microsoft Exchange 2010 Server.

Open the script file with Notepad or any other script editors.

Scroll down to the end of the script file, and then add the example command which you want to run.

Save the file then run the script in Exchange Management Shell.

Method 2:

Rename scriptname.ps1 to scriptname.psm1 (PowerShell Module file)

Run Import-Module cmdlet to import this module file in Exchange Management Shell. Import-Module filepath\scriptname.psm1

 

PowerShell
Edit|Remove
#requires -Version 2 
 
#Import Localized Data 
Import-LocalizedData -BindingVariable Messages 
 
Function New-OSCPSCustomErrorRecord 
{ 
    #This function is used to create a PowerShell ErrorRecord 
    [CmdletBinding()] 
    Param 
    ( 
        [Parameter(Mandatory=$true,Position=1)][String]$ExceptionString, 
        [Parameter(Mandatory=$true,Position=2)][String]$ErrorID, 
        [Parameter(Mandatory=$true,Position=3)][System.Management.Automation.ErrorCategory]$ErrorCategory, 
        [Parameter(Mandatory=$true,Position=4)][PSObject]$TargetObject 
    ) 
    Process 
    { 
        $exception = New-Object System.Management.Automation.RuntimeException($ExceptionString) 
        $customError = New-Object System.Management.Automation.ErrorRecord($exception,$ErrorID,$ErrorCategory,$TargetObject) 
        return $customError 
    } 
} 
 
Function Out-OSCEXEvents 
{ 
    <# 
        .SYNOPSIS 
        Out-OSCEXEvents is an advanced function which can be used to collect events from exchange servers. 
        .DESCRIPTION 
        Out-OSCEXEvents is an advanced function which can be used to collect events from exchange servers. 
        .PARAMETER ServerRole 
        Indicates the server role name of Microsoft Exchange 2010, the available values are MBX,HUB,CAS,UM,EDGE 
        .PARAMETER EventType 
        Indicates the type of event, the available values are Warning,Error,Both.         
        .PARAMETER StartDate 
        Indicates collect the events that occur after the specified date and time. 
        .PARAMETER EndDate 
        Indicates collect the events that occur before the specified date and time. 
        .PARAMETER Property 
        Indicates the event properties you want to collect. The default value is all properties. (Wildcard character) 
        .PARAMETER Credential 
        Indicates the credential which will be used for connecting remote servers. Typically, you should use this parameter when you collect events form EDGE server. 
        .PARAMETER FilePath 
        Indicates the text file path which will be used for saving event log entries. 
        .EXAMPLE 
        #Collect last 7 days error events from mailbox servers. 
        Out-OSCEXEvents -ServerRole "MBX" -StartDate ((Get-Date).AddDays(-7)) -EndDate (Get-Date) -EventType "Error" -Property "Message","MachineName" -FilePath "c:\scripts\mbx-events.txt" -Verbose 
        .EXAMPLE 
        #Collect error events which generated between 2012/03/23 00:00:00 and 2012/03/30 23:59:59 from client access servers. 
        Out-OSCEXEvents -ServerRole "CAS" -StartDate "2012/03/23 00:00:00" -EndDate "2012/03/30 23:59:59" -EventType "Error" -Property "Message","MachineName" -FilePath "c:\scripts\cas-events.txt" -Verbose 
        .EXAMPLE 
        #Collect last 7 days error events from mailbox servers and hub transport servers. By default Out-OSCEXEvents will append the log entries to the existing text file. 
        Out-OSCEXEvents -ServerRole "MBX" -StartDate ((Get-Date).AddDays(-7)) -EndDate (Get-Date) -EventType "Error" -Property "Message","MachineName" -FilePath "c:\scripts\exchange-events.txt" -Verbose 
        Out-OSCEXEvents -ServerRole "HUB" -StartDate ((Get-Date).AddDays(-7)) -EndDate (Get-Date) -EventType "Error" -Property "Message","MachineName" -FilePath "c:\scripts\exchange-events.txt" -Verbose 
        .EXAMPLE 
        #Collect last 7 days error events from edge servers. This example requires an administrator account with same password being existed on each edge server. 
        Out-OSCEXEvents -ServerRole "EDGE" -StartDate ((Get-Date).AddDays(-7)) -EndDate (Get-Date) -Property "Message" -Credential (Get-Credential "administrator") -FilePath "c:\scripts\edge-events.txt" -Verbose 
        .LINK 
        Windows PowerShell Advanced Function 
        http://technet.microsoft.com/en-us/library/dd315326.aspx         
    #> 
     
    [CmdletBinding()] 
    Param 
    ( 
        #Define parameters 
        [Parameter(Mandatory=$true,Position=1)] 
        [ValidateSet("MBX","HUB","CAS","UM","EDGE")] 
        [string]$ServerRole, 
        [Parameter(Mandatory=$false,Position=2)] 
        [ValidateSet("Warning","Error","Both")] 
        [string]$EventType="Error",         
        [Parameter(Mandatory=$true,Position=3)] 
        [datetime]$StartDate, 
        [Parameter(Mandatory=$true,Position=4)] 
        [datetime]$EndDate, 
        [Parameter(Mandatory=$false,Position=5)] 
        [string[]]$Property="*", 
        [Parameter(Mandatory=$false,Position=6)] 
        [System.Management.Automation.PSCredential]$Credential, 
        [Parameter(Mandatory=$true,Position=7)] 
        [string]$FilePath         
    ) 
    Process 
    { 
        $results=@() 
        #Use different kind of cmdlets to retrieve server list. 
        Switch -regex ($ServerRole) { 
            "MBX" { 
                $exchangeServers = Get-ExchangeServer -Verbose:$false | Where-Object {$_.ServerRole -match "Mailbox"} 
            } 
            "HUB" { 
                $exchangeServers = Get-ExchangeServer -Verbose:$false | Where-Object {$_.ServerRole -match "HubTransport"} 
            } 
            "CAS" { 
                $exchangeServers = Get-ExchangeServer -Verbose:$false | Where-Object {$_.ServerRole -match "ClientAccess"} 
            } 
            "UM" { 
                $exchangeServers = Get-ExchangeServer -Verbose:$false | Where-Object {$_.ServerRole -match "UnifiedMessaging"} 
            } 
            "EDGE" { 
                $exchangeServers = Get-ExchangeServer -Verbose:$false | Where-Object {$_.ServerRole -match "Edge"} 
            } 
        } 
        #For MBX, HUB, CAS and UM server, we can use Get-EventLog to collect event logs. 
        #For EDGE server ,we need use Get-WMIObject to collect event logs. 
        Switch -regex ($ServerRole) { 
            "MBX|HUB|CAS|UM" { 
                $evtEntries = @() 
                foreach ($exchangeServer in $exchangeServers) { 
                    $serverName = $exchangeServer.Name 
                    Try 
                    { 
                        $verboseMsg = $Messages.ConnectToComputer 
                        $verboseMsg = $verboseMsg -replace "Placeholder01",$serverName 
                        $pscmdlet.WriteVerbose($verboseMsg) 
                        #Retrieve event entries. 
                        if ($EventType -eq "Error") { 
                            $evtEntries = Get-EventLog -ComputerName $serverName -LogName Application -EntryType "Error" ` 
                            -Before $EndDate -After $StartDate -Source "MSExchange*","ESE*","msftesql-exchange*" -ErrorAction Stop 
                        } else { 
                            $evtEntries = Get-EventLog -ComputerName $serverName -LogName Application -EntryType "Error","Warning" ` 
                            -Before $EndDate -After $StartDate -Source "MSExchange*","ESE*","msftesql-exchange*" -ErrorAction Stop 
                        } 
                        $verboseMsg = $Messages.EventsNumber 
                        if ($evtEntries -ne $null) { 
                            $verboseMsg = $verboseMsg -replace "Placeholder01",$($evtEntries.Count) 
                        } else { 
                            $verboseMsg = $verboseMsg -replace "Placeholder01","0" 
                        } 
                        $pscmdlet.WriteVerbose($verboseMsg) 
                    } 
                    Catch 
                    { 
                        $pscmdlet.WriteError($error[0]) 
                    } 
                    $result = $evtEntries ` 
                    | Select-Object -Property *,@{Name="Message";Expression={$_.Message -replace "`r`n",""}} -ExcludeProperty Message ` 
                    | Select-Object -Property $Property 
                    Out-File -InputObject $result -FilePath $FilePath -Width 300 -Append 
                } 
            } 
            "EDGE" { 
                foreach ($exchangeServer in $exchangeServers) { 
                    $serverName = $exchangeServer.Name 
                    $verboseMsg = $Messages.ConnectToComputer 
                    $verboseMsg = $verboseMsg -replace "Placeholder01",$serverName 
                    $pscmdlet.WriteVerbose($verboseMsg) 
                    Try 
                    { 
                        $timeZoneBias = (Get-WmiObject -ComputerName $serverName -Credential $Credential -Namespace root\CIMV2 ` 
                        -Class Win32_TimeZone -Property Bias -EnableAllPrivileges -ErrorAction Stop).Bias 
                    } 
                    Catch 
                    { 
                        $pscmdlet.WriteError($Error[0]) 
                        return $null 
                    } 
                    #Convert local time to universal time. 
                    $startDate = (Get-Date $StartDate).ToUniversalTime() 
                    $endDate = (Get-date $EndDate).ToUniversalTime() 
                    #Convert universsal time from DateTime to DmtfDateTime, they will be used in the WQL. 
                    $startDmtfDate = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($StartDate) 
                    $endDmtfDate = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($EndDate) 
                    #Generate WMI filter. 
                    if ($EventType -eq "Both") { 
                        $evtFilter = "LogFile='Application' and (SourceName like 'MSExchange%' or SourceName like 'ESE%' or SourceName like 'msftesql-exchange%') and (TimeGenerated > '$startDmtfDate' and TimeGenerated < '$endDmtfDate') and (Type='Error' or Type='Warning')" 
                    } else { 
                        $evtFilter = "LogFile='Application' and (SourceName like 'MSExchange%' or SourceName like 'ESE%' or SourceName like 'msftesql-exchange%') and (TimeGenerated > '$startDmtfDate' and TimeGenerated < '$endDmtfDate') and Type='Error'" 
                    } 
                    #Display WQL filter for troubleshooting purpose. 
                    $verboseMsg = $Messages.WMIQueryString 
                    $verboseMsg = $verboseMsg -replace "Placeholder01",$evtFilter 
                    $pscmdlet.WriteVerbose($verboseMsg) 
                    #Collect event log entries from another computer with specified condition. 
                    Try 
                    { 
                        $wmiEvents = Get-WmiObject -ComputerName $serverName -Class Win32_NTLogEvent -Filter $evtFilter ` 
                        -Credential $Credential -Property $Property -EnableAllPrivileges -ErrorAction Stop 
                    } 
                    Catch 
                    { 
                        $errorMsg = $Messages.WMIConnectionFailed 
                        $errorMsg = $errorMsg -replace "Placeholder01",$ComputerName 
                        $errorMsg = $errorMsg -replace "Placeholder02",$Error[0] 
                        $customError = New-OSCPSCustomErrorRecord ` 
                        -ExceptionString $errorMsg ` 
                        -ErrorCategory NotSpecified -ErrorID 1 -TargetObject $pscmdlet 
                        $pscmdlet.WriteError($customError) 
                        return $null 
                    } 
                    $verboseMsg = $Messages.EventsNumber 
                    if ($wmiEvents -ne $null) { 
                        $verboseMsg = $verboseMsg -replace "Placeholder01",$($wmiEvents.Count) 
                    } else { 
                        $verboseMsg = $verboseMsg -replace "Placeholder01","0" 
                    }                     
                    $pscmdlet.WriteVerbose($verboseMsg) 
                    #Return events 
                    $result = $wmiEvents ` 
                    | Select-Object -ExcludeProperty Message,TimeWritten,TimeGenerated -Property *,` 
                    @{Name="Message";Expression={$_.Message -replace "`r`n",""}},` 
                    @{Name="TimeGenerated";Expression={[System.Management.ManagementDateTimeConverter]::ToDateTime($_.TimeGenerated).ToUniversalTime().AddMinutes($timeZoneBias)}},` 
                    @{Name="TimeWritten";Expression={[System.Management.ManagementDateTimeConverter]::ToDateTime($_.TimeWritten).ToUniversalTime().AddMinutes($timeZoneBias)}} 
                    $result = $result ` 
                    | Select-Object -Property *,@{Name="Message";Expression={$_.Message -replace "`r`n",""}} -ExcludeProperty Message ` 
                    | Select-Object -Property $Property 
                    Out-File -InputObject $result -FilePath $FilePath -Width 300 -Append 
                } 
            } 
        } 
    } 
} 
 

 

 

Examples

Example 01: Displays help about Get-OSCEXEvents
Command: Get-Help Out-OSCEXEvents -Full
Screenshot:

Example 02: Collect last 7 days error events from mailbox servers.
Command:
Out-OSCEXEvents -ServerRole "MBX" -StartDate ((Get-Date).AddDays(-7)) -EndDate (Get-Date) -EventType "Error" -Property "Message","MachineName" -FilePath "c:\scripts\mbx-events.txt" -Verbose
Screenshot:

Example 03: Collect error events which generated between 2012/03/23 00:00:00 and 2012/03/30 23:59:59 from client access servers.
Command:
Out-OSCEXEvents -ServerRole "CAS" -StartDate "2012/03/23 00:00:00" -EndDate "2012/03/30 23:59:59" -EventType "Error" -Property "Message","MachineName" -FilePath "c:\scripts\cas-events.txt" -Verbose
Screenshot:

Example 04: Collect last 7 days error events from mailbox servers and hub transport servers. By default Out-OSCEXEvents will append the log entries to the existing text file.
Command:
Out-OSCEXEvents -ServerRole "MBX" -StartDate ((Get-Date).AddDays(-7)) -EndDate (Get-Date) -EventType "Error" -Property "Message","MachineName" -FilePath "c:\scripts\exchange-events.txt" -Verbose
Out-OSCEXEvents -ServerRole "HUB" -StartDate ((Get-Date).AddDays(-7)) -EndDate (Get-Date) -EventType "Error" -Property "Message","MachineName" -FilePath "c:\scripts\exchange-events.txt" -Verbose
Screenshot:

 

Example 05: Collect last 7 days error events from edge servers. This example requires an administrator account with same password being existed on each edge server.
Command:
Out-OSCEXEvents -ServerRole "EDGE" -StartDate ((Get-Date).AddDays(-7)) -EndDate (Get-Date) -Property "Message" -Credential (Get-Credential "CNSHEDGESVR01\Administrator") -FilePath "c:\scripts\edge-events.txt" -Verbose
Screenshot:

 

 

Additional Resources

Technical Resource:

Windows PowerShell Advanced Function
http://technet.microsoft.com/en-us/library/dd315326.aspx

Forum Threads:

CAS server
http://forums.msexchange.org/m_1800554567/mpage_1/key_/tm.htm#1800554567