Get-SCOMObjectAvailability.ps1
Function Get-SCOMObjectAvailability { <# .SYNOPSIS Retrieves availability data for SCOM monitoring objects from the Operations Manager Data Warehouse. .DESCRIPTION The Get-SCOMObjectAvailability function queries the SCOM Data Warehouse to retrieve detailed availability statistics for monitoring objects. It calculates availability percentages based on different health states (Green, Yellow, Red) and provides comprehensive reporting data including uptime, downtime, and maintenance windows. This function leverages the Microsoft_SystemCenter_DataWarehouse_Report_Library_AvailabilityReportDataGet stored procedure to obtain accurate availability data and presents it in an easily consumable PowerShell object format. The function supports both hourly and daily aggregation and can work with either monitoring object GUIDs or direct monitoring object references from SCOM PowerShell cmdlets. .PARAMETER DataWarehouseServerName The name of the SQL Server hosting the SCOM Data Warehouse database. If not specified, the function attempts to retrieve this information from the local SCOM registry or SCOM PowerShell settings. Example: "SCOM-DW01.contoso.com" or "SCOM-DW01" .PARAMETER DataWarehouseDatabaseName The name of the SCOM Data Warehouse database. Defaults to "OperationsManagerDW" which is the standard database name for SCOM installations. .PARAMETER StartDate The start date and time for the availability calculation period. Defaults to 24 hours ago from the current time. Must be earlier than EndDate. Accepts DateTime objects or strings that can be parsed as dates. .PARAMETER EndDate The end date and time for the availability calculation period. Defaults to the current date and time. Must be later than StartDate. Accepts DateTime objects or strings that can be parsed as dates. .PARAMETER AggregationType Specifies the level of data aggregation for the availability calculation. - "Hourly": Provides hour-by-hour availability data (more granular) - "Daily": Provides day-by-day availability data (summary level) Default is "Hourly". Daily aggregation is recommended for longer time periods (weeks/months). .PARAMETER Id The GUID of the monitoring object for which to retrieve availability data. This parameter is used when you have the specific GUID of a SCOM monitoring object. Must be a valid GUID format. Use this parameter when working with the 'ById' parameter set. Aliases: InstanceId, MonitoringObjectId .PARAMETER MonitoringObject A SCOM MonitoringObject instance obtained from SCOM PowerShell cmdlets like Get-SCOMClassInstance. This parameter is used when you already have a monitoring object reference. Use this parameter when working with the 'ByObject' parameter set. .PARAMETER QueryTimeout The timeout value in seconds for the SQL query execution. Defaults to 30 seconds. Increase this value for large datasets or slower database servers. Valid range: 1-3600 seconds. .PARAMETER ConnectionTimeout The timeout value in seconds for establishing the database connection. Defaults to 15 seconds. Increase this value for slower network connections or heavily loaded database servers. Valid range: 1-300 seconds. .INPUTS None. This function does not accept pipeline input. .OUTPUTS [PSCustomObject] Returns a custom PowerShell object with the following properties: Entity Information: - ManagedEntityRowId: Internal SCOM database row identifier - ManagedEntityGuid: GUID of the monitoring object - Id: Alias for ManagedEntityGuid (for compatibility) - ManagedEntityDefaultName: Default name from SCOM - Path: Full path of the object in SCOM hierarchy - DisplayName: Display name of the monitoring object Time Period Information: - StartTime: Beginning of the availability measurement period - EndTime: End of the availability measurement period - DurationHours: Total hours covered by the measurement (formatted string) - SampleCount: Number of data samples used in calculation - AggregationType: Type of aggregation used (Hourly/Daily) Availability Statistics: - GreenMilliseconds: Time in healthy state (milliseconds) - YellowMilliseconds: Time in warning state (milliseconds) - RedMilliseconds: Time in critical state (milliseconds) - GreenPct: Percentage of time in healthy state (formatted string) - YellowPct: Percentage of time in warning state (formatted string) - RedPct: Percentage of time in critical state (formatted string) - OverallAvailabilityPct: Overall availability percentage (formatted string) Additional State Information: - DisabledMilliseconds: Time in disabled state - PlannedMaintenanceMilliseconds: Time in planned maintenance - UnplannedMaintenanceMilliseconds: Time in unplanned maintenance - HealthServiceUnavailableMilliseconds: Time when health service was unavailable .EXAMPLE # Get availability for a specific monitoring object by GUID $objectId = "c5a9c43c-84d9-a3c2-6e84-c9d68bf79aa1" $availability = Get-SCOMObjectAvailability -Id $objectId -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) Write-Host "Availability for last 7 days: $($availability.OverallAvailabilityPct)%" This example retrieves 7-day availability data for a specific monitoring object using its GUID. .EXAMPLE # Get availability using a monitoring object reference $webApp = Get-SCOMClass -Name 'Microsoft.SystemCenter.WebApplication.Perspective' | Get-SCOMClassInstance | Where-Object {$_.DisplayName -like "*Production*"} $availability = Get-SCOMObjectAvailability -MonitoringObject $webApp -AggregationType Daily -StartDate (Get-Date).AddDays(-30) $availability | Select-Object DisplayName, StartTime, EndTime, OverallAvailabilityPct, SampleCount | Format-Table This example gets 30-day availability data for a web application using daily aggregation. .EXAMPLE # Generate availability report for multiple objects $servers = Get-SCOMClass -Name 'Microsoft.Windows.Computer' | Get-SCOMClassInstance | Where-Object {$_.DisplayName -like "SQL*"} $report = @() foreach ($server in $servers) { $availability = Get-SCOMObjectAvailability -MonitoringObject $server -StartDate (Get-Date).AddDays(-14) -AggregationType Daily $report += [PSCustomObject]@{ ServerName = $server.DisplayName Availability = $availability.OverallAvailabilityPct GreenTime = $availability.GreenPct RedTime = $availability.RedPct Samples = $availability.SampleCount } } $report | Sort-Object Availability | Format-Table This example generates a availability report for multiple SQL servers over the last 14 days. .EXAMPLE # Use custom database server $availability = Get-SCOMObjectAvailability -Id "a1b2c3d4-e5f6-7890-abcd-ef1234567890" ` -DataWarehouseServerName "SCOM-DW02.contoso.com" ` -StartDate "2025-06-01" ` -EndDate "2025-06-30" ` -AggregationType Daily ` -Verbose Write-Host "June 2025 Availability Report:" -ForegroundColor Green Write-Host "Object: $($availability.DisplayName)" Write-Host "Period: $($availability.StartTime) to $($availability.EndTime)" Write-Host "Overall Availability: $($availability.OverallAvailabilityPct)%" Write-Host "Green Time: $($availability.GreenPct)%" Write-Host "Yellow Time: $($availability.YellowPct)%" Write-Host "Red Time: $($availability.RedPct)%" This example demonstrates using custom database settings and verbose output. .EXAMPLE # Export availability data to CSV for analysis $watmObjects = Get-SCOMClass -Name 'Microsoft.SystemCenter.WebApplication.Perspective' | Get-SCOMClassInstance $availabilityData = @() foreach ($watm in $watmObjects) { Write-Progress -Activity "Processing WATM Objects" -Status $watm.DisplayName -PercentComplete (($availabilityData.Count / $watmObjects.Count) * 100) try { $avail = Get-SCOMObjectAvailability -MonitoringObject $watm -StartDate (Get-Date).AddDays(-90) -AggregationType Daily $availabilityData += $avail } catch { Write-Warning "Failed to get availability for $($watm.DisplayName): $($_.Exception.Message)" } } $availabilityData | Export-Csv -Path "C:\Reports\WATM_Availability_90Days.csv" -NoTypeInformation Write-Host "Exported availability data for $($availabilityData.Count) objects to CSV" This example processes multiple web application monitoring objects and exports the results to CSV. .EXAMPLE # Compare availability between different time periods $objectId = "c5a9c43c-84d9-a3c2-6e84-c9d68bf79aa1" $lastWeek = Get-SCOMObjectAvailability -Id $objectId -StartDate (Get-Date).AddDays(-14) -EndDate (Get-Date).AddDays(-7) $thisWeek = Get-SCOMObjectAvailability -Id $objectId -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) Write-Host "Availability Comparison for $($thisWeek.DisplayName):" -ForegroundColor Cyan Write-Host "Last Week: $($lastWeek.OverallAvailabilityPct)%" -ForegroundColor $(if([decimal]$lastWeek.OverallAvailabilityPct -gt 95) {'Green'} else {'Red'}) Write-Host "This Week: $($thisWeek.OverallAvailabilityPct)%" -ForegroundColor $(if([decimal]$thisWeek.OverallAvailabilityPct -gt 95) {'Green'} else {'Red'}) $trend = [decimal]$thisWeek.OverallAvailabilityPct - [decimal]$lastWeek.OverallAvailabilityPct Write-Host "Trend: $(if($trend -gt 0) {'+'})$([Math]::Round($trend, 2))%" -ForegroundColor $(if($trend -gt 0) {'Green'} else {'Red'}) This example compares availability between two different time periods to show trends. .NOTES Author: Tyson Paul (https://monitoringguys.com/2019/11/12/scomhelper/) Version History: 2025.07.07 - 1.0: Initial version with comprehensive availability reporting Requirements: - SCOM 2012 R2 or later with Data Warehouse configured - PowerShell 3.0 or later - SCOM PowerShell module loaded (for MonitoringObject parameter) - Appropriate permissions to query the SCOM Data Warehouse database - Network connectivity to the SCOM Data Warehouse server Performance Considerations: - Large date ranges with hourly aggregation can result in significant data processing - Daily aggregation is recommended for periods longer than 30 days - Consider using custom QueryTimeout for large datasets - The function queries the actual availability data, not cached summary tables Database Dependencies: - Requires access to the OperationsManagerDW database - Uses the Microsoft_SystemCenter_DataWarehouse_Report_Library_AvailabilityReportDataGet stored procedure - Queries the ManagedEntity table for object resolution Troubleshooting: - Ensure SCOM Data Warehouse is properly configured and operational - Verify that the monitoring object exists and has availability data in the specified time range - Check database permissions if authentication errors occur - Use -Verbose for detailed execution information - Validate that the GUID format is correct when using the -Id parameter Common Use Cases: - SLA reporting and compliance monitoring - Availability trending and analysis - Performance baseline establishment - Capacity planning based on historical availability - Troubleshooting recurring availability issues Related SCOM Cmdlets: - Get-SCOMClassInstance: Retrieve monitoring objects - Get-SCOMClass: Find monitoring classes - Get-SCOMDataWarehouseSetting: Get Data Warehouse configuration .LINK Get-SCOMClassInstance Get-SCOMClass Get-SCOMDataWarehouseSetting .FUNCTIONALITY SCOM Data Warehouse, Availability Reporting, System Center Operations Manager, SLA Monitoring #> param( # Defaults to OperationsManagerDW # If not specified, it will be retrieved from the registry or SCOM settings. [Parameter(Mandatory = $false)] [string]$DataWarehouseServerName, # Defaults to OperationsManagerDW [Parameter(Mandatory = $false)] [string]$DataWarehouseDatabaseName = "OperationsManagerDW", # Defaults to the last 24 hours [Parameter(Mandatory = $false)] [datetime]$StartDate = (Get-Date).AddDays(-1), # Defaults to the current time [Parameter(Mandatory = $false)] [datetime]$EndDate = (Get-Date), # Defaults to Hourly aggregation # Options are "Hourly" or "Daily" [Parameter(Mandatory = $false)] [ValidateSet("Hourly", "Daily")] [string]$AggregationType = "Hourly", # Id/Guid of a monitoring object [Parameter(Mandatory=$true, ParameterSetName="ById")] [ValidateNotNullOrEmpty()] [Alias("InstanceId","MonitoringObjectId")] [ValidateScript({ if ([Guid]::TryParse($_, [ref][Guid]::Empty)) { $true } else { throw "Invalid GUID format. Please provide a valid GUID string." } })] [System.Object]$Id, # The monitoring object itself (alternative to Id parameter) [Parameter(Mandatory=$true, ParameterSetName="ByObject")] [ValidateNotNull()] [Microsoft.EnterpriseManagement.Monitoring.MonitoringObject]$MonitoringObject, # Defaults to 30 seconds # The time in seconds to wait for the command to execute. [Parameter(Mandatory = $false)] [int]$QueryTimeout = 30, # Defaults to 15 seconds # The time (in seconds) to wait for a connection to open. [Parameter(Mandatory = $false)] [int]$ConnectionTimeout = 15 ) If ($PSCmdlet.ParameterSetName -eq "ByObject") { # If the object is provided, extract the Id $Id = $MonitoringObject.Id.Guid } # Create hash table for aggregation type mapping $AggregationMap = @{ "Hourly" = 0 "Daily" = 1 } # Retrieve the name of the Operational Database and Data WareHouse Servers from the registry. $reg = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup\" #$OperationsManagerDBServer = $reg.DatabaseServerName $DataWarehouseServerName = $reg.DataWarehouseDBServerName # If the value is empty in this key, then we'll use the Get-SCOMDataWarehouseSetting cmdlet. If (!($DataWarehouseServerName)) { $DataWarehouseServerName = Get-SCOMDataWarehouseSetting | Select-Object -expandProperty DataWarehouseServerName } #$OperationsManagerDBServer = $OperationsManagerDBServer.ToUpper() $DataWarehouseServerName = $DataWarehouseServerName.ToUpper() $Query = @" -- Get MERowID by using InstanceID DECLARE @MEGuid NVARCHAR(50) = N'$($Id)'; DECLARE @MERowId INT; SELECT @MERowId = [ManagedEntityRowId] FROM [OperationsManagerDW].[dbo].[ManagedEntity] WHERE [ManagedEntityGuid] = @MEGuid; -- Build the XML object list string FIRST DECLARE @ObjectList NVARCHAR(MAX); SET @ObjectList = N'<Data><Objects><Object Use="Self">' + CAST(@MERowId AS NVARCHAR(50)) + '</Object></Objects></Data>'; EXEC Microsoft_SystemCenter_DataWarehouse_Report_Library_AvailabilityReportDataGet @ObjectList = @ObjectList, @MonitorName = N'System.Health.AvailabilityState', @StartDate = '$($StartDate.ToString("yyyy-MM-dd HH:mm:ss"))', @EndDate = '$($EndDate.ToString("yyyy-MM-dd HH:mm:ss"))', @DataAggregation = $($AggregationMap[$AggregationType]) --@LanguageCode = N'ENU'; "@ # Each element should be a PSObject with the SCOM SP's output columns [array]$DataRows = Invoke-CLSqlCmd -Server $DataWarehouseServerName -Database $DataWarehouseDatabaseName -Query $Query # Defensive: handle empty input if (-not $DataRows -or $DataRows.Count -eq 0) { Write-Warning "No data provided." return $null } # Sum up durations (all in milliseconds) $sum = @{ Green = 0 Yellow = 0 Red = 0 White = 0 Disabled = 0 PlannedMaintenance = 0 UnplannedMaintenance = 0 HealthServiceUnavailable = 0 Total = 0 } $sum.Green = $DataRows.InGreenStateMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum $sum.Yellow = $DataRows.InYellowStateMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum $sum.Red = $DataRows.InRedStateMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum $sum.White = $DataRows.InWhiteStateMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum $sum.Disabled = $DataRows.InDisabledStateMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum $sum.PlannedMaintenance = $DataRows.InPlannedMaintenanceMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum $sum.UnplannedMaintenance = $DataRows.InUnplannedMaintenanceMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum $sum.HealthServiceUnavailable = $DataRows.HealthServiceUnavailableMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum $sum.Total = $DataRows.IntervalDurationMilliseconds | Measure-Object -Sum | Select-Object -ExpandProperty Sum # Calculate percentages $availability = if ($sum.Total -gt 0) { 100 * $sum.Green / $sum.Total } else { 0 } $yellowPct = if ($sum.Total -gt 0) { 100 * $sum.Yellow / $sum.Total } else { 0 } $redPct = if ($sum.Total -gt 0) { 100 * $sum.Red / $sum.Total } else { 0 } # Grab the basic details from the first row for consistency (assuming same entity) $entityRow = $DataRows[0] [PSCustomObject]@{ ManagedEntityRowId = $entityRow.ManagedEntityRowId ManagedEntityGuid = [GUID]($entityRow.ManagedEntityGuid) Id = [GUID]($entityRow.ManagedEntityGuid) ManagedEntityDefaultName = $entityRow.ManagedEntityDefaultName Path = $entityRow.Path DisplayName = $entityRow.DisplayName StartTime = $StartDate EndTime = $EndDate DurationHours = "{0:N2}" -f (($EndDate - $StartDate).TotalHours) SampleCount = $DataRows.Count AggregationType = $AggregationType #TotalDurationMilli = $sum.Total #TotalDurationHours = "{0:N2}" -f ($sum.Total/3600000) GreenMilliseconds = $sum.Green YellowMilliseconds = $sum.Yellow RedMilliseconds = $sum.Red GreenPct = "{0:N2}" -f $availability YellowPct = "{0:N2}" -f $yellowPct RedPct = "{0:N2}" -f $redPct OverallAvailabilityPct = "{0:N2}" -f $availability DisabledMilliseconds = $sum.Disabled PlannedMaintenanceMilliseconds = $sum.PlannedMaintenance UnplannedMaintenanceMilliseconds = $sum.UnplannedMaintenance HealthServiceUnavailableMilliseconds = $sum.HealthServiceUnavailable } } #------------------------------------------------------------------------------------ $WATMs = Get-SCOMClass -Name 'Microsoft.SystemCenter.WebApplication.Perspective' | Get-SCOMClassInstance $WATM = $WATMs | Where-Object {$_.DisplayName -like "*My WATM Name*"} $result = Get-SCOMObjectAvailability -MonitoringObject $WATM -StartDate (Get-Date).AddDays(-35) -EndDate (Get-Date) -Verbose -AggregationType Daily $result |