Exchange 2010 Powershell指令碼攻略(六)
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] " $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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Exchange 2010 Powershell指令碼攻略(十五)指令碼
- Exchange 2010 Powershell指令碼攻略(十四)指令碼
- Exchange 2010 Powershell指令碼攻略(十三)指令碼
- Exchange 2010 Powershell指令碼攻略(十二)指令碼
- Exchange 2010 Powershell指令碼攻略(十一)指令碼
- Exchange 2010 Powershell指令碼攻略(十)指令碼
- Exchange 2010 Powershell指令碼攻略(九)指令碼
- Exchange 2010 Powershell指令碼攻略(八)指令碼
- Exchange 2010 Powershell指令碼攻略(七)指令碼
- Exchange 2010 Powershell指令碼攻略(五)指令碼
- Exchange 2010 Powershell指令碼攻略(四)指令碼
- Exchange 2010 Powershell指令碼攻略(三)指令碼
- Exchange 2010 Powershell指令碼攻略(二)指令碼
- Exchange 2010 Powershell指令碼攻略(一)指令碼
- powershell指令碼指令碼
- PowerShell 指令碼中的密碼指令碼密碼
- PowerShell 指令碼執行策略指令碼
- powershell重新命名指令碼指令碼
- Exchange 2010搭建
- Bash指令碼debug攻略指令碼
- 開機自啟動Powershell指令碼指令碼
- linux shell 指令碼攻略筆記Linux指令碼筆記
- 【黑客基礎】Windows PowerShell 指令碼學習(上)黑客Windows指令碼
- 最簡單的一個powershell的指令碼指令碼
- Exchange 2010需要的網路埠
- 微軟宣佈全新命令列+指令碼工具:PowerShell 7微軟命令列指令碼
- 五個實用的SQL Server PowerShell指令碼OMSQLServer指令碼
- 利用powershell指令碼Windows hosts記錄替換IP指令碼Windows
- Win10使用Powershell提示禁止執行指令碼怎麼辦 Win10使用Powershell提示禁止執行指令碼如何解決Win10指令碼
- shell指令碼攻略--DNS正向解析一鍵部署指令碼DNS
- 利用 Powershell 編寫簡單的瀏覽器指令碼瀏覽器指令碼
- 【連結】LINUX SHELL指令碼攻略筆記[速查]Linux指令碼筆記
- 《Linux Shell指令碼攻略(第2版)》書評Linux指令碼
- nuget打包檔案丟失如何使用powershell指令碼解決指令碼
- 使用VSCode遠端除錯惡意Powershell指令碼VSCode除錯指令碼
- 【VMware VCF】使用 PowerShell 指令碼管理 SDDC Manager 中的軟體包。指令碼
- PowerShell 指令碼來監控 CPU、記憶體和磁碟使用情況:指令碼記憶體
- linux shell 指令碼攻略學習6-xargs詳解Linux指令碼