Home > Microsoft, SCOM 2007, SQL Server > Check SQL DB Free space

Check SQL DB Free space

System Center Operations Manager is monitoring DB space used by default if you have set the database to a fixed size. If you are using autogrowth with unlimited file growth, your diskspace monitoring will kick in when you are running out of disk space (don’t forget to customize these settings for large disks: you don’t want to get warned on a 500GB volume when there is only 2 GB free space).
However, if you are using autogrow options with a limited size, then SCOM 2007 doesn’t generate alerts as also documented in the product knowledge tab for “DB Space Free (%)” Monitor:
This monitor checks the database percentage free space to ensure it is above the defined thresholds. A warning or error alert will be raised if it is below one of the defined thresholds.
Databases that have autogrow set will never generate an alert regardless of the reported free space.

If your database is filling up, you get the following error: Could not allocate space for object in database because the filegroup is full.
To prevent this error and get warned in advance, I have written a custom monitor that will detect databases with the settings mentioned above and monitors database free space when autogrow AND limited file size are on.

For detailed instruction on how to setup a monitor for monitoring SQL Server, have a look at: Check your SQL backup automatically.

Script is updated on 26-11-2009, some bugs are fixed and it is now using the “SQL 2005 DB Engine” monitor instead of the “SQL 2005 DB” monitor. First I thought it would be better to handle all individual databases by SCOM. However is something is wrong with the script, SCOM generates an alert for every database. If you have a lot of databases on one server (I have servers with over 500 databases), it can generate a lot of alerts. Now only one alert per engine is generated. And the script takes only 3 seconds on my 500+ database server.

Here are the short instructions for this monitor:

  • Create 3 state Script monitor (also select a proper management pack to save your monitor)
  • Set Monitor Target to “SQL 2005 DB Engine”
  • Set running interval (between 15 and 60 minutes should be ok, depending on your situation)
  • Add the script (see below)
  • Add the following parameter:
  • $Target/Property[Type="MicrosoftSQLServerLibrary6064600!Microsoft.SQLServer.DBEngine"]/ConnectionString$

  • Set Unhealthy expression: Property[@Name='Status'] Equals Critical
  • Set Degradedexpression: Property[@Name='Status'] Equals Warning
  • Set Healthy expression: Property[@Name='Status'] Equals Healthy
  • Accept default health options
  • Check “generate alerts for this monitor”
  • Set “Generate an when… The monitor is in a critical or warning state”
  • Adjust Severity to “Match monitor’s health”
  • Use the following alert description:
  • Low DB Free space on $Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetbiosComputerName$ in instance $Target/Property[Type="MicrosoftSQLServerLibrary6064600!Microsoft.SQLServer.DBEngine"]/ServiceName$, list of datafiles: $Data/Context/Property[@Name='DBList']$


    Dim i, oAPI, propertyBag, objShell
    Dim strStatus
    Dim objParameters, sConnectionString
    ' define constants
    Const EVENT_TYPE_ERROR = 1
    Const EVENT_TYPE_WARNING = 2
    Const EVENT_TYPE_INFORMATION = 4
    ' check parameters
    Set objParameters = WScript.Arguments
    If objParameters.Count <> 1 Then
    ' Set objShell = Wscript.CreateObject("Wscript.Shell")
    ' objShell.LogEvent EVENT_TYPE_ERROR, "This Script requires exactly 1 parameter: ConnectionString"
    WScript.Quit -1
    End If
    ' map arguments to friendly names
    sConnectionString= objParameters(0)

    ' initialize SQL statement
    SQL = "SET NOCOUNT ON; " & _
    "DECLARE @dbid int DECLARE @dbname sysname DECLARE @sql varchar(3000) " & _
    "CREATE TABLE #DBSpace ( " & _
    " DBName varchar (50), " & _
    " [Size] int, " & _
    " max_size int, " & _
    " growth int, " & _
    " is_percentage_growth bit, " & _
    " percentage_used real, " & _
    " [type] varchar(15), " & _
    " severity varchar(8)) " & _
    "SET @dbid = (SELECT MIN(database_id) FROM master.sys.databases) " & _
    "WHILE @dbid IS NOT NULL " & _
    " BEGIN " & _
    " SET @dbname = (SELECT [name] FROM master.sys.databases WHERE database_id = @dbid) " & _
    " SET @sql = 'INSERT INTO #DBSpace SELECT dbname , [size], max_size, growth, is_percent_growth, percentage_used, " & _
    " CASE " & _
    " WHEN [type] = 0 THEN ''Database'' " & _
    " WHEN [type] = 1 THEN ''Transaction Log'' " & _
    " END AS [type], " & _
    " CASE " & _
    " WHEN is_percent_growth = 1 THEN " & _
    " CASE " & _
    " WHEN db.percentage_used < (100 - ((db.percentage_used / 100) * db.growth * 1.2)) AND db.percentage_used > (100 - ((db.percentage_used / 100) * db.growth * 2.5)) THEN ''warning'' " & _
    " WHEN db.percentage_used > (100 - ((db.percentage_used / 100) * db.growth * 1.2)) THEN ''critical'' " & _
    " ELSE ''healthy'' " & _
    " END " & _
    " ELSE " & _
    " CASE " & _
    " WHEN db.size < (db.max_size - (db.growth * 2)) AND db.size > (db.max_size - (db.growth * 4)) THEN ''warning'' " & _
    " WHEN db.size > (db.max_size - (db.growth * 2)) THEN ''critical'' " & _
    " ELSE ''healthy'' " & _
    " END " & _
    " END AS severity " & _
    " FROM " & _
    " ( SELECT ''' + @dbname + ''' as dbname, [size] , [type], [max_size], [growth] , " & _
    " [is_percent_growth] , " & _
    " (CAST([size] AS REAL) / CAST([max_size] AS REAL) * 100) AS percentage_used " & _
    " FROM [' + @dbname + '].sys.database_files )AS db " & _
    " WHERE max_size > 0 AND growth > 0 ' " & _
    " EXEC(@sql) " & _
    " SET @dbid = (SELECT MIN(database_id) FROM master.sys.databases WHERE database_id > @dbid) " & _
    " END " & _
    "SELECT * FROM #DBSpace WHERE severity <> 'healthy' " & _
    "drop table #DBSpace"

    On Error resume next
    ' Setup Database connection
    Set cnADOConnection = CreateObject("ADODB.Connection")
    cnADOConnection.Provider = "sqloledb"
    cnADOConnection.ConnectionTimeout = 30
    strProv = "Server=" & sConnectionString & ";Database=Master;Trusted_Connection=yes"
    ' open connection and execute query
    cnADOConnection.Open strProv
    Set rsCustomDBSpaceMonitor = cnADOConnection.Execute(SQL)
    do until rsCustomDBSpaceMonitor.EOF
    strDatabase = CStr(rsCustomDBSpaceMonitor("DBName").Value)
    if rsCustomDBSpaceMonitor("severity").Value = "warning" Then
    strSeverityWarning = "Warning"
    strList = strList & "warning: " & rsCustomDBSpaceMonitor("type").Value & " " & strDatabase & " Percentage Used: " & rsCustomDBSpaceMonitor("percentage_used").Value & ", "
    elseif rsCustomDBSpaceMonitor("severity").Value = "critical" Then
    strSeverityCritical = "Critical"
    strList = strList & "Critical: " & rsCustomDBSpaceMonitor("type").Value & " " & strDatabase & " Percentage Used: " & rsCustomDBSpaceMonitor("percentage_used").Value & ", "
    else
    strSeverityHealthy = "Healthy"
    End If
    ' wscript.echo "percentage used " & rsCustomDBSpaceMonitor("percentage_used").Value

    Err.Clear
    rsCustomDBSpaceMonitor.MoveNext
    ' if 0 <> Err.number then Exit Do
    loop
    ' clean up connection
    rsCustomDBSpaceMonitor.close
    cnADOConnection.close

    ' Set SCOM parameters
    Set oAPI = CreateObject("MOM.ScriptAPI")
    ' set state depending on Free space (order of next statemenst is important, if only in one row the state is critical, the state will be critical)
    If strSeverityHealthy = "Healthy" Then strStatus = "Healthy"
    If strSeverityWarning = "Warning" Then strStatus = "Warning"
    If strSeverityCritical = "Critical" Then strStatus = "Critical"

    If strStatus = "Critical" Then
    ' wscript.echo strList
    Call oAPI.LogScriptEvent("SBPDBFreeSpaceMonitor", 3000, EVENT_TYPE_ERROR, "The Following datafiles are low on free space:" & strList)

    ElseIf strStatus = "Warning" Then
    ' wscript.echo strList
    Call oAPI.LogScriptEvent("SBPDBFreeSpaceMonitor", 3001, EVENT_TYPE_WARNING, "The Following datafiles are low on free space:" & strList)
    Else
    ' wscript.echo "healthy"
    Call oAPI.LogScriptEvent("SBPDBFreeSpaceMonitor", 3002, EVENT_TYPE_INFORMATION, "All datafiles on " & sConnectionString & " have enough free space")
    End If
    ' Return values to SCOM to set state and generate Alert
    Set propertyBag = oAPI.CreatePropertyBag ()
    Call propertyBag.AddValue ("Status", strStatus)
    Call propertyBag.AddValue ("DBList", strList)
    Call oAPI.Return(propertyBag)

    1. Reuvy
      June 17th, 2010 at 08:55 | #1

      I don’t believe this works on databases which for example have multiple data files. It will report on each data file seperatly instead of on the sum of each. So for example, if I have a database with two data files, the first being 99% full and the second 5%, the health of the database as a whole is ok since there is plenty of space. Not the case with the above script.

      That’s my only complaint :-) Awesome otherwise.

    1. No trackbacks yet.