Exchange 2010 Powershell指令碼攻略(六)

ImSunkist發表於2011-07-12

CollectOverMetrics

param(

[string] $DatabaseAvailabilityGroup,

[string[]] $Database,

[string] $TemporaryDataPath,

[string] $ReportPath,

[DateTime] $StartTime = [DateTime]::MinValue,

[DateTime] $EndTime = [DateTime]::MaxValue,

[string] $ReportAlias,

[switch] $IncludeApplogs,

[string[]] $AppLogProviders,

[switch] $AnalyzeOnly,

[string] $MergedXmlFile,

[switch] $GenerateHtmlReport,

[switch] $ShowHtmlReport,

[switch] $DotSourceMode,

[switch] $Help,

[switch] $Verbose)

Set-StrictMode -Version 2.0

# Initialize variables that are used by functions

# Enable some debugging support to debug a specific operation id

$script:IsOperationIdDebugEnabled = 0

$script:OperationIdToBreakOn = ""

function DisplayHelp

{

Write-Host "

===============

Parameter Usage

===============

DatabaseAvailabilityGroup:

Name of database availability group. If nothing is specified then use the DAG which the

local node is a member of.

Database:

List of databases for which the *over report needs to be generated (can use wildcards)

e.g. -Database:"db1","db2"

-Database:"db*","Mailbox*"

TemporaryDataPath:

Location where temporary files will be stored. If nothing is specified, then

The name of directory will be decided by the following logic:

$env:SystemDriveTempCollectOverMetrics

StartTime:

Time at which the event data will start to be collected. If not specified, then

start time will be 12:00am yesterday

EndTime:

Time at which the event data will stop being collected. If not specified, then

collect events up to 11:59pm of yesterday

ReportPath:

Directory where the result of processing events will be stored

ReportAlias:

Email alias to which the generated reports needs to be emailed

IncludeApplogs:

Specify if application events should also be collected, merged and processed.

By default, the following providers will be included:

"MSExchangeIS", "MSExchangeIS Mailbox Store", "MSExchangeRepl"

AppLogProviders:

Specify if specific applog providers' events should be collected. If this is

specified, the above providers will not be included. Those need to be explicitly

specified again

AnalyzeOnly:

Specify if the data is already collected and only processing is required

MergedXmlFile:

Name of the file into which all of the event logs will be merged

GenerateHtmlReport:

Specify if a report needs to be prepared in a simple html table format for easy viewing

ShowHtmlReport:

Specify if an html generated report needs to be shown in an explorer window automatically

after it is generated

DotSourceMode:

Specify if nothing needs to be run immediately, but this file is dot sourced for using

powershell methods defined in it"

}

function LoadExchangeSnapin

{

if (!(get-command get-mailboxdatabase -ErrorAction:SilentlyContinue))

{

$snapIn = Get-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction:SilentlyContinue

if ($snapIn -eq $null)

{

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010

}

}

}

function LoadRequiredAssemblies

{

$linqAssembly = [System.Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")

}

function FindLocalDagName

{

$dagName = $null

$localMachine = [environment]::MachineName

$mbxServer = Get-MailboxServer $localMachine -ErrorAction:SilentlyContinue

if ($mbxServer -ne $Null)

{

$dagId = $mbxServer.DatabaseAvailabilityGroup

if ($dagId -ne $Null)

{

$dagName = $dagId.Name

}

else

{

ShowError("$localMachine is a standalone exchange server. It is not part of any database availability group")

}

}

else

{

ShowError("$localMachine is not a mailbox server")

}

return $dagName

}

function FindDag

{

param([string] $DagName)

$dag = $null

if ($DagName)

{

$dag = Get-DatabaseAvailabilityGroup $DagName -ErrorAction:SilentlyContinue

}

if ($dag -eq $Null)

{

ShowError("Unable to find database availability group named $DagName")

}

return $dag

}

function DetermineDatabases

{

param ($DagObject, [string[]] $DbNames)

$dbSuppliedHash = @{}

$dbGuidTable = $null

if ($DbNames -ne $Null)

{

$dbGuidTable = @{}

# If database is specified then find all the databases that match the wildcard

# that is specified in the argslist. Also make sure that a database appears

# only once in the list

foreach ($dbName in $DbNames)

{

foreach ($db in get-mailboxdatabase $dbName -ErrorAction:SilentlyContinue)

{

$dbSuppliedHash[$db.Name] = $db

}

}

# Make sure that the matching databases are configured in the dag

foreach ($server in $DagObject.Servers)

{

foreach ($db in get-mailboxdatabase -Server:$server.Name -ErrorAction:SilentlyContinue)

{

if ($dbSuppliedHash[$db.Name] -ne $null)

{

if (!$dbGuidTable.Contains($db.Guid))

{

$dbGuidTable[$db.Guid] = $db

}

}

}

}

if ($dbGuidTable.Count -eq 0)

{

ShowError("There are no databases to monitor for database availability group $($DagObject.Name)")

}

}

return $dbGuidTable

}

function FormatXml

{

param($RawXmlString, [switch] $KeepXmlNsSetting)

$stringToFormat = $RawXmlString

if (!$KeepXmlNsSetting)

{

# The following line will remove the name space settings - Having the name space settings

# causes unnecessary parsing issues

$stringToFormat = [System.Text.RegularExpressions.RegEx]::Replace($RawXmlString, 's*xmlns:*.*?=".*?"s*', "")

}

# The following line will format the single line xml string to a nice indented string

return [System.Xml.Linq.XElement]::Parse($stringToFormat).ToString()

}

function ShowError([string] $errorString)

{

write-error $errorString -ErrorAction:Stop

}

function OutputObject

{

param($FileName, $IsAppend = $true)

Begin

{

}

Process

{

if ($FileName)

{

if ($IsAppend)

{

$_ >> $FileName

}

else

{

$_ > $FileName

}

}

$_

}

End

{

}

}

function EventToXmlCore

{

param([int] $Mode, $EventXml, [switch] $FormattingRequired)

if ($mode -eq 1)

{

''

''

}

elseif ($mode -eq 2)

{

if ($FormattingRequired)

{

FormatXml -RawXmlString:$EventXml.OuterXml

}

else

{

$EventXml.OuterXml

}

}

elseif ($mode -eq 3)

{

''

}

}

function EventToXmlFilter

{

param([switch] $FormattingRequired)

Begin

{

EventToXmlCore -Mode:1 -FormattingRequired:$FormattingRequired

}

Process

{

$eventXml = [xml] ($_.ToXml());

if ($IncludeMessage)

{

$msgNode = $eventXml.CreateElement("Message");

$msgNode.InnerText = $_.Message;

$x = $eventXml.Event.System.AppendChild($msgNode);

}

EventToXmlCore -Mode:2 -EventXml:$eventXml -FormattingRequired:$FormattingRequired

}

End

{

EventToXmlCore -Mode:3 -FormattingRequired:$FormattingRequired

}

}

function SaveEventToXmlFilter

{

param($OutputFileName, [switch] $FormattingRequired = $true)

Begin

{

EventToXmlCore -Mode:1 -EventXml:$_ -FormattingRequired:$FormattingRequired > $OutputFileName

}

Process

{

EventToXmlCore -Mode:2 -EventXml:$_ -FormattingRequired:$FormattingRequired >> $OutputFileName

$_

}

End

{

EventToXmlCore -Mode:3 -EventXml:$_ -FormattingRequired:$FormattingRequired >> $OutputFileName

}

}

function GrabEvents

{

param($LogName,

$ProviderName,

$ServerName,

[switch] $IncludeMessage,

$StartTime = (new-object DateTime),

$EndTime = [DateTime]::Now)

if ($StartTime.Year -gt 1)

{

# To offset the fractions start from one seconds previous

$StartTime = $StartTime.AddSeconds(-1)

}

$EndTime = $EndTime.AddSeconds(1)

$providerStr = ""

if ($ProviderName)

{

$providerStr = " Provider(s): "

}

Write-Host "Retrieving events from $ServerName for Log(s): $providerStr"

$strStartTime = $StartTime.ToUniversalTime().ToString("o")

$strEndTime = $EndTime.ToUniversalTime().ToString("o")

$providerQuery = $null

if ($ProviderName)

{

$providers = [string]::Join(" or ", @($ProviderName | foreach { "@Name='$_'" }))

$providerQuery = "Provider[$providers]"

}

$timeRangeQuery = "TimeCreated[@SystemTime>'$strStartTime' and @SystemTime<'$strEndTime']"

$innerQueryStr = $providerQuery

if ($providerQuery)

{

$innerQueryStr += " and "

}

$innerQueryStr += $timeRangeQuery

$xmlQuery = `

"

*[System[$innerQueryStr]]

"

get-winevent -ComputerName:$ServerName -FilterXML $xmlQuery -Oldest -ErrorAction:SilentlyContinue

}

function GetServerEvents

{

param($ServerName,

[switch] $IncludeMessage,

[switch] $IncludeApplogs,

[string] $OutputDirectory,

$StartTime = (new-object DateTime),

$EndTime = [DateTime]::Now)

foreach ($oneServerName in @($ServerName))

{

$HACrimsonOpsFileName = [System.IO.Path]::Combine($OutputDirectory, "$($oneServerName)_HACrimsonOps.xml")

GrabEvents `

-LogName:"Microsoft-Exchange-HighAvailability/Operational" `

-ServerName:$oneServerName `

-IncludeMessage:$IncludeMessage `

-StartTime:$StartTime `

-EndTime:$EndTime | EventToXmlFilter -FormattingRequired > $HACrimsonOpsFileName

$HACrimsonDebugFileName = [System.IO.Path]::Combine($OutputDirectory, "$($oneServerName)_HACrimsonDebug.xml")

GrabEvents `

-LogName:"Microsoft-Exchange-HighAvailability/Debug" `

-ServerName:$oneServerName `

-IncludeMessage:$IncludeMessage `

-StartTime:$StartTime `

-EndTime:$EndTime | EventToXmlFilter -FormattingRequired > $HACrimsonDebugFileName

$FailureItemFileName = [System.IO.Path]::Combine($OutputDirectory, "$($oneServerName)_FailureItems.xml")

GrabEvents `

-LogName:"Microsoft-Exchange-MailboxDatabaseFailureItems/Operational" `

-ServerName:$oneServerName `

-IncludeMessage:$IncludeMessage `

-StartTime:$StartTime `

-EndTime:$EndTime | EventToXmlFilter -FormattingRequired > $FailureItemFileName

if ($IncludeApplogs -or $AppLogProviders)

{

$providers = @("MSExchangeIS", "MSExchangeIS Mailbox Store", "MSExchangeRepl")

if ($AppLogProviders)

{

$providers = $AppLogProviders

}

$AplicationFileName = [System.IO.Path]::Combine($OutputDirectory, "$($oneServerName)_Application.xml")

GrabEvents `

-LogName:"Application" `

-ProviderName:$providers `

-ServerName:$oneServerName `

-IncludeMessage:$IncludeMessage `

-StartTime:$StartTime `

-EndTime:$EndTime | EventToXmlFilter -FormattingRequired > $AplicationFileName

}

}

}

function PrepareEventReader

{

param([string] $FileName)

$reader = new-object object

Add-Member -InputObject $reader -MemberType "NoteProperty" -Name "FileName" -Value $FileName

Add-Member -InputObject $reader -MemberType "NoteProperty" -Name "StreamReader" -Value $null

Add-Member -InputObject $reader -MemberType "NoteProperty" -Name "XmlReader" -Value $null

Add-Member -InputObject $reader -MemberType "NoteProperty" -Name "IsFinished" -Value $false

Add-Member -InputObject $reader -MemberType "NoteProperty" -Name "LastReadEvent" -Value $null

Add-Member -InputObject $reader -MemberType "NoteProperty" -Name "LastEventTimeCreated" -Value $null

$reader.StreamReader = new-object System.IO.StreamReader $FileName

$reader.XmlReader = new-object System.Xml.XmlTextReader $reader.StreamReader

return $reader

}

function CleanupEventReader

{

param([object] $reader)

$reader.StreamReader.Close()

}

function ReadNextEvent

{

param($XmlEventReader)

if (!$XmlEventReader.IsFinished)

{

while ($XmlEventReader.XmlReader.Read())

{

if (($XmlEventReader.XmlReader.NodeType -eq [System.Xml.XmlNodeType]::Element) -and ($XmlEventReader.XmlReader.Name -ieq "Event"))

{

$reader.LastReadEvent = [xml] ($XmlEventReader.XmlReader.ReadOuterXml())

$sysTime = $reader.LastReadEvent.Event.System.TimeCreated.GetAttribute("SystemTime")

$reader.LastEventTimeCreated = [DateTime]::Parse($sysTime, [System.Globalization.CultureInfo]::InvariantCulture)

return $true;

}

}

$XmlEventReader.IsFinished = $true

}

return $false

}

function GetEventTimeObjFromEvent

{

param ($eventObj)

$sysTime = $eventObj.Event.System.TimeCreated.GetAttribute("SystemTime");

$dateOfEvent = [DateTime]::Parse($sysTime, [System.Globalization.CultureInfo]::InvariantCulture);

return $dateOfEvent

}

function GetEventTimeFromEvent

{

param ($eventObj)

$dateOfEvent = GetEventTimeObjFromEvent $eventObj

return $dateOfEvent.ToString("s")+"."+$dateOfEvent.ToString("fff") # Sortable format

}

function GetEventIdFromEvent

{

param ($eventObj)

$eventId = 0

$id = $eventObj.Event.System.EventID;

if ($id.GetType().Name -ieq "string")

{

$eventId = [int] $id

}

else

{

$eventId = [int] $id.InnerText

}

return $eventId

}

function GetShortComputerName

{

param ($fqdnComputerName)

$shortName = ""

if (![string]::IsNullOrEmpty($fqdnComputerName))

{

$index = [int] $fqdnComputerName.IndexOf('.')

if ($index -gt 0)

{

$shortName = $fqdnComputerName.Substring(0, $index)

}

}

return $shortName

}

function GetUserDataElementIfExist

{

param ($EventObj, $MemberName)

$memberValue = $null;

try

{

$memberValue = $eventObj.Event.UserData.EventXML.$memberName

}

catch [System.Exception]

{

}

return $memberValue

}

function GetOperationIdFromEvent

{

param ($eventObj)

$uniqueId = GetUserDataElementIfExist -EventObj:$eventObj -MemberName:"UniqueId"

return $uniqueId

}

function GetSubactionAttemptIdFromEvent

{

param ($eventObj)

$attemptNumber = GetUserDataElementIfExist -EventObj:$eventObj -MemberName:"AttemptNumber"

return $attemptNumber

}

function GetDatabaseGuidFromEvent

{

param ($eventObj)

return [Guid] ($eventObj.Event.UserData.EventXML.DatabaseGuid)

}

function GetDatabaseNameFromEvent

{

param ($eventObj)

return $eventObj.Event.UserData.EventXML.DatabaseName

}

function InitializeEventFormatTableProperties

{

$script:DisplayEventTimeScriptBlock = {

GetEventTimeFromEvent $_

}

$script:DisplayEventIdScriptBlock = {

GetEventIdFromEvent $_

}

$script:DisplayComputerScriptBlock = {

GetShortComputerName $_.Event.System.Computer

}

$script:PrefferedEventProperties = @(

@{Label="EventTime"; Expression=$DisplayEventTimeScriptBlock; width=24}, `

@{Label="ID"; Expression=$DisplayEventIdScriptBlock; width=6}, `

@{Label="Computer"; Expression=$DisplayComputerScriptBlock; width=15}, `

@{Label="Message"; Expression={$_.Event.System.Message}; width=75}, `

@{Label="Channel"; Expression={$_.Event.System.Channel}}

)

$script:PrefferedEventPropertiesNoWidth = @(

@{Label="EventTime"; Expression=$DisplayEventTimeScriptBlock}, `

@{Label="ID"; Expression=$DisplayEventIdScriptBlock}, `

@{Label="Computer"; Expression=$DisplayComputerScriptBlock}, `

@{Label="Message"; Expression={$_.Event.System.Message}}, `

@{Label="Channel"; Expression={$_.Event.System.Channel}}

)

}

function ReadEvents

{

param([string] $FileName, [int] $MaxEvents = -1)

[object] $reader = PrepareEventReader -FileName:$FileName

$counter = 0;

while (ReadNextEvent -XmlEventReader:$reader)

{

if (($MaxEvents -ge 0) -and (++$counter -gt $MaxEvents))

{

break

}

$reader.LastReadEvent;

}

CleanupEventReader($reader)

}

function ReadAllEvents

{

param([string] $FileName, [switch] $PrintMessage, [switch] $PrintProperties, [switch] $PrintXml, [int] $MaxEvents)

[object] $reader = PrepareEventReader -FileName:$FileName

$counter = 0;

while (ReadNextEvent -XmlEventReader:$reader)

{

if (++$counter -gt $MaxEvents)

{

break

}

[System.Xml.XmlDocument] $eventXml = $reader.LastReadEvent;

$systemNode = $eventXml.Event.System

if ($PrintMessage)

{

$message = $systemNode["Message"]

if ($message -ne $null)

{

""

"Message: [ID# $($systemNode.EventID)] - $($message.InnerText)"

}

}

if ($PrintProperties)

{

$userData = $eventXml.Event["UserData"]

if ($userData -ne $null)

{

""

"Properties"

"=========="

foreach ($node in $userData.EventXml.GetEnumerator())

{

" $($node.Name) : $($node.InnerText)"

}

}

}

if ($PrintXml)

{

""

"XML"

"==="

FormatXml -RawXmlString:$eventXml.OuterXml

}

}

CleanupEventReader($reader)

}

function MergeEvents

{

param($InputDir, [int] $MaxEvents = -1)

if ($InputDir -eq $null)

{

write-error "Input directory can't be null"

return

}

#

# Populate an array list with the readers

#

$files = get-childitem $InputDir -Filter "*.xml" -ErrorAction:SilentlyContinue

$readers = @(1..$files.Count)

for ($ii = 0; $ii -lt $files.Count; $ii++)

{

$readers[$ii] = $null

}

$index = 0

foreach ($fileEntry in $files)

{

[object] $reader = PrepareEventReader -FileName:$fileEntry.FullName

if ($reader -ne $null)

{

if (ReadNextEvent($reader))

{

$readers[$index++] = $reader

}

else

{

CleanupEventReader $reader

}

}

}

#

# Sort reader objects

#

$readers = @($readers | sort-object -Property LastEventTimeCreated)

$eventCount = 0

while ($readers)

{

if (($MaxEvents -ne -1) -and (++$eventCount -gt $MaxEvents))

{

break

}

# Top of the list is always the one that we need to process

$reader = $readers[0]

# Output the following into the pipe

$reader.LastReadEvent

if (ReadNextEvent($reader))

{

$swapIndex = 0

# We got an event, but make sure that it is in the right place

# in the sorted list

for ($ii = 1; $ii -lt $readers.Count; $ii++)

{

if ($reader.LastEventTimeCreated -gt $readers[$ii].LastEventTimeCreated)

{

# swap the entries

$readers[$ii],$readers[$swapIndex] = $readers[$swapIndex], $readers[$ii]

$swapIndex = $ii

}

else

{

# everything is already sorted. so process the next item

break

}

}

}

else

{

# close the handles

CleanupEventReader $reader

if ($readers.Count -gt 1)

{

# following line just removes the first item from the list

$readers = $readers[1..($readers.Count-1)]

}

else

{

$readers = $null

}

}

}

}

function InitializeCrimsonIdentifiers

{

$xmlString = '

message="$(string.Message.ToplevelMountInitiated)"

symbol="ToplevelMountInitiated"

task="Task.DbAction"

template="Template.ToplevelMountInitiated"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.ToplevelMountFailed)"

symbol="ToplevelMountFailed"

task="Task.DbAction"

template="Template.ToplevelMountFailed"

level="win:Error"

channel="ReplayChannel" />

message="$(string.Message.ToplevelMountSuccess)"

symbol="ToplevelMountSuccess"

task="Task.DbAction"

template="Template.ToplevelMountSuccess"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.ToplevelDismountInitiated)"

symbol="ToplevelDismountInitiated"

task="Task.DbAction"

template="Template.ToplevelDismountInitiated"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.ToplevelDismountFailed)"

symbol="ToplevelDismountFailed"

task="Task.DbAction"

template="Template.ToplevelDismountFailed"

level="win:Error"

channel="ReplayChannel" />

message="$(string.Message.ToplevelDismountSuccess)"

symbol="ToplevelDismountSuccess"

task="Task.DbAction"

template="Template.ToplevelDismountSuccess"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.ToplevelMoveInitiated)"

symbol="ToplevelMoveInitiated"

task="Task.DbAction"

template="Template.ToplevelMoveInitiated"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.ToplevelMoveFailed)"

symbol="ToplevelMoveFailed"

task="Task.DbAction"

template="Template.ToplevelMoveFailed"

level="win:Error"

channel="ReplayChannel" />

message="$(string.Message.ToplevelMoveSuccess)"

symbol="ToplevelMoveSuccess"

task="Task.DbAction"

template="Template.ToplevelMoveSuccess"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.ToplevelRemountInitiated)"

symbol="ToplevelRemountInitiated"

task="Task.DbAction"

template="Template.ToplevelRemountInitiated"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.ToplevelRemountFailed)"

symbol="ToplevelRemountFailed"

task="Task.DbAction"

template="Template.ToplevelRemountFailed"

level="win:Error"

channel="ReplayChannel" />

message="$(string.Message.ToplevelRemountSuccess)"

symbol="ToplevelRemountSuccess"

task="Task.DbAction"

template="Template.ToplevelRemountSuccess"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.AcllInitiated)"

symbol="AcllInitiated"

task="Task.DbAction"

template="Template.AcllInitiated"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.AcllFailed)"

symbol="AcllFailed"

task="Task.DbAction"

template="Template.AcllFailed"

level="win:Error"

channel="ReplayChannel" />

message="$(string.Message.AcllSuccess2)"

symbol="AcllSuccess2"

task="Task.DbAction"

template="Template.AcllSuccess2"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.DirectMountInitiated)"

symbol="DirectMountInitiated"

task="Task.DbAction"

template="Template.DirectMountInitiated"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.DirectMountFailed)"

symbol="DirectMountFailed"

task="Task.DbAction"

template="Template.DirectMountFailed"

level="win:Error"

channel="ReplayChannel" />

message="$(string.Message.DirectMountSuccess)"

symbol="DirectMountSuccess"

task="Task.DbAction"

template="Template.DirectMountSuccess"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.StoreDismountInitiated)"

symbol="StoreDismountInitiated"

task="Task.DbAction"

template="Template.StoreDismountInitiated"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.StoreDismountFailed)"

symbol="StoreDismountFailed"

task="Task.DbAction"

template="Template.StoreDismountFailed"

level="win:Error"

channel="ReplayChannel" />

message="$(string.Message.StoreDismountSuccess)"

symbol="StoreDismountSuccess"

task="Task.DbAction"

template="Template.StoreDismountSuccess"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.ActiveServerChanged)"

symbol="ActiveServerChanged"

task="Task.DbAction"

template="Template.ActiveServerChanged"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.MountServerSkipped)"

symbol="MountServerSkipped"

task="Task.DbAction"

template="Template.MountServerSkipped"

level="win:Informational"

channel="ReplayChannel" />

message="$(string.Message.AcllReportedLoss)"

symbol="AcllReportedLoss"

task="Task.DbAction"

template="Template.AcllReportedLoss"

level="win:Warning"

channel="ReplayChannel" />

message="$(string.Message.ReportCurrentRole)"

symbol="ReportCurrentRole"

task="Task.General"

template="Template.ReportCurrentRole"

level="win:Informational"

channel="ReplayChannel" />

'

$xmlObject = [xml] "$xmlString"

$script:CrimsonSymToEventIdMap = @{}

$script:CrimsonEventIdToSymMap = @{}

$script:CrimsonEventIds = new-object object

$events = $xmlObject.events.event

for ($ii = 0; $ii -lt $events.count; $ii++)

{

$CrimsonSymToEventIdMap[$events[$ii].symbol] = [int] $events[$ii].value

$CrimsonEventIdToSymMap[[int] $events[$ii].value] = $events[$ii].symbol

Add-Member -InputObject $CrimsonEventIds -MemberType NoteProperty -Name $events[$ii].symbol -Value ([int] $events[$ii].value)

}

}

#

# Courtesy: http://www.leeholmes.com/blog/CreatingGenericTypesInPowerShell.aspx

#

function New-GenericObject

{

param(

[string] $typeName = $(throw "Please specify a generic type name"),

[string[]] $typeParameters = $(throw "Please specify the type parameters"),

[object[]] $constructorParameters

)

## Create the generic type name

$genericTypeName = $typeName + '`' + $typeParameters.Count

$genericType = [Type] $genericTypeName

if(-not $genericType)

{

throw "Could not find generic type $genericTypeName"

}

## Bind the type arguments to it

[type[]] $typedParameters = $typeParameters

$closedType = $genericType.MakeGenericType($typedParameters)

if(-not $closedType)

{

throw "Could not make closed type $genericType"

}

## Create the closed version of the generic type

,[Activator]::CreateInstance($closedType, $constructorParameters)

}

function IntializeEventIdGroups

{

$script:TopInitEvents = @{}

[void] $TopInitEvents.Add($CrimsonEventIds.ToplevelMountInitiated, 1)

[void] $TopInitEvents.Add($CrimsonEventIds.ToplevelDismountInitiated, 1)

[void] $TopInitEvents.Add($CrimsonEventIds.ToplevelMoveInitiated, 1)

[void] $TopInitEvents.Add($CrimsonEventIds.ToplevelRemountInitiated, 1)

$script:TopFailedEvents = @{}

[void] $TopFailedEvents.Add($CrimsonEventIds.ToplevelMountFailed, 1)

[void] $TopFailedEvents.Add($CrimsonEventIds.ToplevelDismountFailed, 1)

[void] $TopFailedEvents.Add($CrimsonEventIds.ToplevelMoveFailed, 1)

[void] $TopFailedEvents.Add($CrimsonEventIds.ToplevelRemountFailed, 1)

$script:TopSuccessEvents = @{}

[void] $TopSuccessEvents.Add($CrimsonEventIds.ToplevelMountSuccess, 1)

[void] $TopSuccessEvents.Add($CrimsonEventIds.ToplevelDismountSuccess, 1)

[void] $TopSuccessEvents.Add($CrimsonEventIds.ToplevelMoveSuccess, 1)

[void] $TopSuccessEvents.Add($CrimsonEventIds.ToplevelRemountSuccess, 1)

$script:SubactionEvents = @{}

[void] $SubactionEvents.Add($CrimsonEventIds.StoreDismountInitiated,0)

[void] $SubactionEvents.Add($CrimsonEventIds.StoreDismountFailed, 1)

[void] $SubactionEvents.Add($CrimsonEventIds.StoreDismountSuccess, 1)

[void] $SubactionEvents.Add($CrimsonEventIds.MountServerSkipped, 2)

[void] $SubactionEvents.Add($CrimsonEventIds.AcllInitiated, 3)

[void] $SubactionEvents.Add($CrimsonEventIds.AcllReportedLoss, 4)

[void] $SubactionEvents.Add($CrimsonEventIds.AcllFailed, 5)

[void] $SubactionEvents.Add($CrimsonEventIds.AcllSuccess2, 5)

[void] $SubactionEvents.Add($CrimsonEventIds.ActiveServerChanged, 6)

[void] $SubactionEvents.Add($CrimsonEventIds.DirectMountInitiated, 6)

[void] $SubactionEvents.Add($CrimsonEventIds.DirectMountFailed, 7)

[void] $SubactionEvents.Add($CrimsonEventIds.DirectMountSuccess, 7)

}

function IsSubactionEventId

{

param ($eventId)

$SubactionEvents.ContainsKey($eventId)

}

function IsTopLevelInitEventId

{

param ($eventId)

$TopInitEvents.Contains($eventId)

}

function IsTopLevelFailedEventId

{

param ($eventId)

$TopFailedEvents.Contains($eventId)

}

function IsTopLevelSuccessEventId

{

param ($eventId)

$TopSuccessEvents.Contains($eventId)

}

function InitializeSubOperation

{

param ($attemptNumber)

$opSubInfo = new-object object

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name AttemptNumber -value $attemptNumber

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name StoreDismountInitiated -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name StoreDismountFailed -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name StoreDismountSuccess -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name MountServerSkipped -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name AcllInitiated -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name AcllReportedLoss -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name AcllFailed -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name AcllSuccess2 -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name ActiveServerChanged -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name DirectMountInitiated -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name DirectMountFailed -value $null

Add-member -InputObject $opSubInfo -MemberType "NoteProperty" -Name DirectMountSuccess -value $null

return $opSubInfo

}

function InitializeOperation

{

param ($xmlEventObj)

$opInfo = new-object object

Add-member -InputObject $opInfo -MemberType NoteProperty -Name "DatabaseGuid" -value (GetDatabaseGuidFromEvent $xmlEventObj)

Add-member -InputObject $opInfo -MemberType NoteProperty -Name "DatabaseName" -value (GetDatabaseNameFromEvent $xmlEventObj)

Add-member -InputObject $opInfo -MemberType NoteProperty -Name "OperationId" -value (GetOperationIdFromEvent $xmlEventObj)

Add-member -InputObject $opInfo -MemberType NoteProperty -Name "IsSuccess" -value ([bool] $false)

Add-member -InputObject $opInfo -MemberType NoteProperty -Name "TopStartEvent" -value $xmlEventObj

Add-member -InputObject $opInfo -MemberType NoteProperty -Name "TopFinishEvent" -value $null

Add-member -InputObject $opInfo -MemberType NoteProperty -Name "SubactionAttempts" -value @{}

Add-member -InputObject $opInfo -MemberType NoteProperty -Name "LastAttemptId" -value ([int] 0)

return $opInfo

}

function ProcessFinishedEntries

{

param($EventObj, $OperationMap, $ReadyHash)

# Whenever we hit a completion event, check all the ready events

# to find if there are events which completed 5 mins before so

# that they will be completely ready with all the parameters

$nowFinishedOperationTime = GetEventTimeObjFromEvent $EventObj

$removeHash = $null

$readyHash.GetEnumerator() | foreach {

$tmpOperationId = $_.Name

$tmpOpInfo = $OperationMap[$tmpOperationId]

$timeRecoveryCompleted = GetEventTimeObjFromEvent $tmpOpInfo.TopFinishEvent

$diff = $nowFinishedOperationTime - $timeRecoveryCompleted

if ($diff.TotalMinutes -ge 5)

{

# Send the value to the pipeline

$tmpOpInfo

# We don't need to keep the values in the map anymore. So remove the entries

if (!$removeHash)

{

$removeHash = @{}

}

[Void] $removeHash.Add($tmpOperationId, 1)

}

}

if ($removeHash)

{

$removeHash.GetEnumerator() | foreach {

# Operation is completely processed. So remove from the

# referencing lists

[Void] $ReadyHash.Remove($_.Name)

[Void] $OperationMap.Remove($_.Name)

}

}

}

function GroupEvent-ByOperation

{

Begin

{

$dbMap = @{}

$opMap = @{}

$readyHash = @{}

}

Process

{

$xmlEventObj = $_

$eventId = GetEventIdFromEvent $xmlEventObj

if (IsTopLevelInitEventId $eventId)

{

$operationId = GetOperationIdFromEvent $xmlEventObj

$dbMap[$eventId] = $operationId

$opInfo = InitializeOperation $xmlEventObj

$opMap[$operationId] = $opInfo

}

elseif (IsSubactionEventId $eventId)

{

$operationId = GetOperationIdFromEvent $xmlEventObj

if (!$operationId)

{

$dbGuid = GetDatabaseGuidFromEvent $xmlEventObj

$operationId = $dbMap[$dbGuid]

}

if ($operationId -and $opMap.ContainsKey($operationId))

{

$opInfo = $opMap[$operationId]

$attemptId = [int] (GetSubactionAttemptIdFromEvent $xmlEventObj)

if (!$attemptId)

{

$attemptId = $opInfo.LastAttemptId

}

$subOpInfo = $opInfo.SubactionAttempts[$attemptId]

if (!$subOpInfo)

{

$subOpInfo = InitializeSubOperation $attemptId

$opInfo.SubactionAttempts[$attemptId] = $subOpInfo

}

$memberName = $CrimsonEventIdToSymMap[$eventId]

$subOpInfo.$memberName = $xmlEventObj

$opInfo.LastAttemptId = $attemptId

}

}

elseif ((IsTopLevelFailedEventId $eventId) -or (IsTopLevelSuccessEventId $eventId))

{

ProcessFinishedEntries -EventObj:$xmlEventObj -OperationMap:$opMap -ReadyHash:$readyHash

$operationId = GetOperationIdFromEvent $xmlEventObj

if ($opMap.ContainsKey($operationId))

{

$opInfo = $opMap[$operationId]

$opInfo.IsSuccess = IsTopLevelSuccessEventId $eventId

$opInfo.TopFinishEvent = $xmlEventObj

# Operation ready. Move it to the ready list

[Void] $readyHash.Add($operationId, 1)

}

else

{

# TODO: Log a warning here for an operation that started before the start time specified

}

}

}

End

{

# After processing is complete now send all the values to pipeline

# If those were not already sent by the readyHash

foreach ($opPair in $opMap.GetEnumerator())

{

$opPair.Value

}

}

}

function CreateEmptyActionEntry

{

$entry = New-Object object

Add-Member -InputObject $entry -MemberType NoteProperty -Name DatabaseName -Value $null

Add-Member -InputObject $entry -MemberType NoteProperty -Name TimeRecoveryStarted -Value $null

Add-Member -InputObject $entry -MemberType NoteProperty -Name ActionInitiator -Value $null

Add-Member -InputObject $entry -MemberType NoteProperty -Name ActionCategory -Value $null

Add-Member -InputObject $entry -MemberType NoteProperty -Name ActionReason -Value $null

Add-Member -InputObject $entry -MemberType NoteProperty -Name Result -Value "Unknown"

Add-Member -InputObject $entry -MemberType NoteProperty -Name DurationOutage -Value $null

Add-Member -InputObject $entry -MemberType NoteProperty -Name DurationDismount -Value $null

Add-Member -InputObject $entry -MemberType NoteProperty -Name DurationAcll -Value $null

Add-Member -InputObject $entry -MemberType NoteProperty -Name DurationMount -Value $null

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23700676/viewspace-1052332/,如需轉載,請註明出處,否則將追究法律責任。

相關文章