ScriptInstanceDST.Execute_Troubleshoot_DatabaseSpace_diagnostic_script. (DataSourceModuleType)

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityPublic
RunAsDefault
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Microsoft_Exchange_2010_Execute_Database_Space_Troubleshooter Default

Source Code:

<DataSourceModuleType ID="ScriptInstanceDST.Execute_Troubleshoot_DatabaseSpace_diagnostic_script." Accessibility="Public">
<Configuration/>
<ModuleImplementation>
<Composite>
<MemberModules>
<DataSource ID="DS" TypeID="Microsoft_Exchange_2010_Execute_Database_Space_Troubleshooter">
<IntervalSeconds>3600</IntervalSeconds>
<SyncTime>$Target/Host/Property[Type="Microsoft.Exchange.2010.ServerRole"]/CmdletSyncTime$</SyncTime>
<TimeoutSeconds>1200</TimeoutSeconds>
<ScriptName>Troubleshoot-DatabaseSpace.ps1</ScriptName>
<Arguments>-Server $Target/Host/Host/Property[Type='Windows!Microsoft.Windows.Computer']/PrincipalName$ -MonitoringContext</Arguments>
<ScriptBody><Script>
# Copyright (c) 2010 Microsoft Corporation. All rights reserved.
#
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK
# OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.

# Requires -Version 2
PARAM(
[parameter(
ParameterSetName = "Default",
Mandatory = $true,
HelpMessage = "The database to troubleshoot.")]
[String]
[ValidateNotNullOrEmpty()]
$MailboxDatabaseName,

[parameter(
ParameterSetName = "Server",
Mandatory = $true,
HelpMessage = "The mailbox server to troubleshoot.")]
[String]
[ValidateNotNullOrEmpty()]
$Server,

[parameter(
Mandatory = $false,
HelpMessage = "The percentage of disk space for the EDB file at which we should start quarantining users.")]
[int]
[ValidateRange(1, 99)]
[ValidateNotNullOrEmpty()]
$PercentEdbFreeSpaceThreshold,

[parameter(
Mandatory = $false,
HelpMessage = "The percentage of disk space for the logs at which we should start quarantining users.")]
[int]
[ValidateRange(1, 99)]
[ValidateNotNullOrEmpty()]
$PercentLogFreeSpaceThreshold,

[parameter(
Mandatory = $false,
HelpMessage = "The number of hours we can wait before running out of space.")]
[int]
[ValidateRange(1, 1000000000)]
[ValidateNotNullOrEmpty()]
$HourThreshold,

[parameter(
Mandatory = $false,
HelpMessage = "Whether or not to quarantine heavy users.")]
[switch]
$Quarantine,

[parameter(
Mandatory = $false,
HelpMessage = "Whether or not we're running under the monitoring context.")]
[switch]
$MonitoringContext
)

#
# Check a single database for free space
#
function Troubleshoot-DatabaseCopySpace([Microsoft.Exchange.Data.Directory.SystemConfiguration.MailboxDatabase] $database, [int] $PercentEdbFreeSpaceThreshold, [int] $PercentLogFreeSpaceThreshold, [int] $HourThreshold, [bool] $Quarantine, [bool] $MonitoringContext)
{
if ($database -eq $null)
{
$argError = new-object System.ArgumentException ($error[0].Exception.ToString())
throw $argError
}

# Event log source name for application log
$appLogSourceName = "Database Space Troubleshooter"

# Event log source name for crimson log
$crimsonLogSourceName = "Database Space"

# The Arguments object is needed for logging
# events.
$Arguments = new-object -typename Arguments
$Arguments.Server = $database.MountedOnServer
$Arguments.Database = $database
$Arguments.MonitoringContext = $MonitoringContext
$Arguments.WriteApplicationEvent = $false

# Check the Edb drive for space
$edbGrowthRateThreshold = -1
$edbVolume = Get-WmiVolumeFromPath $database.EdbFilePath $database.MountedOnServer
$Arguments.InstanceName = $edbVolume.Name -replace "\\$", "" # Remove any trailing backslash if exists since SCOM discovery removes it from the instance name
Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleShooterStarted `
-Parameters @($Arguments.InstanceName, $database)
$edbVolumeFreeSpace = $edbVolume.FreeSpace + $database.AvailableNewMailboxSpace
$edbPercentFreeSpace = ($edbVolumeFreeSpace * 100) / $edbVolume.Capacity

# Check the Log drive for space
$logGrowthRateThreshold = -1
$logVolume = Get-WmiVolumeFromPath $database.LogFolderPath $database.MountedOnServer
$logVolumeFreeSpace = $logVolume.FreeSpace
$logPercentFreeSpace = ($logVolumeFreeSpace * 100) / $logVolume.Capacity
if ($logPercentFreeSpace -lt $PercentLogFreeSpaceThreshold)
{
$logGrowthRateThreshold = $logVolume.FreeSpace / $HourThreshold
}

$growthRateThreshold = -1

# Figure out which of the 2 thresholds is lower
# to determine whether or not we need to quarantine
# some users
if ($logGrowthRateThreshold -ne -1)
{
$growthRateThreshold = $logGrowthRateThreshold
}

if (($edbGrowthRateThreshold -ne -1) -and
($edbGrowthRateThreshold -lt $logGrowthRateThreshold))
{
$growthRateThreshold = $edbGrowthRateThreshold
}

$counterValue = 0
$counterName = "\MSExchangeIS Mailbox($database)\JET Log Bytes Generated/hour"
$logBytesCounter = get-counter -ComputerName $database.MountedOnServer -Counter $counterName -MaxSamples 10
$countervalue = Get-AverageResultForCounter -results $logBytesCounter -counter $counterName

if ($null -eq $countervalue)
{
$countervalue = 0
}

write-verbose ("Current Growth Rate: " + $counterValue)
write-verbose ("Growth Rate Threshold: " + $growthRateThreshold)

# Check if we are low on space compared to any of the thresholds
$problemDetected = $false
if ($edbPercentFreeSpace -lt $PercentEdbFreeSpaceCriticalThreshold)
{
# Log an event that will trigger paging alert for critical space issue
Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleDetectedCriticalSpaceIssue `
-Parameters @($Arguments.InstanceName, $database, $PercentEdbFreeSpaceCriticalThreshold)

$problemDetected = $true
}
elseif ($edbPercentFreeSpace -lt $PercentEdbFreeSpaceAlertThreshold)
{
# Log an event that will trigger non-paging alert for low space issue
Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleDetectedAlertSpaceIssue `
-Parameters @($Arguments.InstanceName, $database, $PercentEdbFreeSpaceAlertThreshold)

$problemDetected = $true
}
elseif ($edbPercentFreeSpace -lt $PercentEdbFreeSpaceThreshold)
{
$edbGrowthRateThreshold = $edbVolumeFreeSpace / $HourThreshold

# Log a warning event for low space issue
Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleDetectedWarningSpaceIssue `
-Parameters @($Arguments.InstanceName, $database, $PercentEdbFreeSpaceThreshold)

$problemDetected = $true
}

# Format to show only 2 decimal places in event log
$edbPercentFreeSpace = "{0:N2}" -f $edbPercentFreeSpace
$logPercentFreeSpace = "{0:N2}" -f $logPercentFreeSpace
$edbVolumeFreeSpaceInGB = "{0:N2}" -f ($edbVolumeFreeSpace/1GB)
$logVolumeFreeSpaceInGB = "{0:N2}" -f ($logVolumeFreeSpace/1GB)

if ($problemDetected)
{
# Exclude the database from provisioning as we are below one of the space thresholds
Set-MailboxDatabase $database -IsExcludedFromProvisioning $true
}
else
{
# We have enough free space that we are not going to even bother looking for outliers causing rapid growth to try to qurantine.
if ($growthRateThreshold -eq -1)
{
Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleShooterNoProblemDetected `
-Parameters @($Arguments.InstanceName, $database, $edbVolumeFreeSpaceInGB, $edbPercentFreeSpace, $logVolumeFreeSpaceInGB, $logPercentFreeSpace, $PercentEdbFreeSpaceThreshold, $PercentLogFreeSpaceThreshold, $HourThreshold, $counterValue, $PercentEdbFreeSpaceCriticalThreshold, $PercentEdbFreeSpaceAlertThreshold, $QuarantineValue)

return
}
}

$cUsersQuarantined = 0
$currentGrowthRate = $counterValue

# Do we need to quarantine users?
if (($currentGrowthRate -lt $growthRateThreshold))
{
Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleShooterFoundLowSpaceNoQuarantine `
-Parameters @($Arguments.InstanceName, $database, $edbVolumeFreeSpaceInGB, $edbPercentFreeSpace, $logVolumeFreeSpaceInGB, $logPercentFreeSpace, $PercentEdbFreeSpaceThreshold, $PercentLogFreeSpaceThreshold, $HourThreshold, $growthRateThreshold, $counterValue, $currentGrowthRate, $PercentEdbFreeSpaceCriticalThreshold, $PercentEdbFreeSpaceAlertThreshold, $QuarantineValue)

return
}

# We have to quarantine some users now, so
# get the least of the most active users
# and figure out which ones we need to quarantine
# so that the current log generation rate drops
# below our maximum calculated growth rate
$topLogGenerators = @(Get-TopLogGenerators $database)
$iNextUserToQuarantine = 0

if ($Quarantine)
{
for($iLogGenerator = 0; $iLogGenerator -lt $topLogGenerators.Length; $iLogGenerator++)
{
write-verbose ("Current Growth Rate: " + $currentGrowthRate)
write-verbose ("Growth Rate Threshold: " + $growthRateThreshold)
write-verbose ("Top user: " + $topLogGenerators[$iLogGenerator].MailboxGuid)
write-verbose ("Top user logs: " + $topLogGenerators[$iLogGenerator].TotalLogBytes)

if ($currentGrowthRate -lt $growthRateThreshold)
{
Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleShooterFoundLowSpace `
-Parameters @($Arguments.InstanceName, $database, $edbVolumeFreeSpaceInGB, $edbPercentFreeSpace, $logVolumeFreeSpaceInGB, $logPercentFreeSpace, $PercentEdbFreeSpaceThreshold, $PercentLogFreeSpaceThreshold, $HourThreshold, $growthRateThreshold, $counterValue, $currentGrowthRate, $cUsersQuarantined, $PercentEdbFreeSpaceCriticalThreshold, $PercentEdbFreeSpaceAlertThreshold, $QuarantineValue)

return
}

write-verbose ("Quarantining: " + $topLogGenerators[$iNextUserToQuarantine].MailboxGuid)
Set-QuarantineMailbox $topLogGenerators[$iNextUserToQuarantine].MailboxGuid

Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleShooterQuarantineUser `
-Parameters @($topLogGenerators[$iNextUserToQuarantine].MailboxGuid, $database)

$currentGrowthRate -= $topLogGenerators[$iNextUserToQuarantine].TotalLogBytes
$iNextUserToQuarantine++
$cUsersQuarantined++
}
}

Log-Event `
-Arguments $Arguments `
-EventInfo $StoreLogEntries.DatabaseSpaceTroubleShooterFinishedInsufficient `
-Parameters @($Arguments.InstanceName, $database, $edbVolumeFreeSpaceInGB, $edbPercentFreeSpace, $logVolumeFreeSpaceInGB, $logPercentFreeSpace, $PercentEdbFreeSpaceThreshold, $PercentLogFreeSpaceThreshold, $HourThreshold, $growthRateThreshold, $counterValue, $currentGrowthRate, $cUsersQuarantined, $PercentEdbFreeSpaceCriticalThreshold, $PercentEdbFreeSpaceAlertThreshold, $QuarantineValue)
}

###################################################################################################################################
# #
# Script Body #
# #
###################################################################################################################################

Set-StrictMode -Version Latest

$scriptPath = [System.IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Path)

. $scriptPath\CITSLibrary.ps1
. $scriptPath\StoreTSLibrary.ps1
. $scriptPath\StoreTSConstants.ps1
. $scriptPath\DiagnosticScriptCommonLibrary.ps1

Load-ExchangeSnapin

$QuarantineValue = $false
$MonitoringContextValue = $false
$MailboxServer = $null
$InvocationGuid = $null

# Since we're in strict mode we must declare all variables we use
$script:monitoringEvents = $null

if (!$MyInvocation.BoundParameters.ContainsKey("PercentEdbFreeSpaceThreshold"))
{
$PercentEdbFreeSpaceThreshold = $PercentEdbFreeSpaceDefaultThreshold
}

if (!$MyInvocation.BoundParameters.ContainsKey("PercentLogFreeSpaceThreshold"))
{
$PercentLogFreeSpaceThreshold = $PercentLogFreeSpaceDefaultThreshold
}

if (!$MyInvocation.BoundParameters.ContainsKey("HourThreshold"))
{
$HourThreshold = $HourDefaultThreshold
}

if ($Quarantine)
{
$QuarantineValue = $true
}

if ($MonitoringContext)
{
$MonitoringContextValue = $true

#E14:303295 Add a monitoring event to suppress SCOM failure alerts
#Use a guid for each invocation so that we can identify
#start and finish events for each unique invocation
$InvocationGuid = [System.Guid]::NewGuid().ToString()
$messageStart = "Database Space TS started successfully for Invocation Guid {0}" -f $InvocationGuid
Add-MonitoringEvent -Id $StoreLogEntries.DatabaseSpaceTroubleShooterStarted[0] -Type $EVENT_TYPE_INFORMATION -Message $messageStart
}

if ($PSCmdlet.ParameterSetName -eq "Server")
{
$MailboxServer = $Server
$databases = @(Get-MailboxDatabase -Server $MailboxServer)
}
else
{
$databases = @(Get-MailboxDatabase $MailboxDatabaseName)
}

foreach($database in $databases)
{
#Get the status right before invoking the function
#so we can narrow down failover related issues
$database = Get-MailboxDatabase $database -Status

#Run only if the database is specified or in case of server,
#on the active copy to avoid running it multiple times
#against the same database
if (($MailboxServer -eq $null) -or
($database.MountedOnServer -match $MailboxServer))
{
Troubleshoot-DatabaseCopySpace `
-database $database `
-PercentEdbFreeSpaceThreshold $PercentEdbFreeSpaceThreshold `
-PercentLogFreeSpaceThreshold $PercentLogFreeSpaceThreshold `
-HourThreshold $HourThreshold `
-Quarantine $QuarantineValue `
-MonitoringContext $MonitoringContextValue
}
}

if ($MonitoringContext)
{
#Monitoring event to suppress SCOM failure alerts
#Also lets us know that TS did finish successfully
$messageFinish = "Database Space TS finished successfully for Invocation Guid {0}" -f $InvocationGuid
Add-MonitoringEvent -Id 5102 -Type $EVENT_TYPE_INFORMATION -Message $messageFinish

Write-MonitoringEvents
}
</Script></ScriptBody>
<MonitoringDataSource>MSExchange Monitoring Troubleshoot-DatabaseSpace</MonitoringDataSource>
<MaxStartDelaySeconds>15</MaxStartDelaySeconds>
</DataSource>
</MemberModules>
<Composition>
<Node ID="DS"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
</DataSourceModuleType>