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.
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.
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
#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
}
}
}
}
}
#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 } } } } }
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:

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